Latest leases patchset - getting there !

Stefan (metze) Metzmacher metze at samba.org
Fri Nov 7 10:08:38 MST 2014


Hi Jeremy,

here're 2 patch files.

ok.diff.txt contains the changes from my
https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=refs/heads/master3-leases-ok
branch, they're ready for master and should not cause much trouble when
you rebase the rest.

tmp.diff.txt contains the grant_fsp_oplock_type() and brl_num_read changes
Just tell me if they look ok for you, don't push them yet.

undo.diff.txt revert some of tmp.diff.txt so that the rest will
rebase correctly.

If you're fine with tmp.diff.txt I'll prepare a complete rebased patchset.

metze

Am 05.11.2014 um 21:53 schrieb Jeremy Allison:
> Applies on top of master. Just wanted
> to let everyone know where this was
> going so people can test/comment.
> 
> I'm planning to get this into master/4.2.0
> soon.
> 
> Cheers,
> 
> 	Jeremy.
> 

-------------- next part --------------
From 97e8c3241d0b81e0b6fa8170e6b71dc53c9e8f7f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 5 Nov 2014 20:27:06 +0100
Subject: [PATCH 1/6] s3:smbstatus: fix return value in print_share_mode()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/utils/status.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/utils/status.c b/source3/utils/status.c
index 936e87b7..978d3c5 100644
--- a/source3/utils/status.c
+++ b/source3/utils/status.c
@@ -123,7 +123,7 @@ static int print_share_mode(const struct share_mode_entry *e,
 	static int count;
 
 	if (do_checks && !is_valid_share_mode_entry(e)) {
-		return;
+		return 0;
 	}
 
 	if (count==0) {
-- 
1.9.1


From b4a3acdba6d109ecffd6a1e118503865d24225a6 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Wed, 5 Nov 2014 10:12:20 -0800
Subject: [PATCH 2/6] s4:torture: Add smb2.oplock test batch9a and raw.oplock
 test batch9a

Shows attribute(stat) access open can create a file,
and subsequent attribute(stat) opens don't break oplocks.

Can be extended to explore more varients.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 selftest/knownfail            |   2 +
 source4/torture/raw/oplock.c  | 121 +++++++++++++++++++++++++++++++++++++++
 source4/torture/smb2/oplock.c | 128 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 251 insertions(+)

diff --git a/selftest/knownfail b/selftest/knownfail
index 6cca3dd..10c2d27 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -130,6 +130,7 @@
 ^samba4.raw.lock.*.async # bug 6960
 ^samba4.smb2.lock.*.multiple-unlock # bug 6959
 ^samba4.raw.sfileinfo.*.end-of-file\(.*\)$ # bug 6962
+^samba4.raw.oplock.*.batch9a
 ^samba4.raw.oplock.*.batch22 # bug 6963
 ^samba4.raw.oplock.*.doc1
 ^samba4.raw.oplock.*.exclusive5
@@ -167,6 +168,7 @@
 ^samba4.smb2.oplock.batch1\(.*\)$ # samba 4 oplocks are a mess
 ^samba4.smb2.oplock.batch6\(.*\)$ # samba 4 oplocks are a mess
 ^samba4.smb2.oplock.batch9\(.*\)$ # samba 4 oplocks are a mess
+^samba4.smb2.oplock.batch9a\(.*\)$ # samba 4 oplocks are a mess
 ^samba4.smb2.oplock.batch10\(.*\)$ # samba 4 oplocks are a mess
 ^samba4.smb2.oplock.batch20\(.*\)$ # samba 4 oplocks are a mess
 ^samba4.smb2.oplock.batch26\(.*\)$
diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c
index a4f6a05..1d7522f 100644
--- a/source4/torture/raw/oplock.c
+++ b/source4/torture/raw/oplock.c
@@ -1873,6 +1873,126 @@ done:
 	return ret;
 }
 
+static bool test_raw_oplock_batch9a(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+	const char *fname = BASEDIR "\\test_batch9a.dat";
+	NTSTATUS status;
+	bool ret = true;
+	union smb_open io;
+	uint16_t fnum=0, fnum2=0;
+	char c = 0;
+
+	if (!torture_setup_dir(cli1, BASEDIR)) {
+		return false;
+	}
+
+	/* cleanup */
+	smbcli_unlink(cli1->tree, fname);
+
+	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+	/*
+	  base ntcreatex parms
+	*/
+	io.generic.level = RAW_OPEN_NTCREATEX;
+	io.ntcreatex.in.root_fid.fnum = 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;
+
+	torture_comment(tctx, "BATCH9: open with attributes only can create file\n");
+
+	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+		NTCREATEX_FLAGS_REQUEST_OPLOCK |
+		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+	io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+	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.create_action, FILE_WAS_CREATED);
+	CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+	torture_comment(tctx, "Subsequent attributes open should not break\n");
+
+	ZERO_STRUCT(break_info);
+	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+	status = smb_raw_open(cli2->tree, tctx, &io);
+	CHECK_STATUS(tctx, status, NT_STATUS_OK);
+	fnum2 = io.ntcreatex.out.file.fnum;
+	torture_wait_for_oplock_break(tctx);
+	CHECK_VAL(break_info.count, 0);
+	CHECK_VAL(io.ntcreatex.out.create_action, FILE_WAS_OPENED);
+	CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+	smbcli_close(cli2->tree, fnum2);
+
+	torture_comment(tctx, "Subsequent normal open should break oplock on attribute only open to level II\n");
+
+	ZERO_STRUCT(break_info);
+	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+		NTCREATEX_FLAGS_REQUEST_OPLOCK |
+		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+	status = smb_raw_open(cli2->tree, tctx, &io);
+	CHECK_STATUS(tctx, status, NT_STATUS_OK);
+	fnum2 = io.ntcreatex.out.file.fnum;
+	torture_wait_for_oplock_break(tctx);
+	CHECK_VAL(break_info.count, 1);
+	CHECK_VAL(break_info.fnum, fnum);
+	CHECK_VAL(break_info.failures, 0);
+	CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+	CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+	smbcli_close(cli2->tree, fnum2);
+
+	torture_comment(tctx, "third oplocked open should grant level2 without break\n");
+	ZERO_STRUCT(break_info);
+	smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+	smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
+	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+		NTCREATEX_FLAGS_REQUEST_OPLOCK |
+		NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+	io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+	status = smb_raw_open(cli2->tree, tctx, &io);
+	CHECK_STATUS(tctx, status, NT_STATUS_OK);
+	fnum2 = io.ntcreatex.out.file.fnum;
+	torture_wait_for_oplock_break(tctx);
+	CHECK_VAL(break_info.count, 0);
+	CHECK_VAL(break_info.failures, 0);
+	CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+	ZERO_STRUCT(break_info);
+
+	torture_comment(tctx, "write should trigger a break to none on both\n");
+	smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
+
+	/* We expect two breaks */
+	torture_wait_for_oplock_break(tctx);
+	torture_wait_for_oplock_break(tctx);
+
+	CHECK_VAL(break_info.count, 2);
+	CHECK_VAL(break_info.level, 0);
+	CHECK_VAL(break_info.failures, 0);
+
+	smbcli_close(cli1->tree, fnum);
+	smbcli_close(cli2->tree, fnum2);
+
+done:
+	smb_raw_exit(cli1->session);
+	smb_raw_exit(cli2->session);
+	smbcli_deltree(cli1->tree, BASEDIR);
+	return ret;
+}
+
 static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
 	const char *fname = BASEDIR "\\test_batch10.dat";
