[SCM] Samba Shared Repository - branch v4-0-test updated - release-4-0-0alpha2-1208-g18e27ae

Stefan Metzmacher metze at samba.org
Wed Mar 5 12:22:54 GMT 2008


The branch, v4-0-test has been updated
       via  18e27aef7be9b21f65f72ab4c656778ce0c23953 (commit)
       via  c459885898c9912df1ae5afff4fef2ff809dc15e (commit)
       via  a5476ee41c140123db160b2e36c8c7084619a738 (commit)
       via  bfb0888578677856b2b6b72471f542d0d5d7b838 (commit)
       via  21772fa33d772a9df6ff04a0ed1b0d8f4f533295 (commit)
       via  2b8934e4ab2dd9673928a6c9a291aedac1ebaa95 (commit)
      from  b0ecd8f8d2c1ebf23957921f4852e90b556812fc (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v4-0-test


- Log -----------------------------------------------------------------
commit 18e27aef7be9b21f65f72ab4c656778ce0c23953
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Mar 4 14:24:27 2008 +0100

    selftest: use the same oplocktimeout for smbtorture as for smbd
    
    metze

commit c459885898c9912df1ae5afff4fef2ff809dc15e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Mar 4 14:08:32 2008 +0100

    RAW-OPLOCK: add BATCH22 and test the behavior of oplock break timeouts
    
    metze

commit a5476ee41c140123db160b2e36c8c7084619a738
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Mar 4 12:15:32 2008 +0100

    RAW-OPLOCK: add BATCH21: a self write with an oplock doesn't break it
    
    metze

commit bfb0888578677856b2b6b72471f542d0d5d7b838
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Mar 4 14:16:17 2008 +0100

    pvfs_oplock: auto release oplocks after a timeout
    
    Remember that we sent an oplock break to
    a client and don't resend. If the filesystem
    layer tries to send a new break and the client
    has not released after a former oplock break
    after the timeout interval, we need to auto release
    the oplock.
    
    metze

commit 21772fa33d772a9df6ff04a0ed1b0d8f4f533295
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Mar 4 14:11:53 2008 +0100

    pvfs_oplock: only a break level2 oplocks...
    
    It seems that I've tested this in the wrong way before.
    
    metze

commit 2b8934e4ab2dd9673928a6c9a291aedac1ebaa95
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Mar 4 14:10:13 2008 +0100

    pvfs_oplock: move pvfs_oplock_release() parts into a helper function
    
    metze

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

Summary of changes:
 source/ntvfs/posix/pvfs_oplock.c |  178 ++++++++++++++++++++++++------------
 source/selftest/samba4_tests.sh  |    2 +-
 source/torture/raw/oplock.c      |  188 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 307 insertions(+), 61 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/ntvfs/posix/pvfs_oplock.c b/source/ntvfs/posix/pvfs_oplock.c
index cf30ddb..dfa3697 100644
--- a/source/ntvfs/posix/pvfs_oplock.c
+++ b/source/ntvfs/posix/pvfs_oplock.c
@@ -22,6 +22,7 @@
 #include "includes.h"
 #include "lib/messaging/messaging.h"
 #include "lib/messaging/irpc.h"
+#include "system/time.h"
 #include "vfs_posix.h"
 
 
@@ -29,9 +30,63 @@ struct pvfs_oplock {
 	struct pvfs_file_handle *handle;
 	struct pvfs_file *file;
 	uint32_t level;
+	struct timeval break_to_level_II;
+	struct timeval break_to_none;
 	struct messaging_context *msg_ctx;
 };
 
+static NTSTATUS pvfs_oplock_release_internal(struct pvfs_file_handle *h,
+					     uint8_t oplock_break)
+{
+	struct odb_lock *olck;
+	NTSTATUS status;
+
+	if (h->fd == -1) {
+		return NT_STATUS_FILE_IS_A_DIRECTORY;
+	}
+
+	if (!h->have_opendb_entry) {
+		return NT_STATUS_FOOBAR;
+	}
+
+	if (!h->oplock) {
+		return NT_STATUS_FOOBAR;
+	}
+
+	olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
+	if (olck == NULL) {
+		DEBUG(0,("Unable to lock opendb for oplock update\n"));
+		return NT_STATUS_FOOBAR;
+	}
+
+	if (oplock_break == OPLOCK_BREAK_TO_NONE) {
+		h->oplock->level = OPLOCK_NONE;
+	} else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) {
+		h->oplock->level = OPLOCK_LEVEL_II;
+	} else {
+		/* fallback to level II in case of a invalid value */
+		DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break));
+		h->oplock->level = OPLOCK_LEVEL_II;
+	}
+	status = odb_update_oplock(olck, h, h->oplock->level);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0,("Unable to update oplock level for '%s' - %s\n",
+			 h->name->full_name, nt_errstr(status)));
+		talloc_free(olck);
+		return status;
+	}
+
+	talloc_free(olck);
+
+	/* after a break to none, we no longer have an oplock attached */
+	if (h->oplock->level == OPLOCK_NONE) {
+		talloc_free(h->oplock);
+		h->oplock = NULL;
+	}
+
+	return NT_STATUS_OK;
+}
+
 /*
   receive oplock breaks and forward them to the client
 */
