[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Wed Jul 31 00:13:10 UTC 2019


The branch, master has been updated
       via  2b590e16bcb smbd: Fix retry for kernel-oplocked files
       via  ef582ffcf3a smbd: Always open files with O_NONBLOCK
       via  57695ad44bf torture3: Add oplock5 kernel-oplock test
      from  ea7708d8c7f ctdb-scripts: Simplify 01.reclock.script

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 2b590e16bcb4f4e1f1f0bf049a863db38e634beb
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Jul 30 12:24:53 2019 +0200

    smbd: Fix retry for kernel-oplocked files
    
    This now removed comment describes the bug correctly:
    /*
     * As this timer event is owned by req, it will
     * disappear if req it talloc_freed.
     */
    
    In smb1, "req" disappears once the reply_whatever routine is done. Thus
    the timer goes away and we never look at "req" again.
    
    This change moves the valid data (xconn and mid) to
    deferred_open_record, and changes the talloc hierarchy such that the
    timer is now a child of open_rec, which is a child of the deferred
    message.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=14060
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Wed Jul 31 00:12:34 UTC 2019 on sn-devel-184

commit ef582ffcf3a220b73f678d9bce0fd37800f76c54
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Jul 29 20:45:51 2019 +0200

    smbd: Always open files with O_NONBLOCK
    
    It's perfectly possible that someone else takes a kernel oplock and
    makes us block, independent of our own kernel oplock setting.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=14060
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 57695ad44bf10d6ae1dc466551358bd826dac923
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Jul 29 17:14:00 2019 +0200

    torture3: Add oplock5 kernel-oplock test
    
    Show that the current smb1 server does not properly retry a nonblocking
    open of a kernel-oplocked file
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=14060
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 source3/selftest/tests.py |  13 +++
 source3/smbd/open.c       |  47 ++++----
 source3/torture/torture.c | 273 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 310 insertions(+), 23 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 53ece589d2a..4c6264e129f 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -113,6 +113,19 @@ for t in tests:
 t = "TLDAP"
 plantestsuite("samba3.smbtorture_s3.plain.%s" % t, "ad_dc", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER/tmp', '$DC_USERNAME', '$DC_PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"])
 
+t = "OPLOCK5"
+plantestsuite("samba3.smbtorture_s3.plain.%s" % t,
+              "fileserver",
+              [os.path.join(samba3srcdir,
+                            "script/tests/test_smbtorture_s3.sh"),
+               t,
+               '//$SERVER/tmp',
+               '$USERNAME',
+               '$PASSWORD',
+               smbtorture3,
+               "",
+               "-l $LOCAL_PATH",
+               "-mNT1"])
 #
 # RENAME-ACCESS needs to run against a special share - acl_xattr_ign_sysacl_windows
 #
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 2ee4a2c4fca..8fcd7b3b580 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -44,6 +44,9 @@
 extern const struct generic_mapping file_generic_mapping;
 
 struct deferred_open_record {
+	struct smbXsrv_connection *xconn;
+	uint64_t mid;
+
         bool delayed_for_oplocks;
 	bool async_open;
         struct file_id id;
@@ -2504,10 +2507,12 @@ static void kernel_oplock_poll_open_timer(struct tevent_context *ev,
 				      struct timeval current_time,
 				      void *private_data)
 {
+	struct deferred_open_record *open_rec = talloc_get_type_abort(
+		private_data, struct deferred_open_record);
 	bool ok;
-	struct smb_request *req = (struct smb_request *)private_data;
 
-	ok = schedule_deferred_open_message_smb(req->xconn, req->mid);
+	ok = schedule_deferred_open_message_smb(
+		open_rec->xconn, open_rec->mid);
 	if (!ok) {
 		exit_server("schedule_deferred_open_message_smb failed");
 	}
@@ -2535,6 +2540,8 @@ static void setup_kernel_oplock_poll_open(struct timeval request_time,
 	if (open_rec == NULL) {
 		exit_server("talloc failed");
 	}
+	open_rec->xconn = req->xconn;
+	open_rec->mid = req->mid;
 
 	ok = push_deferred_open_message_smb(req,
 					    request_time,
@@ -2545,15 +2552,11 @@ static void setup_kernel_oplock_poll_open(struct timeval request_time,
 		exit_server("push_deferred_open_message_smb failed");
 	}
 
-	/*
-	 * As this timer event is owned by req, it will
-	 * disappear if req it talloc_freed.
-	 */
 	open_rec->te = tevent_add_timer(req->sconn->ev_ctx,
-					req,
+					open_rec,
 					timeval_current_ofs(1, 0),
 					kernel_oplock_poll_open_timer,
-					req);
+					open_rec);
 	if (open_rec->te == NULL) {
 		exit_server("tevent_add_timer failed");
 	}
@@ -3214,21 +3217,19 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 		flags2 &= ~(O_CREAT|O_TRUNC);
 	}
 
-	if (lp_kernel_oplocks(SNUM(conn))) {
-		/*
-		 * With kernel oplocks the open breaking an oplock
-		 * blocks until the oplock holder has given up the
-		 * oplock or closed the file. We prevent this by always
-		 * trying to open the file with O_NONBLOCK (see "man
-		 * fcntl" on Linux).
-		 *
-		 * If a process that doesn't use the smbd open files
-		 * database or communication methods holds a kernel
-		 * oplock we must periodically poll for available open
-		 * using O_NONBLOCK.
-		 */
-		flags2 |= O_NONBLOCK;
-	}
+	/*
+	 * With kernel oplocks the open breaking an oplock
+	 * blocks until the oplock holder has given up the
+	 * oplock or closed the file. We prevent this by always
+	 * trying to open the file with O_NONBLOCK (see "man
+	 * fcntl" on Linux).
+	 *
+	 * If a process that doesn't use the smbd open files
+	 * database or communication methods holds a kernel
+	 * oplock we must periodically poll for available open
+	 * using O_NONBLOCK.
+	 */
+	flags2 |= O_NONBLOCK;
 
 	/*
 	 * Ensure we can't write on a read-only share or file.
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 2cb32efea46..17020328eaf 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -45,6 +45,7 @@
 #include "lib/util/base64.h"
 #include "lib/util/time.h"
 #include "lib/gencache.h"
+#include "lib/util/sys_rw.h"
 
 #include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
@@ -4801,6 +4802,274 @@ static void oplock4_got_open(struct tevent_req *req)
 	}
 }
 
+#ifdef HAVE_KERNEL_OPLOCKS_LINUX
+
+struct oplock5_state {
+	int pipe_down_fd;
+};
+
+/*
+ * Async open the file that has a kernel oplock, do an echo to get
+ * that 100% across, close the file to signal to the child fd that the
+ * oplock can be dropped, wait for the open reply.
+ */
+
+static void oplock5_opened(struct tevent_req *subreq);
+static void oplock5_pong(struct tevent_req *subreq);
+static void oplock5_timedout(struct tevent_req *subreq);
+
+static struct tevent_req *oplock5_send(
+	TALLOC_CTX *mem_ctx,
+	struct tevent_context *ev,
+	struct cli_state *cli,
+	const char *fname,
+	int pipe_down_fd)
+{
+	struct tevent_req *req = NULL, *subreq = NULL;
+	struct oplock5_state *state = NULL;
+	static uint8_t data = 0;
+
+	req = tevent_req_create(mem_ctx, &state, struct oplock5_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->pipe_down_fd = pipe_down_fd;
+
+	subreq = cli_ntcreate_send(
+		state,
+		ev,
+		cli,
+		fname,
+		0,			/* CreatFlags */
+		SEC_FILE_READ_DATA,    /* DesiredAccess */
+		FILE_ATTRIBUTE_NORMAL,  /* FileAttributes */
+		FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
+		FILE_OPEN,		 /* CreateDisposition */
+		FILE_NON_DIRECTORY_FILE, /* CreateOptions */
+		0,			 /* Impersonation */
+		0);			 /* SecurityFlags */
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, oplock5_opened, req);
+
+	subreq = cli_echo_send(
+		state,
+		ev,
+		cli,
+		1,
+		(DATA_BLOB) { .data = &data, .length = sizeof(data) });
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, oplock5_pong, req);
+
+	subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(20, 0));
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, oplock5_timedout, req);
+
+	return req;
+}
+
+static void oplock5_opened(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	NTSTATUS status;
+	uint16_t fnum;
+
+	status = cli_ntcreate_recv(subreq, &fnum, NULL);
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+	tevent_req_done(req);
+}
+
+static void oplock5_pong(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct oplock5_state *state = tevent_req_data(
+		req, struct oplock5_state);
+	NTSTATUS status;
+
+	status = cli_echo_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	close(state->pipe_down_fd);
+}
+
+static void oplock5_timedout(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	bool ok;
+
+	ok = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ok) {
+		tevent_req_oom(req);
+		return;
+	}
+	tevent_req_nterror(req, NT_STATUS_TIMEOUT);
+}
+
+static NTSTATUS oplock5_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_ntstatus(req);
+}
+
+static bool run_oplock5(int dummy)
+{
+	struct tevent_context *ev = NULL;
+	struct tevent_req *req = NULL;
+	struct cli_state *cli = NULL;
+	const char *fname = "oplock5.txt";
+	int pipe_down[2], pipe_up[2];
+	pid_t child_pid;
+	uint8_t c = '\0';
+	NTSTATUS status;
+	int ret;
+	bool ok;
+
+	printf("starting oplock5\n");
+
+	if (local_path == NULL) {
+		d_fprintf(stderr, "oplock5 must be given a local path via "
+			  "-l <localpath>\n");
+		return false;
+	}
+
+	ret = pipe(pipe_down);
+	if (ret == -1) {
+		d_fprintf(stderr, "pipe() failed: %s\n", strerror(errno));
+		return false;
+	}
+	ret = pipe(pipe_up);
+	if (ret == -1) {
+		d_fprintf(stderr, "pipe() failed: %s\n", strerror(errno));
+		return false;
+	}
+
+	child_pid = fork();
+	if (child_pid == -1) {
+		d_fprintf(stderr, "fork() failed: %s\n", strerror(errno));
+		return false;
+	}
+
+	if (child_pid == 0) {
+		char *local_file = NULL;
+		int fd;
+
+		close(pipe_down[1]);
+		close(pipe_up[0]);
+
+		local_file = talloc_asprintf(
+			talloc_tos(), "%s/%s", local_path, fname);
+		if (local_file == 0) {
+			c = 1;
+			goto do_write;
+		}
+		fd = open(local_file, O_RDWR|O_CREAT, 0644);
+		if (fd == -1) {
+			d_fprintf(stderr,
+				  "open(%s) in child failed: %s\n",
+				  local_file,
+				  strerror(errno));
+			c = 2;
+			goto do_write;
+		}
+
+		signal(SIGIO, SIG_IGN);
+
+		ret = fcntl(fd, F_SETLEASE, F_WRLCK);
+		if (ret == -1) {
+			d_fprintf(stderr,
+				  "SETLEASE in child failed: %s\n",
+				  strerror(errno));
+			c = 3;
+			goto do_write;
+		}
+
+	do_write:
+		ret = sys_write(pipe_up[1], &c, sizeof(c));
+		if (ret == -1) {
+			d_fprintf(stderr,
+				  "sys_write failed: %s\n",
+				  strerror(errno));
+			exit(4);
+		}
+		ret = sys_read(pipe_down[0], &c, sizeof(c));
+		if (ret == -1) {
+			d_fprintf(stderr,
+				  "sys_read failed: %s\n",
+				  strerror(errno));
+			exit(5);
+		}
+		exit(0);
+	}
+
+	close(pipe_up[1]);
+	close(pipe_down[0]);
+
+	ret = sys_read(pipe_up[0], &c, sizeof(c));
+	if (ret != 1) {
+		d_fprintf(stderr,
+			  "sys_read failed: %s\n",
+			  strerror(errno));
+		return false;
+	}
+	if (c != 0) {
+		d_fprintf(stderr, "got error code %"PRIu8"\n", c);
+		return false;
+	}
+
+	ok = torture_open_connection(&cli, 0);
+	if (!ok) {
+		d_fprintf(stderr, "torture_open_connection failed\n");
+		return false;
+	}
+
+	ev = samba_tevent_context_init(talloc_tos());
+	if (ev == NULL) {
+		d_fprintf(stderr, "samba_tevent_context_init failed\n");
+		return false;
+	}
+
+	req = oplock5_send(ev, ev, cli, fname, pipe_down[1]);
+	if (req == NULL) {
+		d_fprintf(stderr, "oplock5_send failed\n");
+		return false;
+	}
+
+	ok = tevent_req_poll_ntstatus(req, ev, &status);
+	if (!ok) {
+		d_fprintf(stderr,
+			  "tevent_req_poll_ntstatus failed: %s\n",
+			  nt_errstr(status));
+		return false;
+	}
+
+	status = oplock5_recv(req);
+	TALLOC_FREE(req);
+	if (!NT_STATUS_IS_OK(status)) {
+		d_fprintf(stderr,
+			  "oplock5 failed: %s\n",
+			  nt_errstr(status));
+		return false;
+	}
+
+	return true;
+}
+
+#endif /* HAVE_KERNEL_OPLOCKS_LINUX */
+
 /*
   Test delete on close semantics.
  */
@@ -13546,6 +13815,10 @@ static struct {
 		.name  = "OPLOCK4",
 		.fn    =  run_oplock4,
 	},
+	{
+		.name  = "OPLOCK5",
+		.fn    =  run_oplock5,
+	},
 	{
 		.name  = "DIR",
 		.fn    =  run_dirtest,


-- 
Samba Shared Repository



More information about the samba-cvs mailing list