@@ -4311,6 +4431,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx)
 	torture_suite_add_2smb_test(suite, "batch7", test_raw_oplock_batch7);
 	torture_suite_add_2smb_test(suite, "batch8", test_raw_oplock_batch8);
 	torture_suite_add_2smb_test(suite, "batch9", test_raw_oplock_batch9);
+	torture_suite_add_2smb_test(suite, "batch9a", test_raw_oplock_batch9a);
 	torture_suite_add_2smb_test(suite, "batch10", test_raw_oplock_batch10);
 	torture_suite_add_2smb_test(suite, "batch11", test_raw_oplock_batch11);
 	torture_suite_add_2smb_test(suite, "batch12", test_raw_oplock_batch12);
diff --git a/source4/torture/smb2/oplock.c b/source4/torture/smb2/oplock.c
index d2a2832..be1c5eb 100644
--- a/source4/torture/smb2/oplock.c
+++ b/source4/torture/smb2/oplock.c
@@ -1611,6 +1611,133 @@ static bool test_smb2_oplock_batch9(struct torture_context *tctx,
 	return ret;
 }
 
+static bool test_smb2_oplock_batch9a(struct torture_context *tctx,
+				     struct smb2_tree *tree1,
+				     struct smb2_tree *tree2)
+{
+	const char *fname = BASEDIR "\\test_batch9a.dat";
+	NTSTATUS status;
+	bool ret = true;
+	union smb_open io;
+	struct smb2_handle h, h1, h2, h3;
+	char c = 0;
+
+	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, "BATCH9: open with attributes only can create "
+			"file\n");
+
+	io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+	io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+	io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+				SEC_FILE_WRITE_ATTRIBUTE |
+				SEC_STD_SYNCHRONIZE;
+	status = smb2_create(tree1, tctx, &(io.smb2));
+	torture_assert_ntstatus_ok(tctx, status, "Error creating the file");
+	h1 = io.smb2.out.file.handle;
+	CHECK_VAL(io.smb2.out.create_action, FILE_WAS_CREATED);
+	CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+	torture_comment(tctx, "Subsequent attributes open should not break\n");
+
+	ZERO_STRUCT(break_info);
+
+	status = smb2_create(tree2, tctx, &(io.smb2));
+	torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+	h3 = io.smb2.out.file.handle;
+	torture_wait_for_oplock_break(tctx);
+	CHECK_VAL(break_info.count, 0);
+	CHECK_VAL(io.smb2.out.create_action, FILE_WAS_OPENED);
+	CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+	smb2_util_close(tree2, h3);
+
+	torture_comment(tctx, "Subsequent normal open should break oplock on "
+			"attribute only open to level II\n");
+
+	ZERO_STRUCT(break_info);
+
+	io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+	io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+	io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+	status = smb2_create(tree2, tctx, &(io.smb2));
+	torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+	h2 = io.smb2.out.file.handle;
+	torture_wait_for_oplock_break(tctx);
+	CHECK_VAL(break_info.count, 1);
+	CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+	CHECK_VAL(break_info.failures, 0);
+	CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+	CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+	smb2_util_close(tree2, h2);
+
+	torture_comment(tctx, "third oplocked open should grant level2 without "
+			"break\n");
+	ZERO_STRUCT(break_info);
+
+	tree2->session->transport->oplock.handler = torture_oplock_handler;
+	tree2->session->transport->oplock.private_data = tree2;
+
+	io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+	io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+	io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+	status = smb2_create(tree2, tctx, &(io.smb2));
+	torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+	h2 = io.smb2.out.file.handle;
+	torture_wait_for_oplock_break(tctx);
+	CHECK_VAL(break_info.count, 0);
+	CHECK_VAL(break_info.failures, 0);
+	CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+	ZERO_STRUCT(break_info);
+
+	torture_comment(tctx, "write should trigger a break to none on both\n");
+	tree1->session->transport->oplock.handler =
+	    torture_oplock_handler_level2_to_none;
+	tree2->session->transport->oplock.handler =
+	    torture_oplock_handler_level2_to_none;
+	smb2_util_write(tree2, h2, &c, 0, 1);
+
+	/* We expect two breaks */
+	torture_wait_for_oplock_break(tctx);
+	torture_wait_for_oplock_break(tctx);
+
+	CHECK_VAL(break_info.count, 2);
+	CHECK_VAL(break_info.level, 0);
+	CHECK_VAL(break_info.failures, 0);
+
+	smb2_util_close(tree1, h1);
+	smb2_util_close(tree2, h2);
+	smb2_util_close(tree1, h);
+
+	smb2_deltree(tree1, BASEDIR);
+	return ret;
+}
+
+
 static bool test_smb2_oplock_batch10(struct torture_context *tctx,
 				     struct smb2_tree *tree1,
 				     struct smb2_tree *tree2)
@@ -3836,6 +3963,7 @@ struct torture_suite *torture_smb2_oplocks_init(void)
 	torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
 	torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
 	torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
+	torture_suite_add_2smb2_test(suite, "batch9a", test_smb2_oplock_batch9a);
 	torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
 	torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
 	torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
-- 
1.9.1


From 361fd19997755514def99c5e9f0e58a005e63c84 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 23 Sep 2014 22:56:41 +0200
Subject: [PATCH 3/6] libcli/smb: remember the lease_version in struct
 smb2_lease

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/smb2_lease.c          | 1 +
 librpc/idl/smb2_lease_struct.idl | 1 +
 2 files changed, 2 insertions(+)