@@ -41,13 +96,65 @@ static void pvfs_oplock_break(struct pvfs_oplock *opl, uint8_t level)
 	struct pvfs_file *f = opl->file;
 	struct pvfs_file_handle *h = opl->handle;
 	struct pvfs_state *pvfs = h->pvfs;
+	struct timeval cur = timeval_current();
+	struct timeval *last = NULL;
+	struct timeval end;
+
+	switch (level) {
+	case OPLOCK_BREAK_TO_LEVEL_II:
+		last = &opl->break_to_level_II;
+		break;
+	case OPLOCK_BREAK_TO_NONE:
+		last = &opl->break_to_none;
+		break;
+	}
+
+	if (!last) {
+		DEBUG(0,("%s: got unexpected level[0x%02X]\n",
+			__FUNCTION__, level));
+		return;
+	}
+
+	if (timeval_is_zero(last)) {
+		/*
+		 * this is the first break we for this level
+		 * remember the time
+		 */
+		*last = cur;
 
-	DEBUG(10,("pvfs_oplock_break: sending oplock break level %d for '%s' %p\n",
-		level, h->name->original_name, h));
-	status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level);
+		DEBUG(0,("%s: sending oplock break level %d for '%s' %p\n",
+			__FUNCTION__, level, h->name->original_name, h));
+		status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(0,("%s: sending oplock break failed: %s\n",
+				__FUNCTION__, nt_errstr(status)));
+		}
+		return;
+	}
+
+	end = timeval_add(last, pvfs->oplock_break_timeout, 0);
+
+	if (timeval_compare(&cur, &end) < 0) {
+		/*
+		 * If it's not expired just ignore the break
+		 * as we already sent the break request to the client
+		 */
+		DEBUG(0,("%s: do not resend oplock break level %d for '%s' %p\n",
+			__FUNCTION__, level, h->name->original_name, h));
+		return;
+	}
+
+	/*
+	 * If the client did not send a release within the
+	 * oplock break timeout time frame we auto release
+	 * the oplock
+	 */
+	DEBUG(0,("%s: auto release oplock level %d for '%s' %p\n",
+		__FUNCTION__, level, h->name->original_name, h));
+	status = pvfs_oplock_release_internal(h, level);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0,("pvfs_oplock_break: sending oplock break failed: %s\n",
-			nt_errstr(status)));
+		DEBUG(0,("%s: failed to auto release the oplock[0x%02X]: %s\n",
+			__FUNCTION__, level, nt_errstr(status)));
 	}
 }
 
@@ -113,7 +220,7 @@ NTSTATUS pvfs_setup_oplock(struct pvfs_file *f, uint32_t oplock_granted)
 		return NT_STATUS_OK;
 	}
 
