Latest leases patchset - getting there !

Stefan (metze) Metzmacher metze at samba.org
Tue Nov 11 14:41:38 MST 2014


Am 11.11.2014 um 21:36 schrieb Jeremy Allison:
> On Tue, Nov 11, 2014 at 12:30:31PM -0800, Jeremy Allison wrote:
>> Also the change for "level2 oplocks = no" must be documented
>> in the new "smb2 leases" section in the manpage. Here is a
>> new version of that patch (attached).
> 
> Bah, forgot to add the "related" in the level2oplocks man
> page. Updated version attached !

Thanks, I'll integrate this tomorrow.

here's ontop13.diff.txt with some more fixes
and new tests which demonstrate a problem
of outdated fsp->lease information if a lease is shared
between two smbd processes.

We also need to readd the update_num_read_oplocks()
case for exclusive oplocks where we skip the brlock entry.

I'm not sure if we can do such optimisation for leases too,
maybe only if be have just one fsp with a RWH lease.

metze
-------------- next part --------------
From 3dddcde5c8f9529fd1cd8f9bf814204f0ec1b15c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 30 Oct 2014 10:10:07 +0100
Subject: [PATCH 1/7] SQ grant_fsp_oplock_type: minimize the diff

---
 source3/smbd/open.c | 34 ++++++++++++++++------------------
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index e353ec1..aa250f2 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1700,22 +1700,22 @@ static NTSTATUS grant_fsp_lease(files_struct *fsp, struct share_mode_data *d,
 	d->modified = true;
 
 	return NT_STATUS_OK;
-
 }
 
-static NTSTATUS grant_fsp_oplock_type(struct smb_request *req, files_struct *fsp,
+static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
+				      struct files_struct *fsp,
 				      struct share_mode_lock *lck,
 				      int oplock_request,
-				      uint32_t create_disposition,
 				      struct smb2_lease *lease)
 {
 	struct share_mode_data *d = lck->data;
-	bool got_handle_lease, got_oplock;
+	bool got_handle_lease = false;
+	bool got_oplock = false;
 	uint32_t i;
 	uint32_t granted;
 	uint32_t lease_idx = UINT32_MAX;
+	bool ok;
 	NTSTATUS status;
-	bool ret;
 
 	if (oplock_request & INTERNAL_OPEN_ONLY) {
 		/* No oplocks on internal open. */
@@ -1750,9 +1750,6 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req, files_struct *fsp
 		granted &= ~SMB2_LEASE_READ;
 	}
 
-	got_handle_lease = false;
-	got_oplock = false;
-
 	for (i=0; i<d->num_share_modes; i++) {
 		struct share_mode_entry *e = &d->share_modes[i];
 		uint32_t e_lease_type;
@@ -1825,9 +1822,6 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req, files_struct *fsp
 		}
 	}
 
-	DEBUG(10,("grant_fsp_oplock_type: oplock type 0x%x on file %s\n",
-		  fsp->oplock_type, fsp_str_dbg(fsp)));
-
 	status = set_file_oplock(fsp);
 	if (!NT_STATUS_IS_OK(status)) {
 		/*
@@ -1836,16 +1830,22 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req, files_struct *fsp
 		fsp->oplock_type = NO_OPLOCK;
 	}
 
-	if (!set_share_mode(lck, fsp, get_current_uid(fsp->conn),
+	ok = set_share_mode(lck, fsp, get_current_uid(fsp->conn),
 			    req ? req->mid : 0,
-			    fsp->oplock_type, lease_idx)) {
+			    fsp->oplock_type, lease_idx);
+	if (!ok) {
 		return NT_STATUS_NO_MEMORY;
 	}
-	ret = update_num_read_oplocks(fsp, lck);
-	if (!ret) {
+
+	ok = update_num_read_oplocks(fsp, lck);
+	if (!ok) {
 		del_share_mode(lck, fsp);
 		return NT_STATUS_INTERNAL_ERROR;
 	}
+
+	DEBUG(10,("grant_fsp_oplock_type: oplock type 0x%x on file %s\n",
+		  fsp->oplock_type, fsp_str_dbg(fsp)));
+
 	return NT_STATUS_OK;
 }
 
@@ -3109,9 +3109,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 	 * Setup the oplock info in both the shared memory and
 	 * file structs.
 	 */
-
-	status = grant_fsp_oplock_type(req, fsp, lck, oplock_request,
-				       create_disposition, lease);
+	status = grant_fsp_oplock_type(req, fsp, lck, oplock_request, lease);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(lck);
 		fd_close(fsp);
-- 
1.9.1


From 5301c517a747a908af1d719b8dc920ea55164ef4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 11 Nov 2014 10:56:52 +0100
Subject: [PATCH 2/7] SQ fix grant_fsp_oplock_type() for leases  allow_level2
 ... simplify

---
 source3/smbd/open.c | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index aa250f2..af99f36 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1776,14 +1776,23 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
 		}
 	}
 
