[RFC] Fix SMB2 aio cancelling

Ralph Böhme slow at samba.org
Mon Oct 29 09:13:12 UTC 2018


On Sun, Oct 28, 2018 at 08:04:16PM +0100, Ralph Böhme via samba-technical wrote:
>CI: https://gitlab.com/samba-team/devel/samba/pipelines/34610466

failed in the ntvfs, forgot to disable the test there.

Updated patchset attached.

CI: https://gitlab.com/samba-team/devel/samba/pipelines/34651035

-slow

-- 
Ralph Boehme, Samba Team       https://samba.org/
Samba Developer, SerNet GmbH   https://sernet.de/en/samba/
GPG Key Fingerprint:           FAE2 C608 8A24 2520 51C5
                               59E4 AA1E 9B71 2639 9E46
-------------- next part --------------
From 8eac1c0e1587c134bf191d247273900dae942637 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 28 Oct 2018 02:03:28 +0100
Subject: [PATCH 1/7] libcli: add smbXcli_req_endtime

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13667

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 libcli/smb/smbXcli_base.c | 10 ++++++++++
 libcli/smb/smbXcli_base.h |  1 +
 2 files changed, 11 insertions(+)

diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index d94b4d87f27..b7bf5796ba8 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -227,6 +227,8 @@ struct smbXcli_req_state {
 
 	struct tevent_req *write_req;
 
+	struct timeval endtime;
+
 	struct {
 		/* Space for the header including the wct */
 		uint8_t hdr[HDR_VWV];
@@ -2892,6 +2894,14 @@ static void smb2cli_req_cancel_done(struct tevent_req *subreq)
 	TALLOC_FREE(subreq);
 }
 
+struct timeval smbXcli_req_endtime(struct tevent_req *req)
+{
+	struct smbXcli_req_state *state = tevent_req_data(
+		req, struct smbXcli_req_state);
+
+	return state->endtime;
+}
+
 struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
 				      struct tevent_context *ev,
 				      struct smbXcli_conn *conn,
diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
index 20ef26e3353..536c7ab60f4 100644
--- a/libcli/smb/smbXcli_base.h
+++ b/libcli/smb/smbXcli_base.h
@@ -74,6 +74,7 @@ NTSTATUS smbXcli_conn_samba_suicide(struct smbXcli_conn *conn,
 
 void smbXcli_req_unset_pending(struct tevent_req *req);
 bool smbXcli_req_set_pending(struct tevent_req *req);
+struct timeval smbXcli_req_endtime(struct tevent_req *req);
 
 uint32_t smb1cli_conn_capabilities(struct smbXcli_conn *conn);
 uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn);
-- 
2.17.2


From e7a733a53868f17d02d821ddb9e8c53c553f6f05 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 28 Oct 2018 02:04:51 +0100
Subject: [PATCH 2/7] libcli: fill endtime if smbXcli_req_create() timeout is
 non-zero

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13667

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 libcli/smb/smbXcli_base.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index b7bf5796ba8..9edb6292777 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -1585,10 +1585,8 @@ struct tevent_req *smb1cli_req_create(TALLOC_CTX *mem_ctx,
 	state->smb1.iov_count = iov_count + 4;
 
 	if (timeout_msec > 0) {
-		struct timeval endtime;
-
-		endtime = timeval_current_ofs_msec(timeout_msec);
-		if (!tevent_req_set_endtime(req, ev, endtime)) {
+		state->endtime = timeval_current_ofs_msec(timeout_msec);
+		if (!tevent_req_set_endtime(req, ev, state->endtime)) {
 			return req;
 		}
 	}
@@ -3051,10 +3049,8 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
 	}
 
 	if (timeout_msec > 0) {
-		struct timeval endtime;
-
-		endtime = timeval_current_ofs_msec(timeout_msec);
-		if (!tevent_req_set_endtime(req, ev, endtime)) {
+		state->endtime = timeval_current_ofs_msec(timeout_msec);
+		if (!tevent_req_set_endtime(req, ev, state->endtime)) {
 			return req;
 		}
 	}
-- 
2.17.2


From 079fe5e5b26249c86025cc58275fe278c248ef75 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 28 Oct 2018 02:05:45 +0100
Subject: [PATCH 3/7] s4:libcli/smb2: reapply request endtime

tevent_req_finish() removed a possible request timeout, make sure to
reinstall it. This happened when an interim SMB2 response was received.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13667

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source4/libcli/smb2/transport.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c
index 1d08289341b..f45d71d52d6 100644
--- a/source4/libcli/smb2/transport.c
+++ b/source4/libcli/smb2/transport.c
@@ -293,7 +293,23 @@ static void smb2_request_done(struct tevent_req *subreq)
 
 	req->status = smb2cli_req_recv(req->subreq, req, &req->recv_iov, NULL, 0);
 	if (NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
+		struct timeval endtime = smbXcli_req_endtime(subreq);
+		bool ok;
+
 		req->cancel.can_cancel = true;
+		if (timeval_is_zero(&endtime)) {
+			return;
+		}
+
+		ok = tevent_req_set_endtime(subreq, req->transport->ev, endtime);
+		if (!ok) {
+			req->status = NT_STATUS_INTERNAL_ERROR;
+			req->state = SMB2_REQUEST_ERROR;
+			if (req->async.fn) {
+				req->async.fn(req);
+			}
+			return;
+		}
 		return;
 	}
 	TALLOC_FREE(req->subreq);
-- 
2.17.2


From 7f8a6c5215ec806485b14eef2c494bbaffeb3210 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 28 Oct 2018 19:28:42 +0100
Subject: [PATCH 4/7] vfs_delay_inject: implement pread_send and pwrite_send

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13667

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_delay_inject.c | 259 +++++++++++++++++++++++++++++
 1 file changed, 259 insertions(+)

diff --git a/source3/modules/vfs_delay_inject.c b/source3/modules/vfs_delay_inject.c
index 21fea9b10f4..25326428887 100644
--- a/source3/modules/vfs_delay_inject.c
+++ b/source3/modules/vfs_delay_inject.c
@@ -19,6 +19,7 @@
 
 #include "includes.h"
 #include "smbd/smbd.h"
+#include "lib/util/tevent_unix.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -46,8 +47,266 @@ static int vfs_delay_inject_ntimes(vfs_handle_struct *handle,
 	return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
 }
 
+struct vfs_delay_inject_pread_state {
+	struct tevent_context *ev;
+	struct vfs_handle_struct *handle;
+	struct files_struct *fsp;
+	void *data;
+	size_t n;
+	off_t offset;
+	ssize_t ret;
+	struct vfs_aio_state vfs_aio_state;
+};
+
+static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq);
+static void vfs_delay_inject_pread_done(struct tevent_req *subreq);
+
+static struct tevent_req *vfs_delay_inject_pread_send(
+				struct vfs_handle_struct *handle,
+				TALLOC_CTX *mem_ctx,
+				struct tevent_context *ev,
+				struct files_struct *fsp,
+				void *data,
+				size_t n,
+				off_t offset)
+{
+	struct tevent_req *req = NULL, *subreq = NULL;
+	struct vfs_delay_inject_pread_state *state = NULL;
+	int delay;
+	struct timeval delay_tv;
+
+	delay = lp_parm_int(SNUM(handle->conn), "delay_inject", "pread_send", 0);
+	delay_tv = tevent_timeval_current_ofs(delay / 1000,
+					      (delay * 1000) % 1000000);
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct vfs_delay_inject_pread_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	*state = (struct vfs_delay_inject_pread_state) {
+		.ev = ev,
+		.handle = handle,
+		.fsp = fsp,
+		.data = data,
+		.n = n,
+		.offset = offset,
+	};
+
+	if (delay == 0) {
+		subreq = SMB_VFS_NEXT_PREAD_SEND(state,
+						 state->ev,
+						 state->handle,
+						 state->fsp,
+						 state->data,
+						 state->n,
+						 state->offset);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(subreq,
+					vfs_delay_inject_pread_done,
+					req);
+		return req;
+	}
+
+	subreq = tevent_wakeup_send(state, ev, delay_tv);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, vfs_delay_inject_pread_wait_done, req);
+	return req;
+}
+
+
+static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct vfs_delay_inject_pread_state *state = tevent_req_data(
+		req, struct vfs_delay_inject_pread_state);
+	bool ok;
+
+	ok = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ok) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	subreq = SMB_VFS_NEXT_PREAD_SEND(state,
+					 state->ev,
+					 state->handle,
+					 state->fsp,
+					 state->data,
+					 state->n,
+					 state->offset);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, vfs_delay_inject_pread_done, req);
+}
+
+static void vfs_delay_inject_pread_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct vfs_delay_inject_pread_state *state = tevent_req_data(
+		req, struct vfs_delay_inject_pread_state);
+
+	state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
+	TALLOC_FREE(subreq);
+
+	tevent_req_done(req);
+}
+
+static ssize_t vfs_delay_inject_pread_recv(struct tevent_req *req,
+				struct vfs_aio_state *vfs_aio_state)
+{
+	struct vfs_delay_inject_pread_state *state = tevent_req_data(
+		req, struct vfs_delay_inject_pread_state);
+
+	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+		return -1;
+	}
+
+	*vfs_aio_state = state->vfs_aio_state;
+	return state->ret;
+}
+
+struct vfs_delay_inject_pwrite_state {
+	struct tevent_context *ev;
+	struct vfs_handle_struct *handle;
+	struct files_struct *fsp;
+	const void *data;
+	size_t n;
+	off_t offset;
+	ssize_t ret;
+	struct vfs_aio_state vfs_aio_state;
+};
+
+static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq);
+static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq);
+
+static struct tevent_req *vfs_delay_inject_pwrite_send(
+				struct vfs_handle_struct *handle,
+				TALLOC_CTX *mem_ctx,
+				struct tevent_context *ev,
+				struct files_struct *fsp,
+				const void *data,
+				size_t n,
+				off_t offset)
+{
+	struct tevent_req *req = NULL, *subreq = NULL;
+	struct vfs_delay_inject_pwrite_state *state = NULL;
+	int delay;
+	struct timeval delay_tv;
+
+	delay = lp_parm_int(SNUM(handle->conn), "delay_inject", "pwrite_send", 0);
+	delay_tv = tevent_timeval_current_ofs(delay / 1000,
+					      (delay * 1000) % 1000000);
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct vfs_delay_inject_pwrite_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	*state = (struct vfs_delay_inject_pwrite_state) {
+		.ev = ev,
+		.handle = handle,
+		.fsp = fsp,
+		.data = data,
+		.n = n,
+		.offset = offset,
+	};
+
+	if (delay == 0) {
+		subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
+						 state->ev,
+						 state->handle,
+						 state->fsp,
+						 state->data,
+						 state->n,
+						 state->offset);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(subreq,
+					vfs_delay_inject_pwrite_done,
+					req);
+		return req;
+	}
+
+	subreq = tevent_wakeup_send(state, ev, delay_tv);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, vfs_delay_inject_pwrite_wait_done, req);
+	return req;
+}
+
+
+static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
+		req, struct vfs_delay_inject_pwrite_state);
+	bool ok;
+
+	ok = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ok) {
+		tevent_req_error(req, EIO);
+		return;
+	}
+
+	subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
+					 state->ev,
+					 state->handle,
+					 state->fsp,
+					 state->data,
+					 state->n,
+					 state->offset);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, vfs_delay_inject_pwrite_done, req);
+}
+
+static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
+		req, struct vfs_delay_inject_pwrite_state);
+
+	state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
+	TALLOC_FREE(subreq);
+
+	tevent_req_done(req);
+}
+
+static ssize_t vfs_delay_inject_pwrite_recv(struct tevent_req *req,
+				struct vfs_aio_state *vfs_aio_state)
+{
+	struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
+		req, struct vfs_delay_inject_pwrite_state);
+
+	if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+		return -1;
+	}
+
+	*vfs_aio_state = state->vfs_aio_state;
+	return state->ret;
+}
+
 static struct vfs_fn_pointers vfs_delay_inject_fns = {
 	.ntimes_fn = vfs_delay_inject_ntimes,
+	.pread_send_fn = vfs_delay_inject_pread_send,
+	.pread_recv_fn = vfs_delay_inject_pread_recv,
+	.pwrite_send_fn = vfs_delay_inject_pwrite_send,
+	.pwrite_recv_fn = vfs_delay_inject_pwrite_recv,
 };
 
 static_decl_vfs;