diff --git a/libcli/smb/smb2_lease.c b/libcli/smb/smb2_lease.c
index f97f096..5e9a34d 100644
--- a/libcli/smb/smb2_lease.c
+++ b/libcli/smb/smb2_lease.c
@@ -43,6 +43,7 @@ ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
 	lease->lease_state = IVAL(buf, 16);
 	lease->lease_flags = IVAL(buf, 20);
 	lease->lease_duration = BVAL(buf, 24);
+	lease->lease_version = version;
 
 	switch (version) {
 	case 1:
diff --git a/librpc/idl/smb2_lease_struct.idl b/librpc/idl/smb2_lease_struct.idl
index be80d14..5ccd8a3 100644
--- a/librpc/idl/smb2_lease_struct.idl
+++ b/librpc/idl/smb2_lease_struct.idl
@@ -28,6 +28,7 @@ interface smb2_lease_struct
 		uint32 lease_flags;
 		hyper lease_duration;	/* should be 0 */
 		smb2_lease_key parent_lease_key;
+		uint16 lease_version;
 		uint16 lease_epoch;
 	} smb2_lease;
 };
\ No newline at end of file
-- 
1.9.1


From 9139a4ffee57e788dcf5bca93513ca6e85859406 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 22 Sep 2014 21:21:36 +0200
Subject: [PATCH 4/6] libcli/smb: mask off SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET
 for version 1

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/smb2_lease.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcli/smb/smb2_lease.c b/libcli/smb/smb2_lease.c
index 5e9a34d..e817c34 100644
--- a/libcli/smb/smb2_lease.c
+++ b/libcli/smb/smb2_lease.c
@@ -48,6 +48,7 @@ ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
 	switch (version) {
 	case 1:
 		ZERO_STRUCT(lease->parent_lease_key);
+		lease->lease_flags &= ~SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET;
 		lease->lease_epoch = 0;
 		break;
 	case 2:
-- 
1.9.1


From 6c4962bd7e51d419e4d49d9b2aa23a07d9867c52 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 29 Oct 2014 13:55:16 +0100
Subject: [PATCH 5/6] libcli/smb: add smb2_lease_key_equal() helper function

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/smb2_lease.c | 6 ++++++
 libcli/smb/smb2_lease.h | 2 ++
 2 files changed, 8 insertions(+)

diff --git a/libcli/smb/smb2_lease.c b/libcli/smb/smb2_lease.c
index e817c34..41eafc9 100644
--- a/libcli/smb/smb2_lease.c
+++ b/libcli/smb/smb2_lease.c
@@ -87,3 +87,9 @@ bool smb2_lease_push(const struct smb2_lease *lease, uint8_t *buf, size_t len)
 
 	return true;
 }
+
+bool smb2_lease_key_equal(const struct smb2_lease_key *k1,
+			  const struct smb2_lease_key *k2)
+{
+	return ((k1->data[0] == k2->data[0]) && (k1->data[1] == k2->data[1]));
+}
diff --git a/libcli/smb/smb2_lease.h b/libcli/smb/smb2_lease.h
index ba8178d..9db239d 100644
--- a/libcli/smb/smb2_lease.h
+++ b/libcli/smb/smb2_lease.h
@@ -32,5 +32,7 @@
 ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
 			struct smb2_lease *lease);
 bool smb2_lease_push(const struct smb2_lease *lease, uint8_t *buf, size_t len);
+bool smb2_lease_key_equal(const struct smb2_lease_key *k1,
+			  const struct smb2_lease_key *k2);
 
 #endif /* _LIBCLI_SMB_SMB2_LEASE_H_ */
-- 
1.9.1


From d08c70fa5b894eaef3780ac7072e4d3b92857df2 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 4 Nov 2014 21:44:45 -0800
Subject: [PATCH 6/6] libcli/smb: Add smb2_lease_equal() which compares
 client_guids and keys.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 libcli/smb/smb2_lease.c | 8 ++++++++
 libcli/smb/smb2_lease.h | 5 +++++
 2 files changed, 13 insertions(+)

