[PATCH] torture: Add smb2.oplock.levelII501 test

Volker Lendecke Volker.Lendecke at SerNet.DE
Thu Oct 24 05:48:02 MDT 2013


Hi!

Attached find a test that excercises some strange Windows
behaviour. See

https://lists.samba.org/archive/cifs-protocol/2013-October/002466.html

for more info. This is skipped right now, I'm trying to find
the right behaviour. But I want to get it off my patch
list...

Please review & push!

Thanks,

Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From 4711239113204a93276326bf5d034e7a94cc643b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 22 Oct 2013 09:18:01 +0000
Subject: [PATCH] torture: Add smb2.oplock.levelII501 test

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 selftest/skip                 |   2 +
 source4/torture/smb2/oplock.c | 257 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 258 insertions(+), 1 deletion(-)

diff --git a/selftest/skip b/selftest/skip
index 0b8468d..de721f3 100644
--- a/selftest/skip
+++ b/selftest/skip
@@ -43,6 +43,7 @@
 ^samba3.smb2.hold-oplock                # Not a test, but a way to block other clients for a test
 ^samba3.smb2.durable-open-disconnect    # Not a test, but a way to create a disconnected durable
 ^samba3.smb2.scan                       # No tests
+^samba3.smb2.oplock.levelii501		# No test yet
 ^samba4.base.iometer
 ^samba4.base.casetable
 ^samba4.base.nttrans
@@ -62,6 +63,7 @@
 ^samba4.smb2.dir
 ^samba4.smb2.session
 ^samba4.smb2.compound
+^samba4.smb2.oplock.levelii501		# No test yet
 ^samba4.ntvfs.cifs.*.base.charset
 ^samba4.ntvfs.cifs.*.base.iometer
 ^samba4.ntvfs.cifs.*.base.casetable
diff --git a/source4/torture/smb2/oplock.c b/source4/torture/smb2/oplock.c
index fb737fe..463b431 100644
--- a/source4/torture/smb2/oplock.c
+++ b/source4/torture/smb2/oplock.c
@@ -3480,6 +3480,260 @@ static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
 	return ret;
 }
 
