[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