diff --git a/libcli/smb/smb2_lease.c b/libcli/smb/smb2_lease.c
index 41eafc9..7705256 100644
--- a/libcli/smb/smb2_lease.c
+++ b/libcli/smb/smb2_lease.c
@@ -93,3 +93,11 @@ bool smb2_lease_key_equal(const struct smb2_lease_key *k1,
 {
 	return ((k1->data[0] == k2->data[0]) && (k1->data[1] == k2->data[1]));
 }
+
+bool smb2_lease_equal(const struct GUID *g1,
+		      const struct smb2_lease_key *k1,
+		      const struct GUID *g2,
+		      const struct smb2_lease_key *k2)
+{
+	return GUID_equal(g1, g2) && smb2_lease_key_equal(k1, k2);
+}
diff --git a/libcli/smb/smb2_lease.h b/libcli/smb/smb2_lease.h
index 9db239d..2e6faf7 100644
--- a/libcli/smb/smb2_lease.h
+++ b/libcli/smb/smb2_lease.h
@@ -23,6 +23,7 @@
 #ifndef _LIBCLI_SMB_SMB2_LEASE_H_
 #define _LIBCLI_SMB_SMB2_LEASE_H_
 
+#include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/gen_ndr/smb2_lease_struct.h"
 
 /*
@@ -34,5 +35,9 @@ ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
 bool smb2_lease_push(const struct smb2_lease *lease, uint8_t *buf, size_t len);
 bool smb2_lease_key_equal(const struct smb2_lease_key *k1,
 			  const struct smb2_lease_key *k2);
+bool smb2_lease_equal(const struct GUID *g1,
+		      const struct smb2_lease_key *k1,
+		      const struct GUID *g2,
+		      const struct smb2_lease_key *k2);
 
 #endif /* _LIBCLI_SMB_SMB2_LEASE_H_ */
-- 
1.9.1
-------------- next part --------------
From fcf6e41040ffc97ad54db7ea5afd02d03357b2ce Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 28 Oct 2014 15:27:09 -0700
Subject: [PATCH 1/2] s3:smbd: move all oplock granting code to
 grant_fsp_oplock_type()

Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Pair-Programmed-With: Jeremy Allison <jra at samba.org>

Signed-off-by: Volker Lendecke <vl at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Jeremy Allison <jra at samba.org>
---
 source3/smbd/open.c | 73 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 44 insertions(+), 29 deletions(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index ccea1e9..85d82c6 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1489,38 +1489,37 @@ static bool file_has_brlocks(files_struct *fsp)
 	return (brl_num_locks(br_lck) > 0);
 }
 
-static void grant_fsp_oplock_type(files_struct *fsp,
-				  struct share_mode_lock *lck,
-				  int oplock_request)
+static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
+				      struct files_struct *fsp,
+				      struct share_mode_lock *lck,
+				      int oplock_request)
 {
 	bool allow_level2 = (global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
 		            lp_level2_oplocks(SNUM(fsp->conn));
 	bool got_level2_oplock, got_a_none_oplock;
 	uint32_t i;
+	bool ok;
+	NTSTATUS status;
 
 	/* Start by granting what the client asked for,
 	   but ensure no SAMBA_PRIVATE bits can be set. */
 	fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK);
 
+	if (fsp->oplock_type == NO_OPLOCK) {
+		goto type_selected;
+	}
+
 	if (oplock_request & INTERNAL_OPEN_ONLY) {
 		/* No oplocks on internal open. */
 		fsp->oplock_type = NO_OPLOCK;
-		DEBUG(10,("grant_fsp_oplock_type: oplock type 0x%x on file %s\n",
-			fsp->oplock_type, fsp_str_dbg(fsp)));
-		return;
+		goto type_selected;
 	}
 
 	if (lp_locking(fsp->conn->params) && file_has_brlocks(fsp)) {
 		DEBUG(10,("grant_fsp_oplock_type: file %s has byte range locks\n",
 			fsp_str_dbg(fsp)));
 		fsp->oplock_type = NO_OPLOCK;
-	}
-
-	if (is_stat_open(fsp->access_mask)) {
-		/* Leave the value already set. */
-		DEBUG(10,("grant_fsp_oplock_type: oplock type 0x%x on file %s\n",
-			fsp->oplock_type, fsp_str_dbg(fsp)));
-		return;
+		goto type_selected;
 	}
 
 	got_level2_oplock = false;
@@ -1554,6 +1553,23 @@ static void grant_fsp_oplock_type(files_struct *fsp,
 	 */
 	if (fsp->oplock_type == LEVEL_II_OPLOCK && !allow_level2) {
 		fsp->oplock_type = NO_OPLOCK;
+		goto type_selected;
+	}
+
+ type_selected:
+	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),
+			    req ? req->mid : 0,
+			    fsp->oplock_type);
+	if (!ok) {
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	if (fsp->oplock_type == LEVEL_II_OPLOCK && !got_level2_oplock) {
@@ -1571,6 +1587,8 @@ static void grant_fsp_oplock_type(files_struct *fsp,
 
 	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;
 }
 
 static bool request_timed_out(struct timeval request_time,
@@ -2738,8 +2756,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 		}
 	}
 
-	grant_fsp_oplock_type(fsp, lck, oplock_request);
-
 	/*
 	 * We have the share entry *locked*.....
 	 */
@@ -2799,9 +2815,18 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 	}
 
 	if (file_existed) {
-		/* stat opens on existing files don't get oplocks. */
+		/*
+		 * stat opens on existing files don't get oplocks.
+		 *
+		 * Note that we check for stat open on the *open_access_mask*,
+		 * i.e. the access mask we actually used to do the open,
+		 * not the one the client asked for (which is in
+		 * fsp->access_mask). This is due to the fact that
+		 * FILE_OVERWRITE and FILE_OVERWRITE_IF add in O_TRUNC,
+		 * which adds FILE_WRITE_DATA to open_access_mask.
+		 */
 		if (is_stat_open(open_access_mask)) {
-			fsp->oplock_type = NO_OPLOCK;
+			oplock_request = NO_OPLOCK;
 		}
 	}
 
@@ -2823,21 +2848,11 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 	 * Setup the oplock info in both the shared memory and
 	 * file structs.
 	 */
-
-	status = set_file_oplock(fsp);
+	status = grant_fsp_oplock_type(req, fsp, lck, oplock_request);
 	if (!NT_STATUS_IS_OK(status)) {
-		/*
-		 * Could not get the kernel oplock
-		 */
-		fsp->oplock_type = NO_OPLOCK;
-	}
-
-	if (!set_share_mode(lck, fsp, get_current_uid(conn),
-			    req ? req->mid : 0,
-			    fsp->oplock_type)) {
 		TALLOC_FREE(lck);
 		fd_close(fsp);
-		return NT_STATUS_NO_MEMORY;
+		return status;
 	}
 
 	/* Handle strange delete on close create semantics. */
-- 
1.9.1


From 0971eb2852a203e6dd9775e5c1801e7c52f7bbd5 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 28 Oct 2014 15:27:09 -0700
Subject: [PATCH 2/2] s3:locking: convert brl_have_read field to brl_num_read.

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/locking/brlock.c | 123 +++++++++++++++++++++--------------------------
 source3/locking/proto.h  |   6 +--
 source3/smbd/open.c      |  15 ++----
 source3/smbd/oplock.c    | 115 +++++++++++++++++++++++++++-----------------
 source3/smbd/proto.h     |   2 +
 5 files changed, 135 insertions(+), 126 deletions(-)

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index 0bed9f9..e060a45 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -47,7 +47,7 @@ struct byte_range_lock {
 	struct files_struct *fsp;
 	unsigned int num_locks;
 	bool modified;
-	bool have_read_oplocks;
+	uint32_t num_read_oplocks;
 	struct lock_struct *lock_data;
 	struct db_record *record;
 };
@@ -82,18 +82,18 @@ struct files_struct *brl_fsp(struct byte_range_lock *brl)
 	return brl->fsp;
 }
 
-bool brl_have_read_oplocks(const struct byte_range_lock *brl)
+uint32_t brl_num_read_oplocks(const struct byte_range_lock *brl)
 {
-	return brl->have_read_oplocks;
+	return brl->num_read_oplocks;
 }
 
-void brl_set_have_read_oplocks(struct byte_range_lock *brl,
-			       bool have_read_oplocks)
+void brl_set_num_read_oplocks(struct byte_range_lock *brl,
+			      uint32_t num_read_oplocks)
 {
-	DEBUG(10, ("Setting have_read_oplocks to %s\n",
-		   have_read_oplocks ? "true" : "false"));
+	DEBUG(10, ("Setting have_read_oplocks to %"PRIu32"\n",
+		   num_read_oplocks));
 	SMB_ASSERT(brl->record != NULL); /* otherwise we're readonly */
-	brl->have_read_oplocks = have_read_oplocks;
+	brl->num_read_oplocks = num_read_oplocks;
 	brl->modified = true;
 }
 