-- 
2.17.2


From 851d23b560899a33a2dd30ca48f643b57222a8c0 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 28 Oct 2018 19:29:26 +0100
Subject: [PATCH 5/7] s4:torture/smb2/read: add test for cancelling SMB aio

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13667

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail.d/samba3.smb2 |  1 +
 selftest/target/Samba3.pm        |  6 +++
 source3/selftest/tests.py        |  2 +
 source4/selftest/tests.py        |  1 +
 source4/torture/smb2/read.c      | 80 ++++++++++++++++++++++++++++++++
 source4/torture/smb2/smb2.c      |  1 +
 6 files changed, 91 insertions(+)
 create mode 100644 selftest/knownfail.d/samba3.smb2

diff --git a/selftest/knownfail.d/samba3.smb2 b/selftest/knownfail.d/samba3.smb2
new file mode 100644
index 00000000000..f4e2ecf3da4
--- /dev/null
+++ b/selftest/knownfail.d/samba3.smb2
@@ -0,0 +1 @@
+^samba3.smb2.aio_delay.aio_cancel\(nt4_dc\)
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 356b4d3f82a..d46b7cb7ba6 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -2232,6 +2232,12 @@ sub provision($$$$$$$$$)
 	kernel oplocks = no
 	posix locking = no
 	include = $libdir/delay_inject.conf