-	opl = talloc(f->handle, struct pvfs_oplock);
+	opl = talloc_zero(f->handle, struct pvfs_oplock);
 	NT_STATUS_HAVE_NO_MEMORY(opl);
 
 	opl->handle	= f->handle;
@@ -140,8 +247,6 @@ NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs,
 {
 	struct pvfs_state *pvfs = ntvfs->private_data;
 	struct pvfs_file *f;
-	struct pvfs_file_handle *h;
-	struct odb_lock *olck;
 	uint8_t oplock_break;
 	NTSTATUS status;
 
@@ -150,52 +255,15 @@ NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs,
 		return NT_STATUS_INVALID_HANDLE;
 	}
 
-	h = f->handle;
-
-	if (h->fd == -1) {
-		return NT_STATUS_FILE_IS_A_DIRECTORY;
-	}
-
-	if (!h->have_opendb_entry) {
-		return NT_STATUS_FOOBAR;
-	}
-
-	if (!h->oplock) {
-		return NT_STATUS_FOOBAR;
-	}
-
-	olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
-	if (olck == NULL) {
-		DEBUG(0,("Unable to lock opendb for oplock update\n"));
-		return NT_STATUS_FOOBAR;
-	}
-
 	oplock_break = (lck->lockx.in.mode >> 8) & 0xFF;
-	if (oplock_break == OPLOCK_BREAK_TO_NONE) {
-		h->oplock->level = OPLOCK_NONE;
-	} else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) {
-		h->oplock->level = OPLOCK_LEVEL_II;
-	} else {
-		/* fallback to level II in case of a invalid value */
-		DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break));
-		h->oplock->level = OPLOCK_LEVEL_II;
-	}
-	status = odb_update_oplock(olck, h, h->oplock->level);
+
+	status = pvfs_oplock_release_internal(f->handle, oplock_break);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0,("Unable to update oplock level for '%s' - %s\n",
-			 h->name->full_name, nt_errstr(status)));
-		talloc_free(olck);
+		DEBUG(0,("%s: failed to release the oplock[0x%02X]: %s\n",
+			__FUNCTION__, oplock_break, nt_errstr(status)));
 		return status;
 	}
 
-	talloc_free(olck);
-
-	/* after a break to none, we no longer have an oplock attached */
-	if (h->oplock->level == OPLOCK_NONE) {
-		talloc_free(h->oplock);
-		h->oplock = NULL;
-	}
-
 	return NT_STATUS_OK;
 }
 
@@ -205,7 +273,7 @@ NTSTATUS pvfs_break_level2_oplocks(struct pvfs_file *f)
 	struct odb_lock *olck;
 	NTSTATUS status;
 
-	if (h->oplock && h->oplock->level == OPLOCK_EXCLUSIVE) {
+	if (h->oplock && h->oplock->level != OPLOCK_LEVEL_II) {
 		return NT_STATUS_OK;
 	}
 
@@ -215,16 +283,6 @@ NTSTATUS pvfs_break_level2_oplocks(struct pvfs_file *f)
 		return NT_STATUS_FOOBAR;
 	}
 