@@ -1850,7 +1850,6 @@ int brl_forall(void (*fn)(struct file_id id, struct server_id pid,
 
 static void byte_range_lock_flush(struct byte_range_lock *br_lck)
 {
-	size_t data_len;
 	unsigned i;
 	struct lock_struct *locks = br_lck->lock_data;
 
@@ -1874,15 +1873,7 @@ static void byte_range_lock_flush(struct byte_range_lock *br_lck)
 		}
 	}
 
-	data_len = br_lck->num_locks * sizeof(struct lock_struct);
-
-	if (br_lck->have_read_oplocks) {
-		data_len += 1;
-	}
-
-	DEBUG(10, ("data_len=%d\n", (int)data_len));
-
-	if (data_len == 0) {
+	if ((br_lck->num_locks == 0) && (br_lck->num_read_oplocks == 0)) {
 		/* No locks - delete this entry. */
 		NTSTATUS status = dbwrap_record_delete(br_lck->record);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -1891,19 +1882,20 @@ static void byte_range_lock_flush(struct byte_range_lock *br_lck)
 			smb_panic("Could not delete byte range lock entry");
 		}
 	} else {
+		size_t lock_len, data_len;
 		TDB_DATA data;
 		NTSTATUS status;
 
+		lock_len = br_lck->num_locks * sizeof(struct lock_struct);
+		data_len = lock_len + sizeof(br_lck->num_read_oplocks);
+
 		data.dsize = data_len;
 		data.dptr = talloc_array(talloc_tos(), uint8_t, data_len);
 		SMB_ASSERT(data.dptr != NULL);
 
-		memcpy(data.dptr, br_lck->lock_data,
-		       br_lck->num_locks * sizeof(struct lock_struct));
-
-		if (br_lck->have_read_oplocks) {
-			data.dptr[data_len-1] = 1;
-		}
+		memcpy(data.dptr, br_lck->lock_data, lock_len);
+		memcpy(data.dptr + lock_len, &br_lck->num_read_oplocks,
+		       sizeof(br_lck->num_read_oplocks));
 
 		status = dbwrap_record_store(br_lck->record, data, TDB_REPLACE);
 		TALLOC_FREE(data.dptr);
@@ -1926,6 +1918,32 @@ static int byte_range_lock_destructor(struct byte_range_lock *br_lck)
 	return 0;
 }
 
+static bool brl_parse_data(struct byte_range_lock *br_lck, TDB_DATA data)
+{
+	size_t data_len;
+
+	if (data.dsize == 0) {
+		return true;
+	}
+	if (data.dsize % sizeof(struct lock_struct) !=
+	    sizeof(br_lck->num_read_oplocks)) {
+		DEBUG(1, ("Invalid data size: %u\n", (unsigned)data.dsize));
+		return false;
+	}
+
+	br_lck->num_locks = data.dsize / sizeof(struct lock_struct);
+	data_len = br_lck->num_locks * sizeof(struct lock_struct);
+
+	br_lck->lock_data = talloc_memdup(br_lck, data.dptr, data_len);
+	if (br_lck->lock_data == NULL) {
+		DEBUG(1, ("talloc_memdup failed\n"));
+		return false;
+	}
+	memcpy(&br_lck->num_read_oplocks, data.dptr + data_len,
+	       sizeof(br_lck->num_read_oplocks));
+	return true;
+}
+
 /*******************************************************************
  Fetch a set of byte range lock data from the database.
  Leave the record locked.
@@ -1935,16 +1953,14 @@ static int byte_range_lock_destructor(struct byte_range_lock *br_lck)
 struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, files_struct *fsp)
 {
 	TDB_DATA key, data;
-	struct byte_range_lock *br_lck = talloc(mem_ctx, struct byte_range_lock);
+	struct byte_range_lock *br_lck;
 
+	br_lck = talloc_zero(mem_ctx, struct byte_range_lock);
 	if (br_lck == NULL) {
 		return NULL;
 	}
 
 	br_lck->fsp = fsp;
-	br_lck->num_locks = 0;
-	br_lck->have_read_oplocks = false;
-	br_lck->modified = False;
 
 	key.dptr = (uint8 *)&fsp->file_id;
 	key.dsize = sizeof(struct file_id);
@@ -1959,30 +1975,12 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, files_struct *fsp)
 
 	data = dbwrap_record_get_value(br_lck->record);
 
-	br_lck->lock_data = NULL;
-
-	talloc_set_destructor(br_lck, byte_range_lock_destructor);
-
-	br_lck->num_locks = data.dsize / sizeof(struct lock_struct);
-
-	if (br_lck->num_locks != 0) {
-		br_lck->lock_data = talloc_array(
-			br_lck, struct lock_struct, br_lck->num_locks);
-		if (br_lck->lock_data == NULL) {
-			DEBUG(0, ("malloc failed\n"));
-			TALLOC_FREE(br_lck);
-			return NULL;
-		}
-
-		memcpy(br_lck->lock_data, data.dptr,
-		       talloc_get_size(br_lck->lock_data));
+	if (!brl_parse_data(br_lck, data)) {
+		TALLOC_FREE(br_lck);
+		return NULL;
 	}
 
-	DEBUG(10, ("data.dsize=%d\n", (int)data.dsize));
-
-	if ((data.dsize % sizeof(struct lock_struct)) == 1) {
-		br_lck->have_read_oplocks = (data.dptr[data.dsize-1] == 1);
-	}
+	talloc_set_destructor(br_lck, byte_range_lock_destructor);
 
 	if (DEBUGLEVEL >= 10) {
 		unsigned int i;
@@ -2008,28 +2006,19 @@ static void brl_get_locks_readonly_parser(TDB_DATA key, TDB_DATA data,
 {
 	struct brl_get_locks_readonly_state *state =
 		(struct brl_get_locks_readonly_state *)private_data;
-	struct byte_range_lock *br_lock;
+	struct byte_range_lock *br_lck;
 
-	br_lock = talloc_pooled_object(
+	br_lck = talloc_pooled_object(
 		state->mem_ctx, struct byte_range_lock, 1, data.dsize);
-	if (br_lock == NULL) {
+	if (br_lck == NULL) {
 		*state->br_lock = NULL;
 		return;
 	}
-	br_lock->lock_data = (struct lock_struct *)talloc_memdup(
-		br_lock, data.dptr, data.dsize);
-	br_lock->num_locks = data.dsize / sizeof(struct lock_struct);
-
-	if ((data.dsize % sizeof(struct lock_struct)) == 1) {
-		br_lock->have_read_oplocks = (data.dptr[data.dsize-1] == 1);
-	} else {
-		br_lock->have_read_oplocks = false;
+	if (!brl_parse_data(br_lck, data)) {
+		*state->br_lock = NULL;
+		return;
 	}
-
-	DEBUG(10, ("Got %d bytes, have_read_oplocks: %s\n", (int)data.dsize,
-		   br_lock->have_read_oplocks ? "true" : "false"));
-
-	*state->br_lock = br_lock;
+	*state->br_lock = br_lck;
 }
 
 struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
@@ -2072,7 +2061,7 @@ struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
 			return NULL;
 		}
 
-		br_lock->have_read_oplocks = false;
+		br_lock->num_read_oplocks = 0;
 		br_lock->num_locks = 0;
 		br_lock->lock_data = NULL;
 
diff --git a/source3/locking/proto.h b/source3/locking/proto.h
index 44f3ba1..8eccff8 100644
--- a/source3/locking/proto.h
+++ b/source3/locking/proto.h
@@ -30,9 +30,9 @@ void brl_shutdown(void);
 
 unsigned int brl_num_locks(const struct byte_range_lock *brl);
 struct files_struct *brl_fsp(struct byte_range_lock *brl);
-bool brl_have_read_oplocks(const struct byte_range_lock *brl);
-void brl_set_have_read_oplocks(struct byte_range_lock *brl,
-			       bool have_read_oplocks);
+uint32_t brl_num_read_oplocks(const struct byte_range_lock *brl);
+void brl_set_num_read_oplocks(struct byte_range_lock *brl,
+			      uint32_t num_read_oplocks);
 
 NTSTATUS brl_lock_windows_default(struct byte_range_lock *br_lck,
 		struct lock_struct *plock,
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 85d82c6..acf06a3 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1572,17 +1572,10 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	if (fsp->oplock_type == LEVEL_II_OPLOCK && !got_level2_oplock) {
-		/*
-		 * We're the first level2 oplock. Indicate that in brlock.tdb.
-		 */
-		struct byte_range_lock *brl;
-
-		brl = brl_get_locks(talloc_tos(), fsp);
-		if (brl != NULL) {
-			brl_set_have_read_oplocks(brl, true);
-			TALLOC_FREE(brl);
-		}
+	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",
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 7935092..aa99f68 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -148,6 +148,53 @@ static void downgrade_file_oplock(files_struct *fsp)
 	TALLOC_FREE(fsp->oplock_timeout);
 }
 