+
+[aio_delay_inject]
+	copy = tmp
+	vfs objects = delay_inject
+	delay_inject:pread_send = 2000
+	delay_inject:pwrite_send = 2000
 	";
 	close(CONF);
 
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 75190c49b2b..d76fed92445 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -603,6 +603,8 @@ tests = base + raw + smb2 + rpc + unix + local + rap + nbt + libsmbclient + idma
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/streams_xattr -U$USERNAME%$PASSWORD', 'streams_xattr')
+    elif t == "smb2.aio_delay":
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/aio_delay_inject -U$USERNAME%$PASSWORD')
     else:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 6b5ceb556c9..d94f641f18b 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -331,6 +331,7 @@ smb2_s3only = [
     "smb2.credits",
     "smb2.kernel-oplocks",
     "smb2.durable-v2-delay",
+    "smb2.aio_delay",
 ]
 smb2 = [x for x in smbtorture4_testsuites("smb2.") if x not in smb2_s3only]
 
diff --git a/source4/torture/smb2/read.c b/source4/torture/smb2/read.c
index 4bf3bb74be0..039017cfa4f 100644
--- a/source4/torture/smb2/read.c
+++ b/source4/torture/smb2/read.c
@@ -22,6 +22,7 @@
 #include "includes.h"
 #include "libcli/smb2/smb2.h"
 #include "libcli/smb2/smb2_calls.h"