-	if (oplock_request == LEASE_OPLOCK) {
+	if ((granted & SMB2_LEASE_READ) && !(granted & SMB2_LEASE_WRITE)) {
+		bool allow_level2 =
+			(global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
+			lp_level2_oplocks(SNUM(fsp->conn));
 
-		fsp->oplock_type = LEASE_OPLOCK;
+		if (!allow_level2) {
+			granted = SMB2_LEASE_NONE;
+		}
+	}
 
+	if (oplock_request == LEASE_OPLOCK) {
 		if (got_oplock) {
-			granted &= SMB2_LEASE_READ;
+			granted &= ~SMB2_LEASE_HANDLE;
 		}
 
+		fsp->oplock_type = LEASE_OPLOCK;
+
 		status = grant_fsp_lease(fsp, lck->data, lease, &lease_idx,
 					 granted);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -1793,6 +1802,10 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
 		lease->lease_state = d->leases[lease_idx].current_state;
 		DEBUG(10, ("lease_state=%d\n", lease->lease_state));
 	} else {
+		if (got_handle_lease) {
+			granted = SMB2_LEASE_NONE;
+		}
+
 		switch (granted) {
 		case SMB2_LEASE_READ|SMB2_LEASE_WRITE|SMB2_LEASE_HANDLE:
 			fsp->oplock_type = BATCH_OPLOCK|EXCLUSIVE_OPLOCK;
@@ -1808,18 +1821,6 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
 			fsp->oplock_type = NO_OPLOCK;
 			break;
 		}
-		if (fsp->oplock_type == LEVEL_II_OPLOCK) {
-			bool allow_level2 =
-				(global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
-				lp_level2_oplocks(SNUM(fsp->conn));
-
-			if (!allow_level2) {
-				fsp->oplock_type = NO_OPLOCK;
-			}
-		}
-		if (got_handle_lease) {
-			fsp->oplock_type = NO_OPLOCK;
-		}
 	}
 
 	status = set_file_oplock(fsp);
-- 
1.9.1


From 826daca0607838fbf0ca310b16868f726d9819d5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 11 Nov 2014 10:57:32 +0100
Subject: [PATCH 3/7] SQ no leases for kernel oplocks

---
 source3/smbd/open.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index af99f36..f9effe3 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1727,6 +1727,10 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
 	if (oplock_request == LEASE_OPLOCK) {
 		granted = lease->lease_state;
 
+		if (lp_kernel_oplocks(SNUM(fsp->conn))) {
+			DEBUG(10, ("No lease granted because kernel oplocks are enabled\n"));
+			granted = SMB2_LEASE_NONE;
+		}
 		if ((granted & (SMB2_LEASE_READ|SMB2_LEASE_WRITE)) == 0) {
 			DEBUG(10, ("No read or write lease requested\n"));
 			granted = SMB2_LEASE_NONE;
@@ -1821,14 +1825,14 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
 			fsp->oplock_type = NO_OPLOCK;
 			break;
 		}
-	}
 
-	status = set_file_oplock(fsp);
-	if (!NT_STATUS_IS_OK(status)) {
-		/*
-		 * Could not get the kernel oplock
-		 */
-		fsp->oplock_type = NO_OPLOCK;
+		status = set_file_oplock(fsp);
+		if (!NT_STATUS_IS_OK(status)) {
+			/*
+			 * Could not get the kernel oplock
+			 */
+			fsp->oplock_type = NO_OPLOCK;
+		}
 	}
 
 	ok = set_share_mode(lck, fsp, get_current_uid(fsp->conn),
-- 
1.9.1


From e51fc7189d76bd95415f2327642dee0c11b7c262 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 11 Nov 2014 22:09:35 +0100
Subject: [PATCH 4/7] SQ smb2_create only allow leases if negotiated

---
 source3/smbd/smb2_create.c | 33 ++++++++++++++-------------------
 1 file changed, 14 insertions(+), 19 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 38ef04c..0c49c70 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -479,6 +479,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	struct smb2_create_blob *dh2c = NULL;
 	struct smb2_create_blob *dhnq = NULL;
 	struct smb2_create_blob *dh2q = NULL;
+	struct smb2_create_blob *rqls = NULL;
 	struct smbXsrv_open *op = NULL;
 
 	ZERO_STRUCT(out_context_blobs);
@@ -525,6 +526,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 				     SMB2_CREATE_TAG_DH2Q);
 	dh2c = smb2_create_blob_find(&in_context_blobs,
 				     SMB2_CREATE_TAG_DH2C);
+	if (smb2req->xconn->smb2.server.capabilities & SMB2_CAP_LEASING) {
+		rqls = smb2_create_blob_find(&in_context_blobs,
+					     SMB2_CREATE_TAG_RQLS);
+	}
 
 	if ((dhnc && dh2c) || (dhnc && dh2q) || (dh2c && dhnq) ||
 	    (dh2q && dh2c))
@@ -564,8 +569,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			num_blobs_allowed = 1;
 		}
 
-		if (smb2_create_blob_find(&in_context_blobs,
-					  SMB2_CREATE_TAG_RQLS) != NULL) {
+		if (rqls != NULL) {
 			num_blobs_allowed += 1;
 		}
 
@@ -601,8 +605,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		num_blobs_allowed = 1;
 
-		if (smb2_create_blob_find(&in_context_blobs,
-					  SMB2_CREATE_TAG_RQLS) != NULL) {
+		if (rqls != NULL) {
 			num_blobs_allowed += 1;
 		}
 
@@ -667,14 +670,13 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		struct smb2_create_blob *qfid = NULL;
 		struct GUID _create_guid = GUID_zero();
 		struct GUID *create_guid = NULL;
-		struct smb2_create_blob *rqls = NULL;
 		bool update_open = false;
 		bool durable_requested = false;
 		uint32_t durable_timeout_msec = 0;
 		bool do_durable_reconnect = false;
 		uint64_t persistent_id = 0;
 		struct smb2_lease lease;
-		struct smb2_lease *lease_ptr;
+		struct smb2_lease *lease_ptr = NULL;
 		ssize_t lease_len = -1;
 
 		exta = smb2_create_blob_find(&in_context_blobs,
@@ -689,8 +691,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					     SMB2_CREATE_TAG_TWRP);
 		qfid = smb2_create_blob_find(&in_context_blobs,
 					     SMB2_CREATE_TAG_QFID);
-		rqls = smb2_create_blob_find(&in_context_blobs,
-					     SMB2_CREATE_TAG_RQLS);
 
 		fname = talloc_strdup(state, in_name);
 		if (tevent_req_nomem(fname, req)) {
@@ -877,8 +877,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			}
 		}
 
-		lease_ptr = NULL;
-
 		if (rqls) {
 			lease_len = smb2_lease_pull(
 				rqls->data.data, rqls->data.length, &lease);
@@ -900,18 +898,15 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 				requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 			}
 
-			if (smb2req->sconn->client->connections->protocol <
-			    PROTOCOL_SMB2_10) {
-				lease_ptr = NULL;
-				requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
-			}
-
-			/* TODO client->connections ... */
-			if ((smb2req->sconn->client->connections->protocol <
-			     PROTOCOL_SMB3_00) &&
+			if ((smb2req->xconn->protocol < PROTOCOL_SMB3_00) &&
 			    (lease.lease_version != 1)) {
 				DEBUG(10, ("v2 lease key only for SMB3\n"));
 				lease_ptr = NULL;
+			}
+		}
+
+		if (requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
+			if (lease_ptr == NULL) {
 				requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 			}
 		}
-- 
1.9.1


From c01b4f9afe822d0732bccbbe2b57d1ab6285e8dd Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 11 Nov 2014 19:33:13 +0100
Subject: [PATCH 5/7] s4:libcli/smb2: add new_epoch to struct smb2_lease_break

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/raw/interfaces.h | 1 +
 source4/libcli/smb2/transport.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h
index 9003c12..05f5da0 100644
--- a/source4/libcli/raw/interfaces.h
+++ b/source4/libcli/raw/interfaces.h
@@ -57,6 +57,7 @@ struct smb2_handle {
 
 struct smb2_lease_break {
 	struct smb2_lease current_lease;
+	uint16_t new_epoch; /* only for v2 leases */
 	uint32_t break_flags;
 	uint32_t new_lease_state;
 	uint32_t break_reason; /* should be 0 */
diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c
index 9b0c146..d9c3815 100644
--- a/source4/libcli/smb2/transport.c
+++ b/source4/libcli/smb2/transport.c
@@ -390,6 +390,7 @@ static void smb2_transport_break_handler(struct tevent_req *subreq)
 		struct smb2_lease_break lb;
 
 		ZERO_STRUCT(lb);
+		lb.new_epoch =			SVAL(body, 0x2);
 		lb.break_flags =		SVAL(body, 0x4);
 		memcpy(&lb.current_lease.lease_key, body+0x8,
 		    sizeof(struct smb2_lease_key));
-- 
1.9.1


From c1e860a66fa465d9e0345acd013b9e0a4eb5f1ba Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 11 Nov 2014 19:35:07 +0100
Subject: [PATCH 6/7] s4:torture/smb2: always verify the v2 lease epoch.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/torture/smb2/lease.c | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c
index 7ea2eab..d4d4f33 100644
--- a/source4/torture/smb2/lease.c
+++ b/source4/torture/smb2/lease.c
@@ -72,7 +72,7 @@
 		CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
 	} while(0)
 
-#define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent) \
+#define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
 	do {								\
 		if (__oplevel) {					\
 			CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
@@ -92,6 +92,7 @@
 			CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
 		} \
 		CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
+		CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
 	} while(0)
 
 static const uint64_t LEASE1 = 0xBADC0FFEE0DDF00Dull;
@@ -420,6 +421,12 @@ static struct {
 		}							\
 	} while(0)
 
+#define CHECK_BREAK_INFO_V2(__oldstate, __state, __key, __epoch)	\
+	do {								\
+		CHECK_BREAK_INFO(__oldstate, __state, __key);		\
+		CHECK_VAL(break_info.lease_break.new_epoch, __epoch);	\
+	} while(0)
+
 static void torture_lease_break_callback(struct smb2_request *req)
 {
 	NTSTATUS status;
@@ -1211,7 +1218,7 @@ static bool test_lease_v2_request_parent(struct torture_context *tctx,
 	h1 = io.out.file.handle;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
 	CHECK_LEASE_V2(&io, "RHW", true, LEASE1,
-		       SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2);
+		       SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2, 1);
 
  done:
 	smb2_util_close(tree, h1);
@@ -1254,7 +1261,7 @@ static bool test_lease_break_twice(struct torture_context *tctx,
 	CHECK_STATUS(status, NT_STATUS_OK);
 	h1 = io.out.file.handle;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0);
+	CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, 1);
 
 	tree->session->transport->lease.handler = torture_lease_handler;
 	tree->session->transport->lease.private_data = tree;
@@ -1322,7 +1329,7 @@ static bool test_lease_v2_request(struct torture_context *tctx,
 	CHECK_STATUS(status, NT_STATUS_OK);
 	h1 = io.out.file.handle;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0);
+	CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, 1);
 
 	ZERO_STRUCT(io);
 	smb2_lease_v2_create_share(&io, &ls, true, dname,
@@ -1334,7 +1341,7 @@ static bool test_lease_v2_request(struct torture_context *tctx,
 	CHECK_STATUS(status, NT_STATUS_OK);
 	h2 = io.out.file.handle;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
-	CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0);
+	CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, 1);
 
 	ZERO_STRUCT(io);
 	smb2_lease_v2_create_share(&io, &ls, false, dnamefname,
@@ -1347,7 +1354,7 @@ static bool test_lease_v2_request(struct torture_context *tctx,
 	h3 = io.out.file.handle;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
 	CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
-		       SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2);
+		       SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2, 1);
 
 	torture_wait_for_lease_break(tctx);
 	CHECK_VAL(break_info.count, 0);
@@ -1363,7 +1370,7 @@ static bool test_lease_v2_request(struct torture_context *tctx,
 	CHECK_STATUS(status, NT_STATUS_OK);
 	h4 = io.out.file.handle;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0);
+	CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0, 1);
 
 	torture_wait_for_lease_break(tctx);
 	torture_wait_for_lease_break(tctx);
@@ -1383,7 +1390,7 @@ static bool test_lease_v2_request(struct torture_context *tctx,
 	CHECK_STATUS(status, NT_STATUS_OK);
 	h5 = io.out.file.handle;
 	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
-	CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0);
+	CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, 1);
 	smb2_util_close(tree, h5);
 
 	ZERO_STRUCT(w);