+bool update_num_read_oplocks(files_struct *fsp, struct share_mode_lock *lck)
+{
+	struct share_mode_data *d = lck->data;
+	struct byte_range_lock *br_lck;
+	uint32_t num_read_oplocks = 0;
+	uint32_t i;
+
+	if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+		/*
+		 * If we're the only one, we don't need a brlock entry
+		 */
+		SMB_ASSERT(d->num_share_modes == 1);
+		SMB_ASSERT(EXCLUSIVE_OPLOCK_TYPE(d->share_modes[0].op_type));
+		return true;
+	}
+
+	for (i=0; i<d->num_share_modes; i++) {
+		struct share_mode_entry *e = &d->share_modes[i];
+
+		if (EXCLUSIVE_OPLOCK_TYPE(e->op_type)) {
+			num_read_oplocks += 1;
+			continue;
+		}
+
+		if (LEVEL_II_OPLOCK_TYPE(e->op_type)) {
+			num_read_oplocks += 1;
+			continue;
+		}
+	}
+
+	br_lck = brl_get_locks_readonly(fsp);
+	if (br_lck == NULL) {
+		return false;
+	}
+	if (brl_num_read_oplocks(br_lck) == num_read_oplocks) {
+		return true;
+	}
+
+	br_lck = brl_get_locks(talloc_tos(), fsp);
+	if (br_lck == NULL) {
+		return false;
+	}
+	brl_set_num_read_oplocks(br_lck, num_read_oplocks);
+	TALLOC_FREE(br_lck);
+	return true;
+}
+
 /****************************************************************************
  Remove a file oplock. Copes with level II and exclusive.
  Locks then unlocks the share mode lock. Client can decide to go directly
@@ -170,44 +217,6 @@ bool remove_oplock(files_struct *fsp)
 		return False;
 	}
 
-	if (fsp->oplock_type == LEVEL_II_OPLOCK) {
-
-		/*
-		 * If we're the only LEVEL_II holder, we have to remove the
-		 * have_read_oplocks from the brlock entry
-		 */
-
-		struct share_mode_data *data = lck->data;
-		uint32_t i, num_level2;
-
-		num_level2 = 0;
-		for (i=0; i<data->num_share_modes; i++) {
-			if (data->share_modes[i].op_type == LEVEL_II_OPLOCK) {
-				num_level2 += 1;
-			}
-			if (num_level2 > 1) {
-				/*
-				 * No need to count them all...
-				 */
-				break;
-			}
-		}
-
-		if (num_level2 == 1) {
-			/*
-			 * That's only us. We are dropping that level2 oplock,
-			 * so remove the brlock flag.
-			 */
-			struct byte_range_lock *brl;
-
-			brl = brl_get_locks(talloc_tos(), fsp);
-			if (brl) {
-				brl_set_have_read_oplocks(brl, false);
-				TALLOC_FREE(brl);
-			}
-		}
-	}
-
 	ret = remove_share_oplock(lck, fsp);
 	if (!ret) {
 		DEBUG(0,("remove_oplock: failed to remove share oplock for "
@@ -216,6 +225,15 @@ bool remove_oplock(files_struct *fsp)
 			 file_id_string_tos(&fsp->file_id)));
 	}
 	release_file_oplock(fsp);
+
+	ret = update_num_read_oplocks(fsp, lck);
+	if (!ret) {
+		DEBUG(0, ("%s: update_num_read_oplocks failed for "
+			 "file %s, %s, %s\n",
+			  __func__, fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
+			 file_id_string_tos(&fsp->file_id)));
+	}
+
 	TALLOC_FREE(lck);
 	return ret;
 }
@@ -227,7 +245,6 @@ bool downgrade_oplock(files_struct *fsp)
 {
 	bool ret;
 	struct share_mode_lock *lck;
-	struct byte_range_lock *brl;
 
 	DEBUG(10, ("downgrade_oplock called for %s\n",
 		   fsp_str_dbg(fsp)));
@@ -245,13 +262,14 @@ bool downgrade_oplock(files_struct *fsp)
 			 fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
 			 file_id_string_tos(&fsp->file_id)));
 	}
-
 	downgrade_file_oplock(fsp);
 
