[SCM] Samba Shared Repository - branch master updated

Steven Danneman sdanneman at samba.org
Wed Dec 2 18:28:51 MST 2009


The branch, master has been updated
       via  48358b3... s4/torture: add multiple lock cancel test
       via  ad9c5a7... s4/torture: add addition multiple lock tests
       via  dfbb92e... s4/torture: fix build warnings by removing unecessary const
       via  438b7c4... s4/torture: Add target functionality parameters to SMBv1 BRL tests
      from  9a3d9ab... s3-selftest: run LOCAL-NDR when running make selftest.

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


- Log -----------------------------------------------------------------
commit 48358b3eaa425d8fbfec7bfd8ccf56860b5a1ba0
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Wed Nov 25 17:39:42 2009 -0800

    s4/torture: add multiple lock cancel test
    
    See what happens when we have multiple outstanding lock requests and
    we try to cancel both of them within a single LockingAndX.
    
    On Windows, it seems only the first lock in the array is cancelled,
    and the second is left pending.  Though, this behavior goes against
    the MS-CIFS spec.

commit ad9c5a7b881bd28f408a178766a00098bab19157
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Mon Nov 30 17:05:27 2009 -0800

    s4/torture: add addition multiple lock tests
    
    * test that 2 locks in a single LockAndX are transactional
    * test that 1 unlock and 1 lock in a single LockAndX are not
      transactional
    * test that SMB2 doesn't like mixed lock/unlock in a single
      PDU

commit dfbb92e2a1c3478c9b1263adcc4818afe2acd6f7
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Tue Nov 24 18:38:46 2009 -0800

    s4/torture: fix build warnings by removing unecessary const

commit 438b7c41aecaad55f03d2f19a0f33bb57decefa9
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Tue Nov 24 16:58:25 2009 -0800

    s4/torture: Add target functionality parameters to SMBv1 BRL tests
    
    Abstract the server requirements to pass some BRL tests.
    
    * The new default for >64bit lock tests, is that the server should
      return STATUS_INVALID_LOCK_RANGE.
    * Add parameter for targets that don't implement DENY_DOS

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

Summary of changes:
 source4/torture/raw/lock.c   |  195 ++++++++++++++++++++++++++++++++--
 source4/torture/smb2/lock.c  |  241 +++++++++++++++++++++++++++++++++++++-----
 source4/torture/smbtorture.c |    7 +-
 source4/torture/smbtorture.h |    9 ++
 4 files changed, 413 insertions(+), 39 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c
index 610cac9..f36d492 100644
--- a/source4/torture/raw/lock.c
+++ b/source4/torture/raw/lock.c
@@ -69,6 +69,19 @@
 	}} while (0)
 #define BASEDIR "\\testlock"
 
+#define TARGET_SUPPORTS_SMBLOCK(_tctx) \
+    (torture_setting_bool(_tctx, "smblock_pdu_support", true))
+#define TARGET_SUPPORTS_OPENX_DENY_DOS(_tctx) \
+    (torture_setting_bool(_tctx, "openx_deny_dos_support", true))
+#define TARGET_SUPPORTS_INVALID_LOCK_RANGE(_tctx) \
+    (torture_setting_bool(_tctx, "invalid_lock_range_support", true))
+#define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
+#define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
+#define TARGET_IS_WINDOWS(_tctx) ((torture_setting_bool(_tctx, "w2k8", false)) || \
+				  (torture_setting_bool(_tctx, "win7", false)))
+#define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
+#define TARGET_IS_SAMBA4(_tctx) (torture_setting_bool(_tctx, "samba4", false))
+
 /*
   test SMBlock and SMBunlock ops
 */
@@ -80,6 +93,9 @@ static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
 	int fnum;
 	const char *fname = BASEDIR "\\test.txt";
 
+	if (!TARGET_SUPPORTS_SMBLOCK(tctx))
+		torture_skip(tctx, "Target does not support the SMBlock PDU");
+
 	if (!torture_setup_dir(cli, BASEDIR)) {
 		return false;
 	}
@@ -361,7 +377,7 @@ static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
 	lock[0].pid++;
 	lock[0].count = 2;
 	status = smb_raw_lock(cli->tree, &io);
-	if (TARGET_IS_WIN7(tctx) || TARGET_IS_SAMBA4(tctx))
+	if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(tctx))
 		CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
 	else
 		CHECK_STATUS(status, NT_STATUS_OK);