@@ -1445,15 +1452,12 @@ static bool test_lease_v2_epoch1(struct torture_context *tctx,
 				   smb2_util_share_access("RWD"),
 				   LEASE1, NULL,
 				   smb2_util_lease_state("RHW"),
-				   0);
-	ls.lease_epoch = 0x4711;
-
+				   0x4711);
 	status = smb2_create(tree, mem_ctx, &io);
 	CHECK_STATUS(status, NT_STATUS_OK);
 	h = io.out.file.handle;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0);
-	CHECK_VAL(io.out.lease_response_v2.lease_epoch, ls.lease_epoch + 1);
+	CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls.lease_epoch + 1);
 	smb2_util_close(tree, h);
 	smb2_util_unlink(tree, fname);
 
@@ -1463,8 +1467,7 @@ static bool test_lease_v2_epoch1(struct torture_context *tctx,
 	CHECK_STATUS(status, NT_STATUS_OK);
 	h = io.out.file.handle;
 	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-	CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0);
-	CHECK_VAL(io.out.lease_response_v2.lease_epoch, ls.lease_epoch + 1);
+	CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls.lease_epoch + 1);
 	smb2_util_close(tree, h);
 
 done:
-- 
1.9.1


From da39bab6e6b105a05899bf3d4dbcbd259f6d6907 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 11 Nov 2014 19:35:59 +0100
Subject: [PATCH 7/7] s4:torture/smb2: add smb2.lease.[v2_]complex1 tests