-	if (h->oplock && h->oplock->level == OPLOCK_BATCH) {
-		status = odb_update_oplock(olck, h, OPLOCK_LEVEL_II);
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(0,("Unable to update oplock level for '%s' - %s\n",
-				 h->name->full_name, nt_errstr(status)));
-			talloc_free(olck);
-			return status;
-		}
-	}
-
 	status = odb_break_oplocks(olck);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0,("Unable to break level2 oplocks to none for '%s' - %s\n",
diff --git a/source/selftest/samba4_tests.sh b/source/selftest/samba4_tests.sh
index bea4173..8102095 100755
--- a/source/selftest/samba4_tests.sh
+++ b/source/selftest/samba4_tests.sh
@@ -217,7 +217,7 @@ done
 plantest "rpc.echo on ncacn_np over smb2" dc $smb4torture ncacn_np:"\$SERVER[smb2]" -U"\$USERNAME"%"\$PASSWORD" -W \$DOMAIN RPC-ECHO "$*"
 
 # Tests against the NTVFS POSIX backend
-NTVFSARGS="--option=torture:sharedelay=100000"
+NTVFSARGS="--option=torture:sharedelay=100000 --option=torture:oplocktimeout=3"
 smb2=`$smb4torture --list | grep "^SMB2-" | xargs`
 raw=`$smb4torture --list | grep "^RAW-" | xargs`
 base=`$smb4torture --list | grep "^BASE-" | xargs`
diff --git a/source/torture/raw/oplock.c b/source/torture/raw/oplock.c
index 7ac88c0..8a7489c 100644
--- a/source/torture/raw/oplock.c
+++ b/source/torture/raw/oplock.c
@@ -32,6 +32,13 @@
 		ret = false; \
 	}} while (0)
 
+#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", \
@@ -92,6 +99,21 @@ static bool oplock_handler_ack_to_none(struct smbcli_transport *transport,
 	return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
 }
 
+/*
+  a handler function for oplock break requests. Let it timeout
+*/
+static bool oplock_handler_timeout(struct smbcli_transport *transport,
+				   uint16_t tid, uint16_t fnum,
+				   uint8_t level, void *private)
+{
+	break_info.fnum = fnum;
+	break_info.level = level;
+	break_info.count++;
+
+	printf("Let oplock break timeout\n");
+	return true;
+}
+
 static void oplock_handler_close_recv(struct smbcli_request *req)
 {
 	NTSTATUS status;
@@ -2204,6 +2226,170 @@ done:
 	return ret;
 }
 