+#include <tevent.h>
 
 #include "torture/torture.h"
 #include "torture/smb2/proto.h"
@@ -317,3 +318,82 @@ struct torture_suite *torture_smb2_read_init(TALLOC_CTX *ctx)
 	return suite;
 }
 
+static bool test_aio_cancel(struct torture_context *tctx,
+			    struct smb2_tree *tree)
+{
+	struct smb2_handle h;
+	uint8_t buf[64 * 1024];
+	struct smb2_read r;
+	struct smb2_request *req = NULL;
+	int rc;
+	NTSTATUS status;
+	bool ret = true;
+
+	ZERO_STRUCT(buf);
+
+	smb2_util_unlink(tree, FNAME);
+
+	status = torture_smb2_testfile(tree, FNAME, &h);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_close failed\n");
+
+	status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_close failed\n");
+
+	status = smb2_util_close(tree, h);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_close failed\n");
+
+	status = torture_smb2_testfile_access(tree, FNAME, &h,
+					      SEC_RIGHTS_FILE_ALL);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_close failed\n");
+
+	r = (struct smb2_read) {
+		.in.file.handle = h,
+		.in.length      = 1,
+		.in.offset      = 0,
+		.in.min_count   = 1,
+	};
+
+	req = smb2_read_send(tree, &r);
+	torture_assert_goto(tctx, req != NULL, ret, done,
+			    "smb2_read_send failed\n");
+
+	while (!req->cancel.can_cancel) {
+		rc = tevent_loop_once(tctx->ev);
+		torture_assert_goto(tctx, rc == 0, ret, done,
+				    "tevent_loop_once failed\n");
+	}
+
+	status = smb2_cancel(req);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_close failed\n");
+
+	status = smb2_read_recv(req, tree, &r);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_read_recv failed\n");
+
+	status = smb2_util_close(tree, h);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_util_close failed\n");
+
+done:
+	smb2_util_unlink(tree, FNAME);
+	return ret;
+}
+
+/*
+ * aio testing against share with VFS module "delay_inject"
+ */
+struct torture_suite *torture_smb2_aio_delay_init(TALLOC_CTX *ctx)
+{
+	struct torture_suite *suite = torture_suite_create(ctx, "aio_delay");
+
+	torture_suite_add_1smb2_test(suite, "aio_cancel", test_aio_cancel);
+
+	suite->description = talloc_strdup(suite, "SMB2 delayed aio tests");
+
+	return suite;
+}
diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c
index 12f7edf8f86..6f9884e3c27 100644
--- a/source4/torture/smb2/smb2.c
+++ b/source4/torture/smb2/smb2.c
@@ -152,6 +152,7 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx)
 	torture_suite_add_simple_test(suite, "setinfo", torture_smb2_setinfo);
 	torture_suite_add_suite(suite, torture_smb2_lock_init(suite));
 	torture_suite_add_suite(suite, torture_smb2_read_init(suite));