@@ -484,7 +500,7 @@ static bool test_async(struct torture_context *tctx,
 	int fnum;
 	const char *fname = BASEDIR "\\test.txt";
 	time_t t;
-	struct smbcli_request *req;
+	struct smbcli_request *req, *req2;
 	struct smbcli_session_options options;
 
 	if (!torture_setup_dir(cli, BASEDIR)) {
@@ -510,6 +526,9 @@ static bool test_async(struct torture_context *tctx,
 	lock[0].pid = cli->session->pid;
 	lock[0].offset = 100;
 	lock[0].count = 10;
+	lock[1].pid = cli->session->pid;
+	lock[1].offset = 110;
+	lock[1].count = 10;
 	io.lockx.in.locks = &lock[0];
 	status = smb_raw_lock(cli->tree, &io);
 	CHECK_STATUS(status, NT_STATUS_OK);
@@ -552,13 +571,97 @@ static bool test_async(struct torture_context *tctx,
 	torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
 		       "lock cancel was not immediate (%s)\n", __location__));
 
+	/* MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
+	 * if the lock vector contains one entry. When given mutliple cancel
+	 * requests in a single PDU we expect the server to return an
+	 * error. Samba4 handles this correctly. Windows servers seem to
+	 * accept the request but only cancel the first lock.  Samba3
+	 * cancels both locks. */
+	torture_comment(tctx, "testing multiple cancel\n");
+
+	/* acquire second lock */
+	io.lockx.in.timeout = 0;
+	io.lockx.in.ulock_cnt = 0;
+	io.lockx.in.lock_cnt = 1;
+	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+	io.lockx.in.locks = &lock[1];
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* setup 2 timed locks */
+	t = time(NULL);
+	io.lockx.in.timeout = 10000;
+	io.lockx.in.lock_cnt = 1;
+	io.lockx.in.locks = &lock[0];
+	req = smb_raw_lock_send(cli->tree, &io);
+	torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+		       "Failed to setup timed lock (%s)\n", __location__));
+	io.lockx.in.locks = &lock[1];
+	req2 = smb_raw_lock_send(cli->tree, &io);
+	torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
+		       "Failed to setup timed lock (%s)\n", __location__));
+
+	/* try to cancel both locks in the same packet */
+	io.lockx.in.timeout = 0;
+	io.lockx.in.lock_cnt = 2;
+	io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
+	io.lockx.in.locks = lock;
+	status = smb_raw_lock(cli->tree, &io);
+	if (TARGET_IS_WINDOWS(tctx) || TARGET_IS_SAMBA3(tctx)) {
+		CHECK_STATUS(status, NT_STATUS_OK);
+
+		torture_warning(tctx, "Target server accepted a lock cancel "
+				      "request with multiple locks. This violates "
+				      "MS-CIFS 2.2.4.32.1.\n");
+
+		/* receive the failed lock requests */
+		status = smbcli_request_simple_recv(req);
+		CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+		torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
+			       "first lock was not cancelled immediately (%s)\n",
+			       __location__));
+
+		/* send cancel to second lock */
+		io.lockx.in.timeout = 0;
+		io.lockx.in.lock_cnt = 1;
+		io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK |
+				   LOCKING_ANDX_LARGE_FILES;
+		io.lockx.in.locks = &lock[1];
+		status = smb_raw_lock(cli->tree, &io);
+		if (TARGET_IS_SAMBA3(tctx)) {
+			/* Samba3 supports multiple cancels in a single PDU. */
+			CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,
+							   ERRcancelviolation));
+		} else {
+			CHECK_STATUS(status, NT_STATUS_OK);
+		}
+
+		status = smbcli_request_simple_recv(req2);
+		CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+		torture_assert(tctx,!(time(NULL) > t+2), talloc_asprintf(tctx,
+			       "second lock was not cancelled immediately (%s)\n",
+			       __location__));
+	} else {
+		CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
+	}
+
+	/* cleanup the second lock */
+	io.lockx.in.ulock_cnt = 1;
+	io.lockx.in.lock_cnt = 0;
+	io.lockx.in.locks = &lock[1];
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
 	torture_comment(tctx, "testing cancel by unlock\n");
 	io.lockx.in.ulock_cnt = 0;
 	io.lockx.in.lock_cnt = 1;
 	io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
 	io.lockx.in.timeout = 0;