-	brl = brl_get_locks(talloc_tos(), fsp);
-	if (brl != NULL) {
-		brl_set_have_read_oplocks(brl, true);
-		TALLOC_FREE(brl);
+	ret = update_num_read_oplocks(fsp, lck);
+	if (!ret) {
+		DEBUG(0, ("%s: update_num_read_oplocks failed for "
+			 "file %s, %s, %s\n",
+			  __func__, fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
+			 file_id_string_tos(&fsp->file_id)));
 	}
 
 	TALLOC_FREE(lck);
@@ -596,6 +614,7 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
 	struct tevent_immediate *im;
 	struct break_to_none_state *state;
 	struct byte_range_lock *brl;
+	uint32_t num_read_oplocks = 0;
 
 	/*
 	 * If this file is level II oplocked then we need
@@ -613,7 +632,13 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
 	}
 
 	brl = brl_get_locks_readonly(fsp);
-	if ((brl != NULL) && !brl_have_read_oplocks(brl)) {
+	if (brl != NULL) {
+		num_read_oplocks = brl_num_read_oplocks(brl);
+	}
+
+	DEBUG(10, ("num_read_oplocks = %"PRIu32"\n", num_read_oplocks));
+
+	if (num_read_oplocks == 0) {
 		DEBUG(10, ("No read oplocks around\n"));
 		return;
 	}
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 68c2da2..1080895 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -647,6 +647,8 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
 
 /* The following definitions come from smbd/oplock.c  */
 
+bool update_num_read_oplocks(files_struct *fsp, struct share_mode_lock *lck);
+
 void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp);
 NTSTATUS set_file_oplock(files_struct *fsp);
 bool remove_oplock(files_struct *fsp);
-- 
1.9.1
-------------- next part --------------
From dc28069df5e9ffc845d21e343de6e731d5ad8371 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 7 Nov 2014 17:16:01 +0100
Subject: [PATCH] metze revert sq after

---
 source3/smbd/open.c   |  82 ++++++++++++++++-------------------
 source3/smbd/oplock.c | 115 ++++++++++++++++++++------------------------------
 source3/smbd/proto.h  |   2 -
 3 files changed, 82 insertions(+), 117 deletions(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index acf06a3..ccea1e9 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1489,37 +1489,38 @@ static bool file_has_brlocks(files_struct *fsp)
 	return (brl_num_locks(br_lck) > 0);
 }
 
-static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
-				      struct files_struct *fsp,
-				      struct share_mode_lock *lck,
-				      int oplock_request)
+static void grant_fsp_oplock_type(files_struct *fsp,
+				  struct share_mode_lock *lck,
+				  int oplock_request)
 {
 	bool allow_level2 = (global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
 		            lp_level2_oplocks(SNUM(fsp->conn));
 	bool got_level2_oplock, got_a_none_oplock;
 	uint32_t i;
-	bool ok;
-	NTSTATUS status;
 
 	/* Start by granting what the client asked for,
 	   but ensure no SAMBA_PRIVATE bits can be set. */
 	fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK);
 
-	if (fsp->oplock_type == NO_OPLOCK) {
-		goto type_selected;
-	}
-
 	if (oplock_request & INTERNAL_OPEN_ONLY) {
 		/* No oplocks on internal open. */
 		fsp->oplock_type = NO_OPLOCK;
-		goto type_selected;
+		DEBUG(10,("grant_fsp_oplock_type: oplock type 0x%x on file %s\n",
+			fsp->oplock_type, fsp_str_dbg(fsp)));
+		return;
 	}
 
 	if (lp_locking(fsp->conn->params) && file_has_brlocks(fsp)) {
 		DEBUG(10,("grant_fsp_oplock_type: file %s has byte range locks\n",
 			fsp_str_dbg(fsp)));
 		fsp->oplock_type = NO_OPLOCK;
-		goto type_selected;
+	}
+
+	if (is_stat_open(fsp->access_mask)) {
+		/* Leave the value already set. */
+		DEBUG(10,("grant_fsp_oplock_type: oplock type 0x%x on file %s\n",
+			fsp->oplock_type, fsp_str_dbg(fsp)));
+		return;
 	}
 
 	got_level2_oplock = false;
@@ -1553,35 +1554,23 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req,
 	 */
 	if (fsp->oplock_type == LEVEL_II_OPLOCK && !allow_level2) {
 		fsp->oplock_type = NO_OPLOCK;
-		goto type_selected;
 	}
 
- type_selected:
-	status = set_file_oplock(fsp);
-	if (!NT_STATUS_IS_OK(status)) {
+	if (fsp->oplock_type == LEVEL_II_OPLOCK && !got_level2_oplock) {
 		/*
-		 * Could not get the kernel oplock
+		 * We're the first level2 oplock. Indicate that in brlock.tdb.
 		 */
-		fsp->oplock_type = NO_OPLOCK;
-	}
+		struct byte_range_lock *brl;
 
-	ok = set_share_mode(lck, fsp, get_current_uid(fsp->conn),
-			    req ? req->mid : 0,
-			    fsp->oplock_type);
-	if (!ok) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	ok = update_num_read_oplocks(fsp, lck);
-	if (!ok) {
-		del_share_mode(lck, fsp);
-		return NT_STATUS_INTERNAL_ERROR;
+		brl = brl_get_locks(talloc_tos(), fsp);
+		if (brl != NULL) {
+			brl_set_have_read_oplocks(brl, true);
+			TALLOC_FREE(brl);
+		}
 	}
 
 	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;
 }
 
 static bool request_timed_out(struct timeval request_time,
@@ -2749,6 +2738,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 		}
 	}
 
+	grant_fsp_oplock_type(fsp, lck, oplock_request);
+
 	/*
 	 * We have the share entry *locked*.....
 	 */
@@ -2808,18 +2799,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 	}
 
 	if (file_existed) {
-		/*
-		 * stat opens on existing files don't get oplocks.
-		 *
-		 * Note that we check for stat open on the *open_access_mask*,
-		 * i.e. the access mask we actually used to do the open,
-		 * not the one the client asked for (which is in
-		 * fsp->access_mask). This is due to the fact that
-		 * FILE_OVERWRITE and FILE_OVERWRITE_IF add in O_TRUNC,
-		 * which adds FILE_WRITE_DATA to open_access_mask.
-		 */
+		/* stat opens on existing files don't get oplocks. */
 		if (is_stat_open(open_access_mask)) {
-			oplock_request = NO_OPLOCK;
+			fsp->oplock_type = NO_OPLOCK;
 		}
 	}
 