These tests verify the lease state is consistent between two connections
with the same client_guid.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/torture/smb2/lease.c | 195 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 194 insertions(+), 1 deletion(-)

diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c
index d4d4f33..ca85e80 100644
--- a/source4/torture/smb2/lease.c
+++ b/source4/torture/smb2/lease.c
@@ -397,6 +397,7 @@ static bool test_lease_upgrade2(struct torture_context *tctx,
 
 static struct {
 	struct smb2_lease_break lease_break;
+	struct smb2_transport *lease_transport;
 	struct smb2_lease_break_ack lease_break_ack;
 	int count;
 	int failures;
@@ -421,10 +422,11 @@ static struct {
 		}							\
 	} while(0)
 
-#define CHECK_BREAK_INFO_V2(__oldstate, __state, __key, __epoch)	\
+#define CHECK_BREAK_INFO_V2(__transport, __oldstate, __state, __key, __epoch) \
 	do {								\
 		CHECK_BREAK_INFO(__oldstate, __state, __key);		\
 		CHECK_VAL(break_info.lease_break.new_epoch, __epoch);	\
+		CHECK_VAL(break_info.lease_transport, __transport);	\
 	} while(0)
 
 static void torture_lease_break_callback(struct smb2_request *req)
@@ -447,6 +449,7 @@ static bool torture_lease_handler(struct smb2_transport *transport,
 	struct smb2_lease_break_ack io;
 	struct smb2_request *req;
 
+	break_info.lease_transport = transport;
 	break_info.lease_break = *lb;
 	break_info.count++;
 
@@ -1476,6 +1479,194 @@ done:
 	return ret;
 }
 
+static bool test_lease_complex1(struct torture_context *tctx,
+				struct smb2_tree *tree1a)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_create io;
+	struct smb2_lease ls;
+	struct smb2_handle h, h2, h3;
+	NTSTATUS status;
+	const char *fname = "lease_complex1.dat";
+	bool ret = true;
+	uint32_t caps;
+	struct smb2_tree *tree1b = NULL;
+	struct smbcli_options options1;
+
+	options1 = tree1a->session->transport->options;
+
+	caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
+	if (!(caps & SMB2_CAP_LEASING)) {
+		torture_skip(tctx, "leases are not supported");
+	}
+
+	tree1a->session->transport->lease.handler = torture_lease_handler;
+	tree1a->session->transport->lease.private_data = tree1a;
+	tree1a->session->transport->oplock.handler = torture_oplock_handler;
+	tree1a->session->transport->oplock.private_data = tree1a;
+
+	/* create a new connection (same client_guid) */
+	if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
+		torture_warning(tctx, "couldn't reconnect, bailing\n");
+		ret = false;
+		goto done;
+	}
+
+	tree1b->session->transport->lease.handler = torture_lease_handler;
+	tree1b->session->transport->lease.private_data = tree1b;
+	tree1b->session->transport->oplock.handler = torture_oplock_handler;
+	tree1b->session->transport->oplock.private_data = tree1b;
+
+	smb2_util_unlink(tree1a, fname);
+
+	ZERO_STRUCT(break_info);
+
+	/* Grab R lease over connection 1a */
+	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
+	status = smb2_create(tree1a, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h = io.out.file.handle;
+	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_LEASE(&io, "R", true, LEASE1);
+
+	/* Upgrade to RWH over connection 1b */
+	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
+	status = smb2_create(tree1b, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h2 = io.out.file.handle;
+	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_LEASE(&io, "RHW", true, LEASE1);
+
+	/* close over connection 1b */
+	status = smb2_util_close(tree1b, h2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Contend with LEASE2. */
+	smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
+	status = smb2_create(tree1b, mem_ctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h3 = io.out.file.handle;
+	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+	CHECK_LEASE(&io, "RH", true, LEASE2);
+
+	/* Verify that we were only sent one break. */
+	torture_wait_for_lease_break(tctx);
+	CHECK_BREAK_INFO("RHW", "RH", LEASE1);
+
+ done:
+	smb2_util_close(tree1a, h);
+	smb2_util_close(tree1b, h2);
+	smb2_util_close(tree1b, h3);
+
+	smb2_util_unlink(tree1a, fname);
+
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
+static bool test_lease_v2_complex1(struct torture_context *tctx,
+				   struct smb2_tree *tree1a)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	struct smb2_create io1;
+	struct smb2_create io2;
+	struct smb2_lease ls1;
+	struct smb2_lease ls2;
+	struct smb2_handle h, h2, h3;
+	NTSTATUS status;
+	const char *fname = "lease_v2_complex1.dat";
+	bool ret = true;
+	uint32_t caps;
+	struct smb2_tree *tree1b = NULL;
+	struct smbcli_options options1;
+
+	options1 = tree1a->session->transport->options;
+
+	caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
+	if (!(caps & SMB2_CAP_LEASING)) {
+		torture_skip(tctx, "leases are not supported");
+	}
+
+	if (smbXcli_conn_protocol(tree1a->session->transport->conn) < PROTOCOL_SMB3_00) {
+		torture_skip(tctx, "v2 leases are not supported");
+	}
+
+	tree1a->session->transport->lease.handler = torture_lease_handler;
+	tree1a->session->transport->lease.private_data = tree1a;
+	tree1a->session->transport->oplock.handler = torture_oplock_handler;
+	tree1a->session->transport->oplock.private_data = tree1a;
+
+	/* create a new connection (same client_guid) */
+	if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
+		torture_warning(tctx, "couldn't reconnect, bailing\n");
+		ret = false;
+		goto done;
+	}
+
+	tree1b->session->transport->lease.handler = torture_lease_handler;
+	tree1b->session->transport->lease.private_data = tree1b;
+	tree1b->session->transport->oplock.handler = torture_oplock_handler;
+	tree1b->session->transport->oplock.private_data = tree1b;
+
+	smb2_util_unlink(tree1a, fname);
+
+	ZERO_STRUCT(break_info);
+
+	/* Grab R lease over connection 1a */
+	smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
+			     smb2_util_lease_state("R"), 0x4711);
+	status = smb2_create(tree1a, mem_ctx, &io1);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h = io1.out.file.handle;
+	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+	ls1.lease_epoch += 1;
+	CHECK_LEASE_V2(&io1, "R", true, LEASE1,
+		       0, 0, ls1.lease_epoch);
+
+	/* Upgrade to RWH over connection 1b */
+	ls1.lease_state = smb2_util_lease_state("RWH");
+	status = smb2_create(tree1b, mem_ctx, &io1);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h2 = io1.out.file.handle;
+	CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+	ls1.lease_epoch += 1;
+	CHECK_LEASE_V2(&io1, "RHW", true, LEASE1,
+		       0, 0, ls1.lease_epoch);
+
+	/* close over connection 1b */
+	status = smb2_util_close(tree1b, h2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/* Contend with LEASE2. */
+	smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
+			     smb2_util_lease_state("RWH"), 0x11);
+	status = smb2_create(tree1b, mem_ctx, &io2);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	h3 = io2.out.file.handle;
+	CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+	ls2.lease_epoch += 1;
+	CHECK_LEASE_V2(&io2, "RH", true, LEASE2,
+		       0, 0, ls2.lease_epoch);
+
+	/* Verify that we were only sent one break. */
+	ls1.lease_epoch += 1;
+	torture_wait_for_lease_break(tctx);
+	CHECK_BREAK_INFO_V2(tree1a->session->transport,
+			    "RHW", "RH", LEASE1, ls1.lease_epoch);
+
+ done:
+	smb2_util_close(tree1a, h);
+	smb2_util_close(tree1b, h2);
+	smb2_util_close(tree1b, h3);
+
+	smb2_util_unlink(tree1a, fname);
+
+	talloc_free(mem_ctx);
+
+	return ret;
+}
+
 struct torture_suite *torture_smb2_lease_init(void)
 {
 	struct torture_suite *suite =
@@ -1492,10 +1683,12 @@ struct torture_suite *torture_smb2_lease_init(void)
 	torture_suite_add_1smb2_test(suite, "break", test_lease_break);
 	torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
 	torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
+	torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1);
 	torture_suite_add_1smb2_test(suite, "v2_request_parent",
 				     test_lease_v2_request_parent);
 	torture_suite_add_1smb2_test(suite, "v2_request", test_lease_v2_request);
 	torture_suite_add_1smb2_test(suite, "v2_epoch1", test_lease_v2_epoch1);
+	torture_suite_add_1smb2_test(suite, "v2_complex1", test_lease_v2_complex1);
 
 	suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
 
-- 
1.9.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20141111/a3f4348e/attachment.pgp>


More information about the samba-technical mailing list