+	io.lockx.in.locks = &lock[0];
 	status = smb_raw_lock(cli->tree, &io);
-	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
 
 	io.lockx.in.timeout = 5000;
 	req = smb_raw_lock_send(cli->tree, &io);
@@ -780,6 +883,7 @@ static bool test_errorcode(struct torture_context *tctx,
 	time_t start;
 	int t;
 	int delay;
+	uint16_t deny_mode = 0;
 
 	if (!torture_setup_dir(cli, BASEDIR)) {
 		return false;
@@ -796,14 +900,20 @@ static bool test_errorcode(struct torture_context *tctx,
 	 * the second with t > 0 (=1)
 	 */
 next_run:
-	/* 
-	 * use the DENY_DOS mode, that creates two fnum's of one low-level file handle,
-	 * this demonstrates that the cache is per fnum
+	/*
+	 * use the DENY_DOS mode, that creates two fnum's of one low-level
+	 * file handle, this demonstrates that the cache is per fnum, not
+	 * per file handle
 	 */
+	if (TARGET_SUPPORTS_OPENX_DENY_DOS(tctx))
+	    deny_mode = OPENX_MODE_DENY_DOS;
+	else
+	    deny_mode = OPENX_MODE_DENY_NONE;
+
 	op.openx.level = RAW_OPEN_OPENX;
 	op.openx.in.fname = fname;
 	op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
-	op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_DOS;
+	op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | deny_mode;
 	op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
 	op.openx.in.search_attrs = 0;
 	op.openx.in.file_attrs = 0;
@@ -1054,7 +1164,7 @@ next_run:
 	/* 
 	 * demonstrate the a successful lock in a different range, 
 	 * doesn't reset the cache, the failing lock on the 2nd handle
-	 * resets the resets the cache
+	 * resets the cache
 	 */
 	lock[0].offset = 120;
 	lock[0].count = 15;
@@ -1322,7 +1432,7 @@ struct double_lock_test {
 /**
  * Tests zero byte locks.
  */
-static const struct double_lock_test zero_byte_tests[] = {
+static struct double_lock_test zero_byte_tests[] = {
 	/* {pid, offset, count}, {pid, offset, count}, status */
 
 	/** First, takes a zero byte lock at offset 10. Then:
@@ -1729,6 +1839,73 @@ static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_sta
 	status = smb_raw_lock(cli->tree, &io);
 	CHECK_STATUS(status, NT_STATUS_OK);
 
+	/* Test3: Request 2 locks, second will contend.  What happens to the
+	 * first? */
+	torture_comment(tctx, "  request 2 locks, second one will contend. "
+	   "Expect both to fail.\n");
+
+	/* Lock the second range */
+	io.lockx.in.ulock_cnt = 0;
+	io.lockx.in.lock_cnt = 1;
+	io.lockx.in.locks = &lock2;
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Request both locks */
+	io.lockx.in.ulock_cnt = 0;
+	io.lockx.in.lock_cnt = 2;
+	io.lockx.in.locks = locks;
+
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+	/* First lock should be unlocked. */
+	io.lockx.in.ulock_cnt = 0;
+	io.lockx.in.lock_cnt = 1;
+	io.lockx.in.locks = &lock1;
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* cleanup */
+	io.lockx.in.ulock_cnt = 2;
+	io.lockx.in.lock_cnt = 0;
+	io.lockx.in.locks = locks;
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Test4: Request unlock and lock. The lock contends, is the unlock
+	 * then re-locked? */
+	torture_comment(tctx, "  request unlock and lock, second one will "
+	   "contend. Expect the unlock to succeed.\n");
+
+	/* Lock both ranges */
+	io.lockx.in.ulock_cnt = 0;
+	io.lockx.in.lock_cnt = 2;
+	io.lockx.in.locks = locks;
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Attempt to unlock the first range and lock the second */
+	io.lockx.in.ulock_cnt = 1;
+	io.lockx.in.lock_cnt = 1;
+	io.lockx.in.locks = locks;
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+	/* The first lock should've been unlocked */
+	io.lockx.in.ulock_cnt = 0;
+	io.lockx.in.lock_cnt = 1;
+	io.lockx.in.locks = &lock1;
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* cleanup */
+	io.lockx.in.ulock_cnt = 2;
+	io.lockx.in.lock_cnt = 0;
+	io.lockx.in.locks = locks;
+	status = smb_raw_lock(cli->tree, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
 done:
 	smbcli_close(cli->tree, fnum1);
 	smb_raw_exit(cli->session);
diff --git a/source4/torture/smb2/lock.c b/source4/torture/smb2/lock.c
index 95b825e..ba97a54 100644
--- a/source4/torture/smb2/lock.c
+++ b/source4/torture/smb2/lock.c
@@ -1702,7 +1702,6 @@ static bool test_multiple_unlock(struct torture_context *torture,
 	uint8_t buf[200];
 	struct smb2_lock lck;
 	struct smb2_lock_element el[2];
-	struct smb2_lock_element el0, el1;
 
 	const char *fname = BASEDIR "\\unlock_multiple.txt";
 
@@ -1723,41 +1722,37 @@ static bool test_multiple_unlock(struct torture_context *torture,
 	lck.in.lock_count	= 0x0002;
 	lck.in.lock_sequence	= 0x00000000;
 	lck.in.file.handle	= h;
-	el0.offset		= 0;
-	el0.length		= 10;
-	el0.reserved		= 0x00000000;
-	el1.offset		= 10;
-	el1.length		= 10;
-	el1.reserved		= 0x00000000;
-	el[0]			= el0;
-	el[1]			= el1;
+	el[0].offset		= 0;
+	el[0].length		= 10;
+	el[0].reserved		= 0x00000000;
+	el[1].offset		= 10;
+	el[1].length		= 10;
+	el[1].reserved		= 0x00000000;
 
 	/* Test1: Acquire second lock, but not first. */
 	torture_comment(torture, "  unlock 2 locks, first one not locked. "
 				 "Expect no locks unlocked. \n");
 
 	lck.in.lock_count	= 0x0001;
-	el1.flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+	el[1].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
 				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
-	lck.in.locks		= &el1;
+	lck.in.locks		= &el[1];
 	status = smb2_lock(tree, &lck);
 	CHECK_STATUS(status, NT_STATUS_OK);
 
 	/* Try to unlock both locks */
 	lck.in.lock_count	= 0x0002;
-	el0.flags		= SMB2_LOCK_FLAG_UNLOCK;
-	el1.flags		= SMB2_LOCK_FLAG_UNLOCK;
-	el[0]			= el0;
-	el[1]			= el1;
+	el[0].flags		= SMB2_LOCK_FLAG_UNLOCK;
+	el[1].flags		= SMB2_LOCK_FLAG_UNLOCK;
 	lck.in.locks		= el;
 	status = smb2_lock(tree, &lck);
 	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
 
 	/* Second lock should not be unlocked. */
 	lck.in.lock_count	= 0x0001;
-	el1.flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+	el[1].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
 				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
-	lck.in.locks		= &el1;
+	lck.in.locks		= &el[1];
 	status = smb2_lock(tree, &lck);
 	if (TARGET_IS_W2K8(torture)) {
 		CHECK_STATUS(status, NT_STATUS_OK);
@@ -1770,8 +1765,8 @@ static bool test_multiple_unlock(struct torture_context *torture,
 
 	/* cleanup */
 	lck.in.lock_count	= 0x0001;
-	el1.flags		= SMB2_LOCK_FLAG_UNLOCK;
-	lck.in.locks		= &el1;
+	el[1].flags		= SMB2_LOCK_FLAG_UNLOCK;
+	lck.in.locks		= &el[1];
 	status = smb2_lock(tree, &lck);
 	CHECK_STATUS(status, NT_STATUS_OK);
 
@@ -1780,37 +1775,225 @@ static bool test_multiple_unlock(struct torture_context *torture,
 				 "Expect first lock unlocked.\n");
 
 	lck.in.lock_count	= 0x0001;
-	el0.flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+	el[0].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
 				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
-	lck.in.locks		= &el0;
+	lck.in.locks		= &el[0];
 	status = smb2_lock(tree, &lck);
 	CHECK_STATUS(status, NT_STATUS_OK);
 
 	/* Try to unlock both locks */
 	lck.in.lock_count	= 0x0002;
-	el0.flags		= SMB2_LOCK_FLAG_UNLOCK;
-	el1.flags		= SMB2_LOCK_FLAG_UNLOCK;
-	el[0]			= el0;
-	el[1]			= el1;
+	el[0].flags		= SMB2_LOCK_FLAG_UNLOCK;
+	el[1].flags		= SMB2_LOCK_FLAG_UNLOCK;
 	lck.in.locks		= el;
 	status = smb2_lock(tree, &lck);
 	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
 
 	/* First lock should be unlocked. */
 	lck.in.lock_count	= 0x0001;
-	el0.flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+	el[0].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+	lck.in.locks		= &el[0];
+	status = smb2_lock(tree, &lck);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* cleanup */
+	lck.in.lock_count	= 0x0001;
+	el[0].flags		= SMB2_LOCK_FLAG_UNLOCK;
+	lck.in.locks		= &el[0];
+	status = smb2_lock(tree, &lck);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Test3: Request 2 locks, second will contend.  What happens to the
+	 * first? */
+	torture_comment(torture, "  request 2 locks, second one will contend. "
+				 "Expect both to fail.\n");
+
+	/* Lock the second range */
+	lck.in.lock_count	= 0x0001;
+	el[1].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+	lck.in.locks		= &el[1];
+	status = smb2_lock(tree, &lck);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Request both locks */
+	lck.in.lock_count	= 0x0002;
+	el[0].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
 				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
-	lck.in.locks		= &el0;
+	lck.in.locks		= el;
+	status = smb2_lock(tree, &lck);
+	CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+	/* First lock should be unlocked. */
+	lck.in.lock_count	= 0x0001;
+	lck.in.locks		= &el[0];
 	status = smb2_lock(tree, &lck);
 	CHECK_STATUS(status, NT_STATUS_OK);
 
 	/* cleanup */
+	if (TARGET_IS_W2K8(torture)) {
+		lck.in.lock_count	= 0x0001;
+		el[0].flags		= SMB2_LOCK_FLAG_UNLOCK;
+		lck.in.locks		= &el[0];
+		status = smb2_lock(tree, &lck);
+		CHECK_STATUS(status, NT_STATUS_OK);
+		torture_warning(torture, "Target has \"pretty please\" bug. "
+				"A contending lock request on the same handle "
+				"unlocks the lock.\n");
+	} else {
+		lck.in.lock_count	= 0x0002;
+		el[0].flags		= SMB2_LOCK_FLAG_UNLOCK;
+		el[1].flags		= SMB2_LOCK_FLAG_UNLOCK;
+		lck.in.locks		= el;
+		status = smb2_lock(tree, &lck);
+		CHECK_STATUS(status, NT_STATUS_OK);
+	}
+
+	/* Test4: Request unlock and lock.  The lock contends, is the unlock
+	 * then relocked?  SMB2 doesn't like the lock and unlock requests in the
+	 * same packet. The unlock will succeed, but the lock will return
+	 * INVALID_PARAMETER.  This behavior is described in MS-SMB2
+	 * 3.3.5.14.1 */
+	torture_comment(torture, "  request unlock and lock, second one will "
+				 "error. Expect the unlock to succeed.\n");
+
+	/* Lock both ranges */
+	lck.in.lock_count	= 0x0002;
+	el[0].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+	el[1].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+	lck.in.locks		= el;
+	status = smb2_lock(tree, &lck);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Attempt to unlock the first range and lock the second. The lock
+	 * request will error. */
+	lck.in.lock_count	= 0x0002;
+	el[0].flags		= SMB2_LOCK_FLAG_UNLOCK;
+	el[1].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+	lck.in.locks		= el;
+	status = smb2_lock(tree, &lck);
+	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+	/* The first lock should've been unlocked */
 	lck.in.lock_count	= 0x0001;
-	el0.flags		= SMB2_LOCK_FLAG_UNLOCK;
-	lck.in.locks		= &el0;
+	el[0].flags		= SMB2_LOCK_FLAG_EXCLUSIVE |
+				  SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+	lck.in.locks		= &el[0];
 	status = smb2_lock(tree, &lck);
 	CHECK_STATUS(status, NT_STATUS_OK);
 
+	/* cleanup */
+	lck.in.lock_count	= 0x0002;
+	el[0].flags		= SMB2_LOCK_FLAG_UNLOCK;
+	el[1].flags		= SMB2_LOCK_FLAG_UNLOCK;
+	lck.in.locks		= el;
+	status = smb2_lock(tree, &lck);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Test10: SMB2 only test. Request unlock and lock in same packet.
+	 * Neither contend. SMB2 doesn't like lock and unlock requests in the
+	 * same packet.  The unlock will succeed, but the lock will return
+	 * INVALID_PARAMETER. */


-- 
Samba Shared Repository


More information about the samba-cvs mailing list