+static bool test_raw_oplock_batch21(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+	const char *fname = BASEDIR "\\test_batch21.dat";
+	NTSTATUS status;
+	bool ret = true;
+	union smb_open io;
+	struct smb_echo e;
+	uint16_t fnum=0;
+	char c = 0;
+	ssize_t wr;
+
+	if (!torture_setup_dir(cli1, BASEDIR)) {
+		return false;
+	}
+
+	/* cleanup */
+	smbcli_unlink(cli1->tree, fname);
+
+	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+	/*
+	  base ntcreatex parms
+	*/
+	io.generic.level = RAW_OPEN_NTCREATEX;
+	io.ntcreatex.in.root_fid = 0;
+	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+	io.ntcreatex.in.alloc_size = 0;
+	io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+	io.ntcreatex.in.create_options = 0;
+	io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+	io.ntcreatex.in.security_flags = 0;
+	io.ntcreatex.in.fname = fname;
+
+	/*
+	  with a batch oplock we get a break
+	*/
+	torture_comment(tctx, "open with batch oplock\n");
+	ZERO_STRUCT(break_info);
+	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+		NTCREATEX_FLAGS_REQUEST_OPLOCK |
+		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+	status = smb_raw_open(cli1->tree, tctx, &io);
+	CHECK_STATUS(tctx, status, NT_STATUS_OK);
+	fnum = io.ntcreatex.out.file.fnum;
+	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+	torture_comment(tctx, "writing should not generate a break\n");
+	wr = smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
+	CHECK_VAL(wr, 1);
+	CHECK_STATUS(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_OK);
+
+	ZERO_STRUCT(e);
+	e.in.repeat_count = 1;
+	status = smb_raw_echo(cli1->transport, &e);
+	CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+	CHECK_VAL(break_info.count, 0);
+
+	smbcli_close(cli1->tree, fnum);
+
+done:
+	smb_raw_exit(cli1->session);
+	smb_raw_exit(cli2->session);
+	smbcli_deltree(cli1->tree, BASEDIR);
+	return ret;
+}
+
+static bool test_raw_oplock_batch22(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+	const char *fname = BASEDIR "\\test_batch22.dat";
+	NTSTATUS status;
+	bool ret = true;
+	union smb_open io;
+	union smb_unlink unl;
+	uint16_t fnum=0, fnum2=0;
+	char c = 0;
+	struct timeval tv;
+	int timeout = torture_setting_int(tctx, "oplocktimeout", 30);
+	int te;
+	ssize_t wr;
+
+	if (torture_setting_bool(tctx, "samba3", false)) {
+		torture_skip(tctx, "BACHT22 disabled against samba3\n");
+	}
+
+	if (!torture_setup_dir(cli1, BASEDIR)) {
+		return false;
+	}
+
+	/* cleanup */
+	smbcli_unlink(cli1->tree, fname);
+
+	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+	/*
+	  base ntcreatex parms
+	*/
+	io.generic.level = RAW_OPEN_NTCREATEX;
+	io.ntcreatex.in.root_fid = 0;
+	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+	io.ntcreatex.in.alloc_size = 0;
+	io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+	io.ntcreatex.in.create_options = 0;
+	io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+	io.ntcreatex.in.security_flags = 0;
+	io.ntcreatex.in.fname = fname;
+
+	/*
+	  with a batch oplock we get a break
+	*/
+	torture_comment(tctx, "open with batch oplock\n");
+	ZERO_STRUCT(break_info);
+	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+		NTCREATEX_FLAGS_REQUEST_OPLOCK |
+		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+		NTCREATEX_SHARE_ACCESS_WRITE|
+		NTCREATEX_SHARE_ACCESS_DELETE;
+	status = smb_raw_open(cli1->tree, tctx, &io);
+	CHECK_STATUS(tctx, status, NT_STATUS_OK);
+	fnum = io.ntcreatex.out.file.fnum;
+	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+	torture_comment(tctx, "a 2nd open shoud not succeed after the oplock break timeout\n");
+	tv = timeval_current();
+	smbcli_oplock_handler(cli1->transport, oplock_handler_timeout, cli1->tree);
+	status = smb_raw_open(cli1->tree, tctx, &io);
+	CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+	te = (int)timeval_elapsed(&tv);
+	CHECK_RANGE(te, timeout - 1, timeout + 15);
+
+	CHECK_VAL(break_info.count, 1);
+	CHECK_VAL(break_info.fnum, fnum);
+	CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+	CHECK_VAL(break_info.failures, 0);
+	ZERO_STRUCT(break_info);
+
+	torture_comment(tctx, "a 2nd open shoud succeed after the oplock release without break\n");
+	tv = timeval_current();
+	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+	status = smb_raw_open(cli1->tree, tctx, &io);
+	CHECK_STATUS(tctx, status, NT_STATUS_OK);
+	CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+	te = (int)timeval_elapsed(&tv);
+	/* it should come in without delay */
+	CHECK_RANGE(te+1, 0, timeout);
+	fnum2 = io.ntcreatex.out.file.fnum;
+
+	CHECK_VAL(break_info.count, 0);
+
+	smbcli_close(cli1->tree, fnum);
+	smbcli_close(cli1->tree, fnum2);
+
+done:
+	smb_raw_exit(cli1->session);
+	smb_raw_exit(cli2->session);
+	smbcli_deltree(cli1->tree, BASEDIR);
+	return ret;
+}
+
 /* 
    basic testing of oplocks
 */
@@ -2237,6 +2423,8 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx)
 	torture_suite_add_2smb_test(suite, "BATCH18", test_raw_oplock_batch18);
 	torture_suite_add_2smb_test(suite, "BATCH19", test_raw_oplock_batch19);
 	torture_suite_add_2smb_test(suite, "BATCH20", test_raw_oplock_batch20);
+	torture_suite_add_2smb_test(suite, "BATCH21", test_raw_oplock_batch21);
+	torture_suite_add_2smb_test(suite, "BATCH22", test_raw_oplock_batch22);
 
 	return suite;
 }


-- 
Samba Shared Repository


More information about the samba-cvs mailing list