@@ -2841,11 +2823,21 @@ 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);
+
+	status = set_file_oplock(fsp);
 	if (!NT_STATUS_IS_OK(status)) {
+		/*
+		 * Could not get the kernel oplock
+		 */
+		fsp->oplock_type = NO_OPLOCK;
+	}
+
+	if (!set_share_mode(lck, fsp, get_current_uid(conn),
+			    req ? req->mid : 0,
+			    fsp->oplock_type)) {
 		TALLOC_FREE(lck);
 		fd_close(fsp);
-		return status;
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	/* Handle strange delete on close create semantics. */
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index aa99f68..7935092 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -148,53 +148,6 @@ static void downgrade_file_oplock(files_struct *fsp)
 	TALLOC_FREE(fsp->oplock_timeout);
 }
 
-bool update_num_read_oplocks(files_struct *fsp, struct share_mode_lock *lck)
-{
-	struct share_mode_data *d = lck->data;
-	struct byte_range_lock *br_lck;
-	uint32_t num_read_oplocks = 0;
-	uint32_t i;
-
-	if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-		/*
-		 * If we're the only one, we don't need a brlock entry
-		 */
-		SMB_ASSERT(d->num_share_modes == 1);
-		SMB_ASSERT(EXCLUSIVE_OPLOCK_TYPE(d->share_modes[0].op_type));
-		return true;
-	}
-
-	for (i=0; i<d->num_share_modes; i++) {
-		struct share_mode_entry *e = &d->share_modes[i];
-
-		if (EXCLUSIVE_OPLOCK_TYPE(e->op_type)) {
-			num_read_oplocks += 1;
-			continue;
-		}
-
-		if (LEVEL_II_OPLOCK_TYPE(e->op_type)) {
-			num_read_oplocks += 1;
-			continue;
-		}
-	}
-
-	br_lck = brl_get_locks_readonly(fsp);
-	if (br_lck == NULL) {
-		return false;
-	}
-	if (brl_num_read_oplocks(br_lck) == num_read_oplocks) {
-		return true;
-	}
-
-	br_lck = brl_get_locks(talloc_tos(), fsp);
-	if (br_lck == NULL) {
-		return false;
-	}
-	brl_set_num_read_oplocks(br_lck, num_read_oplocks);
-	TALLOC_FREE(br_lck);
-	return true;
-}
-
 /****************************************************************************
  Remove a file oplock. Copes with level II and exclusive.
  Locks then unlocks the share mode lock. Client can decide to go directly
@@ -217,6 +170,44 @@ bool remove_oplock(files_struct *fsp)
 		return False;
 	}
 
+	if (fsp->oplock_type == LEVEL_II_OPLOCK) {
+
+		/*
+		 * If we're the only LEVEL_II holder, we have to remove the
+		 * have_read_oplocks from the brlock entry
+		 */
+
+		struct share_mode_data *data = lck->data;
+		uint32_t i, num_level2;
+
+		num_level2 = 0;
+		for (i=0; i<data->num_share_modes; i++) {
+			if (data->share_modes[i].op_type == LEVEL_II_OPLOCK) {
+				num_level2 += 1;
+			}
+			if (num_level2 > 1) {
+				/*
+				 * No need to count them all...
+				 */
+				break;
+			}
+		}
+
+		if (num_level2 == 1) {
+			/*
+			 * That's only us. We are dropping that level2 oplock,
+			 * so remove the brlock flag.
+			 */
+			struct byte_range_lock *brl;
+
+			brl = brl_get_locks(talloc_tos(), fsp);
+			if (brl) {
+				brl_set_have_read_oplocks(brl, false);
+				TALLOC_FREE(brl);
+			}
+		}
+	}
+
 	ret = remove_share_oplock(lck, fsp);
 	if (!ret) {
 		DEBUG(0,("remove_oplock: failed to remove share oplock for "
@@ -225,15 +216,6 @@ bool remove_oplock(files_struct *fsp)
 			 file_id_string_tos(&fsp->file_id)));
 	}
 	release_file_oplock(fsp);
-
-	ret = update_num_read_oplocks(fsp, lck);
-	if (!ret) {
-		DEBUG(0, ("%s: update_num_read_oplocks failed for "
-			 "file %s, %s, %s\n",
-			  __func__, fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
-			 file_id_string_tos(&fsp->file_id)));
-	}
-
 	TALLOC_FREE(lck);
 	return ret;
 }
@@ -245,6 +227,7 @@ bool downgrade_oplock(files_struct *fsp)
 {
 	bool ret;
 	struct share_mode_lock *lck;
+	struct byte_range_lock *brl;
 
 	DEBUG(10, ("downgrade_oplock called for %s\n",
 		   fsp_str_dbg(fsp)));
@@ -262,14 +245,13 @@ bool downgrade_oplock(files_struct *fsp)
 			 fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
 			 file_id_string_tos(&fsp->file_id)));
 	}
+
 	downgrade_file_oplock(fsp);
 
-	ret = update_num_read_oplocks(fsp, lck);
-	if (!ret) {
-		DEBUG(0, ("%s: update_num_read_oplocks failed for "
-			 "file %s, %s, %s\n",
-			  __func__, fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
-			 file_id_string_tos(&fsp->file_id)));
+	brl = brl_get_locks(talloc_tos(), fsp);
+	if (brl != NULL) {
+		brl_set_have_read_oplocks(brl, true);
+		TALLOC_FREE(brl);
 	}
 
 	TALLOC_FREE(lck);
@@ -614,7 +596,6 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
 	struct tevent_immediate *im;
 	struct break_to_none_state *state;
 	struct byte_range_lock *brl;
-	uint32_t num_read_oplocks = 0;
 
 	/*
 	 * If this file is level II oplocked then we need
@@ -632,13 +613,7 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
 	}
 
 	brl = brl_get_locks_readonly(fsp);
-	if (brl != NULL) {
-		num_read_oplocks = brl_num_read_oplocks(brl);
-	}
-
-	DEBUG(10, ("num_read_oplocks = %"PRIu32"\n", num_read_oplocks));
-
-	if (num_read_oplocks == 0) {
+	if ((brl != NULL) && !brl_have_read_oplocks(brl)) {
 		DEBUG(10, ("No read oplocks around\n"));
 		return;
 	}
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 1080895..68c2da2 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -647,8 +647,6 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
 
 /* The following definitions come from smbd/oplock.c  */
 
-bool update_num_read_oplocks(files_struct *fsp, struct share_mode_lock *lck);
-
 void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp);
 NTSTATUS set_file_oplock(files_struct *fsp);
 bool remove_oplock(files_struct *fsp);
-- 
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/20141107/037f5140/attachment.pgp>


More information about the samba-technical mailing list