[SCM] Samba Shared Repository - branch master updated - tevent-0-9-8-860-gc38c99a

Steven Danneman sdanneman at samba.org
Thu Oct 1 17:40:57 MDT 2009


The branch, master has been updated
       via  c38c99af91baf4a130917f1a0eb399879ae5708f (commit)
      from  295fec2b46be2ee492b1fbe7a51d95de8ddce5ba (commit)

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


- Log -----------------------------------------------------------------
commit c38c99af91baf4a130917f1a0eb399879ae5708f
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Thu Oct 1 16:38:40 2009 -0700

    s4/torture: second try on renaming oplocks.c to oplock.c
    
    Forgot to "git add" the new file in commit b2bcfaae

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

Summary of changes:
 source4/torture/smb2/oplock.c | 3617 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 3617 insertions(+), 0 deletions(-)
 create mode 100644 source4/torture/smb2/oplock.c


Changeset truncated at 500 lines:

diff --git a/source4/torture/smb2/oplock.c b/source4/torture/smb2/oplock.c
new file mode 100644
index 0000000..f686de6
--- /dev/null
+++ b/source4/torture/smb2/oplock.c
@@ -0,0 +1,3617 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   test suite for SMB2 oplocks
+
+   Copyright (C) Andrew Tridgell 2003
+   Copyright (C) Stefan Metzmacher 2008
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "libcli/resolve/resolve.h"
+
+#include "lib/cmdline/popt_common.h"
+#include "lib/events/events.h"
+
+#include "param/param.h"
+#include "system/filesys.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+
+#define CHECK_RANGE(v, min, max) do { \
+	if ((v) < (min) || (v) > (max)) { \
+		torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
+			       "got %d - should be between %d and %d\n", \
+				__location__, #v, (int)v, (int)min, (int)max); \
+		ret = false; \
+	}} while (0)
+
+#define CHECK_STRMATCH(v, correct) do { \
+	if (!v || strstr((v),(correct)) == NULL) { \
+		torture_result(tctx, TORTURE_FAIL,  "(%s): wrong value for %s "\
+			       "got '%s' - should be '%s'\n", \
+				__location__, #v, v?v:"NULL", correct); \
+		ret = false; \
+	}} while (0)
+
+#define CHECK_VAL(v, correct) do { \
+	if ((v) != (correct)) { \
+		torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
+			       "got 0x%x - should be 0x%x\n", \
+				__location__, #v, (int)v, (int)correct); \
+		ret = false; \
+	}} while (0)
+
+#define BASEDIR "oplock_test"
+
+static struct {
+	struct smb2_handle handle;
+	uint8_t level;
+	struct smb2_break br;
+	int count;
+	int failures;
+	NTSTATUS failure_status;
+} break_info;
+
+static void torture_oplock_break_callback(struct smb2_request *req)
+{
+	NTSTATUS status;
+	struct smb2_break br;
+
+	ZERO_STRUCT(br);
+	status = smb2_break_recv(req, &break_info.br);
+	if (!NT_STATUS_IS_OK(status)) {
+		break_info.failures++;
+		break_info.failure_status = status;
+	}
+
+	return;
+}
+
+/* A general oplock break notification handler.  This should be used when a
+ * test expects to break from batch or exclusive to a lower level. */
+static bool torture_oplock_handler(struct smb2_transport *transport,
+				   const struct smb2_handle *handle,
+				   uint8_t level,
+				   void *private_data)
+{
+	struct smb2_tree *tree = private_data;
+	const char *name;
+	struct smb2_request *req;
+	ZERO_STRUCT(break_info.br);
+
+	break_info.handle	= *handle;
+	break_info.level	= level;
+	break_info.count++;
+
+	switch (level) {
+	case SMB2_OPLOCK_LEVEL_II:
+		name = "level II";
+		break;
+	case SMB2_OPLOCK_LEVEL_NONE:
+		name = "none";
+		break;
+	default:
+		name = "unknown";
+		break_info.failures++;
+	}
+	printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
+
+	break_info.br.in.file.handle	= *handle;
+	break_info.br.in.oplock_level	= level;
+	break_info.br.in.reserved	= 0;
+	break_info.br.in.reserved2	= 0;
+
+	req = smb2_break_send(tree, &break_info.br);
+	req->async.fn = torture_oplock_break_callback;
+	req->async.private_data = NULL;
+	return true;
+}
+
+/*
+  A handler function for oplock break notifications. Send a break to none
+  request.
+*/
+static bool torture_oplock_handler_ack_to_none(struct smb2_transport *transport,
+					       const struct smb2_handle *handle,
+					       uint8_t level,
+					       void *private_data)
+{
+	struct smb2_tree *tree = private_data;
+	struct smb2_request *req;
+
+	break_info.handle = *handle;
+	break_info.level = level;
+	break_info.count++;
+
+	printf("Acking to none in oplock handler\n");
+
+	ZERO_STRUCT(break_info.br);
+	break_info.br.in.file.handle    = *handle;
+	break_info.br.in.oplock_level   = SMB2_OPLOCK_LEVEL_NONE;
+	break_info.br.in.reserved       = 0;
+	break_info.br.in.reserved2      = 0;
+
+	req = smb2_break_send(tree, &break_info.br);
+	req->async.fn = torture_oplock_break_callback;
+	req->async.private_data = NULL;
+
+	return true;
+}
+
+/*
+  A handler function for oplock break notifications. Break from level II to
+  none.  SMB2 requires that the client does not send an oplock break request to
+  the server in this case.
+*/
+static bool torture_oplock_handler_level2_to_none(
+					       struct smb2_transport *transport,
+					       const struct smb2_handle *handle,
+					       uint8_t level,
+					       void *private_data)
+{
+	struct smb2_tree *tree = private_data;
+
+	break_info.handle = *handle;
+	break_info.level = level;
+	break_info.count++;
+
+	printf("Break from level II to none in oplock handler\n");
+
+	return true;
+}
+
+/* A handler function for oplock break notifications.  This should be used when
+ * test expects two break notifications, first to level II, then to none. */
+static bool torture_oplock_handler_two_notifications(
+					struct smb2_transport *transport,
+					const struct smb2_handle *handle,
+					uint8_t level,
+					void *private_data)
+{
+	struct smb2_tree *tree = private_data;
+	const char *name;
+	struct smb2_request *req;
+	ZERO_STRUCT(break_info.br);
+
+	break_info.handle	= *handle;
+	break_info.level	= level;
+	break_info.count++;
+
+	switch (level) {
+	case SMB2_OPLOCK_LEVEL_II:
+		name = "level II";
+		break;
+	case SMB2_OPLOCK_LEVEL_NONE:
+		name = "none";
+		break;
+	default:
+		name = "unknown";
+		break_info.failures++;
+	}
+	printf("Breaking to %s [0x%02X] in oplock handler\n", name, level);
+
+	if (level == SMB2_OPLOCK_LEVEL_NONE)
+		return true;
+
+	break_info.br.in.file.handle	= *handle;
+	break_info.br.in.oplock_level	= level;
+	break_info.br.in.reserved	= 0;
+	break_info.br.in.reserved2	= 0;
+
+	req = smb2_break_send(tree, &break_info.br);
+	req->async.fn = torture_oplock_break_callback;
+	req->async.private_data = NULL;
+	return true;
+}
+static void torture_oplock_handler_close_recv(struct smb2_request *req)
+{
+	if (!smb2_request_receive(req)) {
+		printf("close failed in oplock_handler_close\n");
+		break_info.failures++;
+	}
+}
+
+/*
+  a handler function for oplock break requests - close the file
+*/
+static bool torture_oplock_handler_close(struct smb2_transport *transport,
+					 const struct smb2_handle *handle,
+					 uint8_t level,
+					 void *private_data)
+{
+	struct smb2_close io;
+	struct smb2_tree *tree = private_data;
+	struct smb2_request *req;
+
+	break_info.handle = *handle;
+	break_info.level = level;
+	break_info.count++;
+
+	ZERO_STRUCT(io);
+	io.in.file.handle       = *handle;
+	io.in.flags	     = RAW_CLOSE_SMB2;
+	req = smb2_close_send(tree, &io);
+	if (req == NULL) {
+		printf("failed to send close in oplock_handler_close\n");
+		return false;
+	}
+
+	req->async.fn = torture_oplock_handler_close_recv;
+	req->async.private_data = NULL;
+
+	return true;
+}
+
+/*
+  a handler function for oplock break requests. Let it timeout
+*/
+static bool torture_oplock_handler_timeout(struct smb2_transport *transport,
+					   const struct smb2_handle *handle,
+					   uint8_t level,
+					   void *private_data)
+{
+	break_info.handle = *handle;
+	break_info.level = level;
+	break_info.count++;
+
+	printf("Let oplock break timeout\n");
+	return true;
+}
+
+static bool open_smb2_connection_no_level2_oplocks(struct torture_context *tctx,
+						   struct smb2_tree **tree)
+{
+	NTSTATUS status;
+	const char *host = torture_setting_string(tctx, "host", NULL);
+	const char *share = torture_setting_string(tctx, "share", NULL);
+	struct cli_credentials *credentials = cmdline_credentials;
+	struct smbcli_options options;
+
+	lp_smbcli_options(tctx->lp_ctx, &options);
+	options.use_level2_oplocks = false;
+
+	status = smb2_connect(tctx, host,
+			      lp_smb_ports(tctx->lp_ctx), share,
+			      lp_resolve_context(tctx->lp_ctx),
+			      credentials, tree, tctx->ev, &options,
+			      lp_socket_options(tctx->lp_ctx),
+			      lp_gensec_settings(tctx, tctx->lp_ctx));
+	if (!NT_STATUS_IS_OK(status)) {
+		torture_comment(tctx, "Failed to connect to SMB2 share "
+				"\\\\%s\\%s - %s\n", host, share,
+				nt_errstr(status));
+		return false;
+	}
+	return true;
+}
+
+/*
+   Timer handler function notifies the registering function that time is up
+*/
+static void timeout_cb(struct tevent_context *ev,
+		       struct tevent_timer *te,
+		       struct timeval current_time,
+		       void *private_data)
+{
+	bool *timesup = (bool *)private_data;
+	*timesup = true;
+	return;
+}
+
+/*
+   Wait a short period of time to receive a single oplock break request
+*/
+static void torture_wait_for_oplock_break(struct torture_context *tctx)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+	struct tevent_timer *te = NULL;
+	struct timeval ne;
+	bool timesup = false;
+	int old_count = break_info.count;
+
+	/* Wait .1 seconds for an oplock break */
+	ne = tevent_timeval_current_ofs(0, 100000);
+
+	if ((te = event_add_timed(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup))
+	    == NULL)
+	{
+		torture_comment(tctx, "Failed to wait for an oplock break. "
+				      "test results may not be accurate.");
+		goto done;
+	}
+
+	while (!timesup && break_info.count < old_count + 1) {
+		if (event_loop_once(tctx->ev) != 0) {
+			torture_comment(tctx, "Failed to wait for an oplock "
+					      "break. test results may not be "
+					      "accurate.");
+			goto done;
+		}
+	}
+
+done:
+	/* We don't know if the timed event fired and was freed, we received
+	 * our oplock break, or some other event triggered the loop.  Thus,
+	 * we create a tmp_ctx to be able to safely free/remove the timed
+	 * event in all 3 cases. */
+	talloc_free(tmp_ctx);
+
+	return;
+}
+
+static bool test_smb2_oplock_exclusive1(struct torture_context *tctx,
+					struct smb2_tree *tree1,
+					struct smb2_tree *tree2)
+{
+	const char *fname = BASEDIR "\\test_exclusive1.dat";
+	NTSTATUS status;
+	bool ret = true;
+	union smb_open io;
+	union smb_unlink unl;
+	struct smb2_handle h1;
+	struct smb2_handle h;
+
+	status = torture_smb2_testdir(tree1, BASEDIR, &h);
+	torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+	/* cleanup */
+	smb2_util_unlink(tree1, fname);
+
+	tree1->session->transport->oplock.handler = torture_oplock_handler;
+	tree1->session->transport->oplock.private_data = tree1;
+
+	/*
+	  base ntcreatex parms
+	*/
+	ZERO_STRUCT(io.smb2);
+	io.generic.level = RAW_OPEN_SMB2;
+	io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+	io.smb2.in.alloc_size = 0;
+	io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+	io.smb2.in.create_options = 0;
+	io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+	io.smb2.in.security_flags = 0;
+	io.smb2.in.fname = fname;
+
+	torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive "
+			"oplock (share mode: none)\n");
+	ZERO_STRUCT(break_info);
+	io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+	status = smb2_create(tree1, tctx, &(io.smb2));
+	torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+	h1 = io.smb2.out.file.handle;
+	CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+	torture_comment(tctx, "a 2nd open should not cause a break\n");
+	status = smb2_create(tree2, tctx, &(io.smb2));
+	torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+				      "Incorrect status");
+	torture_wait_for_oplock_break(tctx);
+	CHECK_VAL(break_info.count, 0);
+	CHECK_VAL(break_info.failures, 0);
+
+	torture_comment(tctx, "unlink it - should also be no break\n");
+	unl.unlink.in.pattern = fname;
+	unl.unlink.in.attrib = 0;
+	status = smb2_util_unlink(tree2, fname);
+	torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+				      "Incorrect status");
+	torture_wait_for_oplock_break(tctx);
+	CHECK_VAL(break_info.count, 0);
+	CHECK_VAL(break_info.failures, 0);
+
+	smb2_util_close(tree1, h1);
+	smb2_util_close(tree1, h);
+
+	smb2_deltree(tree1, BASEDIR);
+	return ret;
+}
+
+static bool test_smb2_oplock_exclusive2(struct torture_context *tctx,
+					struct smb2_tree *tree1,
+					struct smb2_tree *tree2)
+{
+	const char *fname = BASEDIR "\\test_exclusive2.dat";
+	NTSTATUS status;
+	bool ret = true;
+	union smb_open io;
+	union smb_unlink unl;
+	struct smb2_handle h, h1, h2;
+
+	status = torture_smb2_testdir(tree1, BASEDIR, &h);
+	torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+	/* cleanup */
+	smb2_util_unlink(tree1, fname);
+
+	tree1->session->transport->oplock.handler = torture_oplock_handler;
+	tree1->session->transport->oplock.private_data = tree1;
+
+	/*
+	  base ntcreatex parms
+	*/
+	ZERO_STRUCT(io.smb2);
+	io.generic.level = RAW_OPEN_SMB2;
+	io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+	io.smb2.in.alloc_size = 0;
+	io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+	io.smb2.in.create_options = 0;
+	io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+	io.smb2.in.security_flags = 0;
+	io.smb2.in.fname = fname;
+
+	torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive "
+			"oplock (share mode: all)\n");
+	ZERO_STRUCT(break_info);
+	io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+		NTCREATEX_SHARE_ACCESS_WRITE|
+		NTCREATEX_SHARE_ACCESS_DELETE;
+	io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+	status = smb2_create(tree1, tctx, &(io.smb2));
+	torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+	h1 = io.smb2.out.file.handle;
+	CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+	torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
+	status = smb2_create(tree2, tctx, &(io.smb2));
+	torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+	h2 = io.smb2.out.file.handle;
+	torture_wait_for_oplock_break(tctx);
+	CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+	CHECK_VAL(break_info.count, 1);
+	CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+	CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+	CHECK_VAL(break_info.failures, 0);
+	ZERO_STRUCT(break_info);
+
+	/* now we have 2 level II oplocks... */
+	torture_comment(tctx, "try to unlink it - should cause a break\n");


-- 
Samba Shared Repository


More information about the samba-cvs mailing list