+/*
+ * Test a double-break. Open a file with exclusive. Send off a second open
+ * request with OPEN_IF, triggering a break to level2. This should respond
+ * with level2. Before replying to the break to level2, fire off a third open
+ * with OVERWRITE_IF. The expected sequence would be that the 3rd opener gets
+ * a level2 immediately triggered by a break to none, but that seems not the
+ * case. Still investigating what the right behaviour should be.
+ */
+
+struct levelII501_state {
+	struct torture_context *tctx;
+	struct smb2_tree *tree1;
+	struct smb2_tree *tree2;
+	struct smb2_tree *tree3;
+	struct smb2_handle h;
+	struct smb2_handle h1;
+	union smb_open io;
+
+	struct smb2_handle break_handle;
+	uint8_t break_to;
+	struct smb2_break br;
+
+	bool done;
+};
+
+static bool torture_oplock_break_delay(struct smb2_transport *transport,
+				       const struct smb2_handle *handle,
+				       uint8_t level, void *private_data);
+static void levelII501_break_done(struct smb2_request *req);
+static void levelII501_open1_done(struct smb2_request *req);
+static void levelII501_open2_done(struct smb2_request *req);
+static void levelII501_2ndopen_cb(struct tevent_context *ev,
+				  struct tevent_timer *te,
+				  struct timeval current_time,
+				  void *private_data);
+static void levelII501_break_timeout_cb(struct tevent_context *ev,
+					struct tevent_timer *te,
+					struct timeval current_time,
+					void *private_data);
+static void levelII501_timeout_cb(struct tevent_context *ev,
+				  struct tevent_timer *te,
+				  struct timeval current_time,
+				  void *private_data);
+
+static bool test_smb2_oplock_levelII501(struct torture_context *tctx,
+					struct smb2_tree *tree1,
+					struct smb2_tree *tree2)
+{
+	const char *fname = BASEDIR "\\test_levelII501.dat";
+	NTSTATUS status;
+	bool ret = true;
+	struct levelII501_state *state;
+	struct smb2_request *req;
+	struct tevent_timer *te;
+
+	state = talloc(tctx, struct levelII501_state);
+	state->tctx = tctx;
+	state->done = false;
+	state->tree1 = tree1;
+	state->tree2 = tree2;
+
+	if (!torture_smb2_connection(tctx, &state->tree3)) {
+		torture_fail(tctx, "Establishing SMB2 connection failed\n");
+		return false;
+	}
+
+	status = torture_smb2_testdir(tree1, BASEDIR, &state->h);
+	torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+	/* cleanup */
+	smb2_util_unlink(tree1, fname);
+
+	/*
+	  base ntcreatex parms
+	*/
+	ZERO_STRUCT(state->io.smb2);
+	state->io.generic.level = RAW_OPEN_SMB2;
+	state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+	state->io.smb2.in.alloc_size = 0;
+	state->io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+	state->io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+	state->io.smb2.in.create_options = 0;
+	state->io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+	state->io.smb2.in.security_flags = 0;
+	state->io.smb2.in.fname = fname;
+
+	torture_comment(tctx, "LEVELII501: Test double break sequence\n");
+	ZERO_STRUCT(break_info);
+
+	state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+				SEC_RIGHTS_FILE_WRITE;
+	state->io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+				NTCREATEX_SHARE_ACCESS_WRITE;
+	state->io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+	state->io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+	tree1->session->transport->oplock.handler = torture_oplock_break_delay;
+	tree1->session->transport->oplock.private_data = state;
+
+	status = smb2_create(tree1, tctx, &(state->io.smb2));
+	torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+	state->h1 = state->io.smb2.out.file.handle;
+	CHECK_VAL(state->io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+	/*
+	 * Trigger a break to level2
+	 */
+
+	req = smb2_create_send(tree2, &state->io.smb2);
+	req->async.fn = levelII501_open1_done;
+	req->async.private_data = state;
+
+	te = tevent_add_timer(
+		tctx->ev, tctx, tevent_timeval_current_ofs(0, 200000),
+		levelII501_2ndopen_cb, state);
+	torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
+
+	te = tevent_add_timer(
+		tctx->ev, tctx, tevent_timeval_current_ofs(2, 0),
+		levelII501_timeout_cb, state);
+	torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
+
+	while (!state->done) {
+		if (tevent_loop_once(tctx->ev) != 0) {
+			torture_comment(tctx, "tevent_loop_once failed\n");
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Fire off a second open after a little timeout
+ */
+
+static void levelII501_2ndopen_cb(struct tevent_context *ev,
+				  struct tevent_timer *te,
+				  struct timeval current_time,
+				  void *private_data)
+{
+	struct levelII501_state *state = talloc_get_type_abort(
+		private_data, struct levelII501_state);
+	struct smb2_request *req;
+
+	state->io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+	req = smb2_create_send(state->tree3, &state->io.smb2);
+	req->async.fn = levelII501_open2_done;
+	req->async.private_data = state;
+}
+
+/*
+ * Postpone the break response by 500 msec
+ */
+static bool torture_oplock_break_delay(struct smb2_transport *transport,
+				       const struct smb2_handle *handle,
+				       uint8_t level, void *private_data)
+{
+	struct levelII501_state *state = talloc_get_type_abort(
+		private_data, struct levelII501_state);
+	const char *name;
+	struct tevent_timer *te;
+
+	break_info.handle	= *handle;
+	break_info.level	= level;
+	break_info.count++;
+
+	state->break_handle = *handle;
+	state->break_to = level;
+
+	switch(level) {
+	case SMB2_OPLOCK_LEVEL_II:
+		name = "level II";
+		break;
+	case SMB2_OPLOCK_LEVEL_NONE:
+		name = "none";
+		break;
+	default:
+		name = "unknown";
+		break;
+	}
+	printf("Got break to %s [0x%02X] in oplock handler, postponing "
+	       "break response for 500msec\n", name, level);
+
+	te = tevent_add_timer(
+		state->tctx->ev, state->tctx,
+		tevent_timeval_current_ofs(0, 500000),
+		levelII501_break_timeout_cb, state);
+	torture_assert(state->tctx, te != NULL, "tevent_add_timer failed\n");
+
+	return true;
+}
+
+static void levelII501_break_timeout_cb(struct tevent_context *ev,
+					struct tevent_timer *te,
+					struct timeval current_time,
+					void *private_data)
+{
+	struct levelII501_state *state = talloc_get_type_abort(
+		private_data, struct levelII501_state);
+	struct smb2_request *req;
+
+	talloc_free(te);
+
+	ZERO_STRUCT(state->br);
+	state->br.in.file.handle = state->break_handle;
+	state->br.in.oplock_level = state->break_to;
+
+	req = smb2_break_send(state->tree1, &state->br);
+	req->async.fn = levelII501_break_done;
+	req->async.private_data = state;
+}
+
+static void levelII501_break_done(struct smb2_request *req)
+{
+	struct smb2_break io;
+	NTSTATUS status;
+
+	status = smb2_break_recv(req, &io);
+	printf("break done: %s\n", nt_errstr(status));
+}
+
+static void levelII501_open1_done(struct smb2_request *req)
+{
+	struct levelII501_state *state = talloc_get_type_abort(
+		req->async.private_data, struct levelII501_state);
+	struct smb2_create io;
+	NTSTATUS status;
+
+	status = smb2_create_recv(req, state, &io);
+	printf("open1 done: %s\n", nt_errstr(status));
+}
+
+static void levelII501_open2_done(struct smb2_request *req)
+{
+	struct levelII501_state *state = talloc_get_type_abort(
+		req->async.private_data, struct levelII501_state);
+	struct smb2_create io;
+	NTSTATUS status;
+
+	status = smb2_create_recv(req, state, &io);
+	printf("open2 done: %s\n", nt_errstr(status));
+}
+
+static void levelII501_timeout_cb(struct tevent_context *ev,
+				  struct tevent_timer *te,
+				  struct timeval current_time,
+				  void *private_data)
+{
+	struct levelII501_state *state = talloc_get_type_abort(
+		private_data, struct levelII501_state);
+	talloc_free(te);
+	state->done = true;
+}
+
 struct torture_suite *torture_smb2_oplocks_init(void)
 {
 	struct torture_suite *suite =
@@ -3522,7 +3776,8 @@ struct torture_suite *torture_smb2_oplocks_init(void)
 	torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
 	torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
 	torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
-
+	torture_suite_add_2smb2_test(suite, "levelii501",
+				     test_smb2_oplock_levelII501);
 	suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
 
 	return suite;
-- 
1.8.1.2



More information about the samba-technical mailing list