+	torture_suite_add_suite(suite, torture_smb2_aio_delay_init(suite));
 	torture_suite_add_suite(suite, torture_smb2_create_init(suite));
 	torture_suite_add_suite(suite, torture_smb2_acls_init(suite));
 	torture_suite_add_suite(suite, torture_smb2_notify_init(suite));
-- 
2.17.2


From a25d3adb9722ef6756a0d48eee1991d2206d7770 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 27 Oct 2018 22:50:30 +0200
Subject: [PATCH 6/7] Revert "s3:smbd: missing tevent_req_nterror"

This reverts commit ad52dcdf5de6f5f2c2ee156d93ebbb343f39e526.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13667

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/aio.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index c066ea1a978..a5fc2d7efaf 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -747,10 +747,10 @@ static void aio_pread_smb2_done(struct tevent_req *req)
 		   (nread == -1) ? strerror(vfs_aio_state.error) : "no error"));
 
 	if (fsp == NULL) {
-		DEBUG(3, ("%s: request cancelled (mid[%ju])\n",
-			  __func__, (uintmax_t)aio_ex->smbreq->mid));
+		DEBUG( 3, ("aio_pread_smb2_done: file closed whilst "
+			   "aio outstanding (mid[%llu]).\n",
+			   (unsigned long long)aio_ex->smbreq->mid));
 		TALLOC_FREE(aio_ex);
-		tevent_req_nterror(subreq, NT_STATUS_INTERNAL_ERROR);
 		return;
 	}
 
@@ -910,10 +910,10 @@ static void aio_pwrite_smb2_done(struct tevent_req *req)
 		   (nwritten == -1) ? strerror(err) : "no error"));
 
 	if (fsp == NULL) {
-		DEBUG(3, ("%s: request cancelled (mid[%ju])\n",
-			  __func__, (uintmax_t)aio_ex->smbreq->mid));
+		DEBUG( 3, ("aio_pwrite_smb2_done: file closed whilst "
+			   "aio outstanding (mid[%llu]).\n",
+			   (unsigned long long)aio_ex->smbreq->mid));
 		TALLOC_FREE(aio_ex);
-		tevent_req_nterror(subreq, NT_STATUS_INTERNAL_ERROR);
 		return;
 	}
 
-- 
2.17.2


From fc7df5670fba91afa215a31990366a2e85f4fb50 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 28 Oct 2018 19:35:59 +0100
Subject: [PATCH 7/7] s3:smbd: fix SMB2 aio cancelling

As we currently don't attempt to cancel the internal aio request, we
must ignore the SMB2 cancel request and continue to process the SMB2
request, cf MS-SM2 3.3.5.16:

  If the target request is not successfully canceled, processing of the
  target request MUST continue and no response is sent to the cancel
  request.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13667

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail.d/samba3.smb2 |  1 -
 source3/smbd/aio.c               | 12 ++++++++----
 2 files changed, 8 insertions(+), 5 deletions(-)
 delete mode 100644 selftest/knownfail.d/samba3.smb2

diff --git a/selftest/knownfail.d/samba3.smb2 b/selftest/knownfail.d/samba3.smb2
deleted file mode 100644
index f4e2ecf3da4..00000000000
--- a/selftest/knownfail.d/samba3.smb2
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.smb2.aio_delay.aio_cancel\(nt4_dc\)
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index a5fc2d7efaf..0d2b91ab40c 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -622,12 +622,16 @@ bool cancel_smb2_aio(struct smb_request *smbreq)
 	}
 
 	/*
-	 * We let the aio request run. Setting fsp to NULL has the
-	 * effect that the _done routines don't send anything out.
+	 * We let the aio request run and don't try to cancel it which means
+	 * processing of the SMB2 request must continue as normal, cf MS-SMB2
+	 * 3.3.5.16:
+	 *
+	 *   If the target request is not successfully canceled, processing of
+	 *   the target request MUST continue and no response is sent to the
+	 *   cancel request.
 	 */
 
-	aio_ex->fsp = NULL;
-	return true;
+	return false;
 }
 
 static void aio_pread_smb2_done(struct tevent_req *req);
-- 
2.17.2



More information about the samba-technical mailing list