Patchset: Remove FAKE_LEVEL_II_OPLOCK type

Volker Lendecke Volker.Lendecke at SerNet.DE
Fri Sep 13 16:51:53 CEST 2013


Hi!

Attached find a patchset that among other things removes the
FAKE_LEVEL_II_OPLOCK type. I think this makes our oplock
code more correct and also easier to understand.

Comments?

Thanks,

Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de

*****************************************************************
visit us on it-sa:IT security exhibitions in Nürnberg, Germany
October 8th - 10th 2013, hall 12, booth 333
free tickets available via code 270691 on: www.it-sa.de/gutschein
******************************************************************
-------------- next part --------------
From fe1d291f44221fccefc549c88118a46cd67fc87b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 13 Sep 2013 13:49:20 +0200
Subject: [PATCH 01/13] smbd: Use remove_oplock() in close_normal_file

remove_oplock is a wrapper around release_file_oplock. This streamlines
the API in oplock.c a bit.

Reason for this patch: In a later patch I will add functionality to
release_file_oplock that is required in close_normal_file as well.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/close.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index f341c72..6153066 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -735,7 +735,7 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
 
 	/* Remove the oplock before potentially deleting the file. */
 	if(fsp->oplock_type) {
-		release_file_oplock(fsp);
+		remove_oplock(fsp);
 	}
 
 	/* If this is an old DOS or FCB open and we have multiple opens on
-- 
1.7.9.5


From dea6b030fb0e9653fc92811235487cfaa47da0df Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 13 Sep 2013 13:55:05 +0200
Subject: [PATCH 02/13] smbd: Make release_file_oplock static

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/oplock.c |    2 +-
 source3/smbd/proto.h  |    1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 96c451c..0b90d92 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -95,7 +95,7 @@ NTSTATUS set_file_oplock(files_struct *fsp, int oplock_type)
  Attempt to release an oplock on a file. Decrements oplock count.
 ****************************************************************************/
 
-void release_file_oplock(files_struct *fsp)
+static void release_file_oplock(files_struct *fsp)
 {
 	struct smbd_server_connection *sconn = fsp->conn->sconn;
 	struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 54d6da0..bead710 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -660,7 +660,6 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
 
 void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp);
 NTSTATUS set_file_oplock(files_struct *fsp, int oplock_type);
-void release_file_oplock(files_struct *fsp);
 bool remove_oplock(files_struct *fsp);
 bool downgrade_oplock(files_struct *fsp);
 void contend_level2_oplocks_begin(files_struct *fsp,
-- 
1.7.9.5


From 7a53613f0d075e6162d22ffbf793e7bd8b4d8059 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 11 Sep 2013 09:31:36 +0000
Subject: [PATCH 03/13] smbd: Remove unused "brl->key" struct element

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/locking/brlock.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index adbfc5f..ee4354c 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -48,7 +48,6 @@ struct byte_range_lock {
 	unsigned int num_locks;
 	bool modified;
 	bool read_only;
-	struct file_id key;
 	struct lock_struct *lock_data;
 	struct db_record *record;
 };
@@ -1944,9 +1943,8 @@ static struct byte_range_lock *brl_get_locks_internal(TALLOC_CTX *mem_ctx,
 	br_lck->fsp = fsp;
 	br_lck->num_locks = 0;
 	br_lck->modified = False;
-	br_lck->key = fsp->file_id;
 
-	key.dptr = (uint8 *)&br_lck->key;
+	key.dptr = (uint8 *)&fsp->file_id;
 	key.dsize = sizeof(struct file_id);
 
 	if (!fsp->lockdb_clean) {
-- 
1.7.9.5


From 21e881163138492ad3dd184ea92e6183312d37b7 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 11 Sep 2013 10:17:05 +0000
Subject: [PATCH 04/13] smbd: Avoid an if-statement per read/write in the
 non-clustered case

Without clustering, fsp->brlock_rec will never be set anyway. In the
clustering case we can't use the seqnum trick, so this is slow enough
that the additional if-statement does not matter in this case anyway. In
the non-clustered case it might. Have not measured it, but every little
bit helps I guess.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/locking/brlock.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index ee4354c..a0b94cd 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -2062,15 +2062,15 @@ struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
 {
 	struct byte_range_lock *br_lock;
 
-	if (lp_clustering()) {
-		return brl_get_locks_internal(talloc_tos(), fsp, true);
-	}
-
 	if ((fsp->brlock_rec != NULL)
 	    && (dbwrap_get_seqnum(brlock_db) == fsp->brlock_seqnum)) {
 		return fsp->brlock_rec;
 	}
 
+	if (lp_clustering()) {
+		return brl_get_locks_internal(talloc_tos(), fsp, true);
+	}
+
 	TALLOC_FREE(fsp->brlock_rec);
 
 	br_lock = brl_get_locks_internal(talloc_tos(), fsp, true);
-- 
1.7.9.5


From 2f92b63263fd4e001d4030ea23ecf63ed4a2551a Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 11 Sep 2013 11:36:54 +0000
Subject: [PATCH 05/13] smbd: Restructure brl_get_locks_readonly

This is step 1 to get rid of brl_get_locks_internal with its complex readonly
business. It also optimizes 2 things: First, it uses dbwrap_parse_record to
avoid a talloc and memcpy, and second it uses talloc_pooled_object.

And -- hopefully it is easier to understand the caching logic with
fsp->brlock_rec and the clustering escape.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/locking/brlock.c |  113 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 103 insertions(+), 10 deletions(-)

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index a0b94cd..e0335dc 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -2058,30 +2058,123 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
 	return brl_get_locks_internal(mem_ctx, fsp, False);
 }
 
-struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
+struct brl_get_locks_readonly_state {
+	TALLOC_CTX *mem_ctx;
+	struct byte_range_lock **br_lock;
+};
+
+static void brl_get_locks_readonly_parser(TDB_DATA key, TDB_DATA data,
+					  void *private_data)
 {
+	struct brl_get_locks_readonly_state *state =
+		(struct brl_get_locks_readonly_state *)private_data;
 	struct byte_range_lock *br_lock;
 
+	br_lock = talloc_pooled_object(
+		state->mem_ctx, struct byte_range_lock, 1, data.dsize);
+	if (br_lock == 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);
+
+	*state->br_lock = br_lock;
+}
+
+struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
+{
+	struct byte_range_lock *br_lock = NULL;
+	struct byte_range_lock *rw = NULL;
+
 	if ((fsp->brlock_rec != NULL)
 	    && (dbwrap_get_seqnum(brlock_db) == fsp->brlock_seqnum)) {
+		/*
+		 * We have cached the brlock_rec and the database did not
+		 * change.
+		 */
 		return fsp->brlock_rec;
 	}
 
-	if (lp_clustering()) {
-		return brl_get_locks_internal(talloc_tos(), fsp, true);
+	if (!fsp->lockdb_clean) {
+		/*
+		 * Fetch the record in R/W mode to give validate_lock_entries
+		 * a chance to kick in once.
+		 */
+		rw = brl_get_locks_internal(talloc_tos(), fsp, false);
+		if (rw == NULL) {
+			return NULL;
+		}
+		fsp->lockdb_clean = true;
 	}
 
-	TALLOC_FREE(fsp->brlock_rec);
+	if (rw != NULL) {
+		size_t lock_data_size;
 
-	br_lock = brl_get_locks_internal(talloc_tos(), fsp, true);
-	if (br_lock == NULL) {
-		return NULL;
+		/*
+		 * Make a copy of the already retrieved and sanitized rw record
+		 */
+		lock_data_size = rw->num_locks * sizeof(struct lock_struct);
+		br_lock = talloc_pooled_object(
+			fsp, struct byte_range_lock, 1, lock_data_size);
+		if (br_lock == NULL) {
+			goto fail;
+		}
+		br_lock->num_locks = rw->num_locks;
+		br_lock->lock_data = (struct lock_struct *)talloc_memdup(
+			br_lock, rw->lock_data, lock_data_size);
+	} else {
+		struct brl_get_locks_readonly_state state;
+		NTSTATUS status;
+
+		/*
+		 * Parse the record fresh from the database
+		 */
+
+		state.mem_ctx = fsp;
+		state.br_lock = &br_lock;
+
+		status = dbwrap_parse_record(
+			brlock_db,
+			make_tdb_data((uint8_t *)&fsp->file_id,
+				      sizeof(fsp->file_id)),
+			brl_get_locks_readonly_parser, &state);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(3, ("Could not parse byte range lock record: "
+				  "%s\n", nt_errstr(status)));
+			goto fail;
+		}
+		if (br_lock == NULL) {
+			goto fail;
+		}
 	}
-	fsp->brlock_seqnum = dbwrap_get_seqnum(brlock_db);
 
-	fsp->brlock_rec = talloc_move(fsp, &br_lock);
+	br_lock->fsp = fsp;
+	br_lock->modified = false;
+	br_lock->read_only = true;
+	br_lock->record = NULL;
+
+	if (lp_clustering()) {
+		/*
+		 * In the cluster case we can't cache the brlock struct
+		 * because dbwrap_get_seqnum does not work reliably over
+		 * ctdb. Thus we have to throw away the brlock struct soon.
+		 */
+		talloc_steal(talloc_tos(), br_lock);
+	} else {
+		/*
+		 * Cache the brlock struct, invalidated when the dbwrap_seqnum
+		 * changes. See beginning of this routine.
+		 */
+		TALLOC_FREE(fsp->brlock_rec);
+		fsp->brlock_rec = br_lock;
+		fsp->brlock_seqnum = dbwrap_get_seqnum(brlock_db);
+	}
 
-	return fsp->brlock_rec;
+fail:
+	TALLOC_FREE(rw);
+	return br_lock;
 }
 
 struct brl_revalidate_state {
-- 
1.7.9.5


From 0a8e324d44bdde50d8682524bfef167cb1e6ec7e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 11 Sep 2013 11:51:44 +0000
Subject: [PATCH 06/13] smbd: brl_get_locks_internal is always called r/w now

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/locking/brlock.c |   48 +++++++++++-----------------------------------
 1 file changed, 11 insertions(+), 37 deletions(-)

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index e0335dc..f57c7e5 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -1930,11 +1930,10 @@ static int byte_range_lock_destructor(struct byte_range_lock *br_lck)
 ********************************************************************/
 
 static struct byte_range_lock *brl_get_locks_internal(TALLOC_CTX *mem_ctx,
-					files_struct *fsp, bool read_only)
+						      files_struct *fsp)
 {
 	TDB_DATA key, data;
 	struct byte_range_lock *br_lck = talloc(mem_ctx, struct byte_range_lock);
-	bool do_read_only = read_only;
 
 	if (br_lck == NULL) {
 		return NULL;
@@ -1947,40 +1946,23 @@ static struct byte_range_lock *brl_get_locks_internal(TALLOC_CTX *mem_ctx,
 	key.dptr = (uint8 *)&fsp->file_id;
 	key.dsize = sizeof(struct file_id);
 
-	if (!fsp->lockdb_clean) {
-		/* We must be read/write to clean
-		   the dead entries. */
-		do_read_only = false;
-	}
-
-	if (do_read_only) {
-		NTSTATUS status;
-		status = dbwrap_fetch(brlock_db, br_lck, key, &data);
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(3, ("Could not fetch byte range lock record\n"));
-			TALLOC_FREE(br_lck);
-			return NULL;
-		}
-		br_lck->record = NULL;
-	} else {
-		br_lck->record = dbwrap_fetch_locked(brlock_db, br_lck, key);
-
-		if (br_lck->record == NULL) {
-			DEBUG(3, ("Could not lock byte range lock entry\n"));
-			TALLOC_FREE(br_lck);
-			return NULL;
-		}
+	br_lck->record = dbwrap_fetch_locked(brlock_db, br_lck, key);
 
-		data = dbwrap_record_get_value(br_lck->record);
+	if (br_lck->record == NULL) {
+		DEBUG(3, ("Could not lock byte range lock entry\n"));
+		TALLOC_FREE(br_lck);
+		return NULL;
 	}
 
+	data = dbwrap_record_get_value(br_lck->record);
+
 	if ((data.dsize % sizeof(struct lock_struct)) != 0) {
 		DEBUG(3, ("Got invalid brlock data\n"));
 		TALLOC_FREE(br_lck);
 		return NULL;
 	}
 
-	br_lck->read_only = do_read_only;
+	br_lck->read_only = false;
 	br_lck->lock_data = NULL;
 
 	talloc_set_destructor(br_lck, byte_range_lock_destructor);
@@ -2041,21 +2023,13 @@ static struct byte_range_lock *brl_get_locks_internal(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (do_read_only != read_only) {
-		/*
-		 * this stores the record and gets rid of
-		 * the write lock that is needed for a cleanup
-		 */
-		byte_range_lock_flush(br_lck);
-	}
-
 	return br_lck;
 }
 
 struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
 					files_struct *fsp)
 {
-	return brl_get_locks_internal(mem_ctx, fsp, False);
+	return brl_get_locks_internal(mem_ctx, fsp);
 }
 
 struct brl_get_locks_readonly_state {
@@ -2102,7 +2076,7 @@ struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
 		 * Fetch the record in R/W mode to give validate_lock_entries
 		 * a chance to kick in once.
 		 */
-		rw = brl_get_locks_internal(talloc_tos(), fsp, false);
+		rw = brl_get_locks_internal(talloc_tos(), fsp);
 		if (rw == NULL) {
 			return NULL;
 		}
-- 
1.7.9.5


From 5fb0d16ce7eee39083358d10154d4b51fee36386 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 11 Sep 2013 11:53:26 +0000
Subject: [PATCH 07/13] smbd: Remove the brl_get_locks wrapper

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/locking/brlock.c |   11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index f57c7e5..78315bc 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -1929,8 +1929,7 @@ static int byte_range_lock_destructor(struct byte_range_lock *br_lck)
  TALLOC_FREE(brl) will release the lock in the destructor.
 ********************************************************************/
 
-static struct byte_range_lock *brl_get_locks_internal(TALLOC_CTX *mem_ctx,
-						      files_struct *fsp)
+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);
@@ -2026,12 +2025,6 @@ static struct byte_range_lock *brl_get_locks_internal(TALLOC_CTX *mem_ctx,
 	return br_lck;
 }
 
-struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
-					files_struct *fsp)
-{
-	return brl_get_locks_internal(mem_ctx, fsp);
-}
-
 struct brl_get_locks_readonly_state {
 	TALLOC_CTX *mem_ctx;
 	struct byte_range_lock **br_lock;
@@ -2076,7 +2069,7 @@ struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
 		 * Fetch the record in R/W mode to give validate_lock_entries
 		 * a chance to kick in once.
 		 */
-		rw = brl_get_locks_internal(talloc_tos(), fsp);
+		rw = brl_get_locks(talloc_tos(), fsp);
 		if (rw == NULL) {
 			return NULL;
 		}
-- 
1.7.9.5


From ce585dbaf00aaaad18afd27a949f877b014c727b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 11 Sep 2013 11:54:37 +0000
Subject: [PATCH 08/13] smbd: Remove byte_range_lock->read_only

With the rewritten brl_get_lock_readonly we only set the destructor for
r/w lock records anyway.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/locking/brlock.c |   10 ----------
 1 file changed, 10 deletions(-)

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index 78315bc..0d45501 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -47,7 +47,6 @@ struct byte_range_lock {
 	struct files_struct *fsp;
 	unsigned int num_locks;
 	bool modified;
-	bool read_only;
 	struct lock_struct *lock_data;
 	struct db_record *record;
 };
@@ -1879,10 +1878,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)
 {
-	if (br_lck->read_only) {
-		SMB_ASSERT(!br_lck->modified);
-	}
-
 	if (!br_lck->modified) {
 		goto done;
 	}
@@ -1910,10 +1905,7 @@ static void byte_range_lock_flush(struct byte_range_lock *br_lck)
 	}
 
  done:
-
-	br_lck->read_only = true;
 	br_lck->modified = false;
-
 	TALLOC_FREE(br_lck->record);
 }
 
@@ -1961,7 +1953,6 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, files_struct *fsp)
 		return NULL;
 	}
 
-	br_lck->read_only = false;
 	br_lck->lock_data = NULL;
 
 	talloc_set_destructor(br_lck, byte_range_lock_destructor);
@@ -2119,7 +2110,6 @@ struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
 
 	br_lock->fsp = fsp;
 	br_lock->modified = false;
-	br_lock->read_only = true;
 	br_lock->record = NULL;
 
 	if (lp_clustering()) {
-- 
1.7.9.5


From 69561b1243990f97a75a4f9020f34127e5b9c4aa Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 11 Sep 2013 12:48:14 +0000
Subject: [PATCH 09/13] smbd: Put "have_level2_oplocks" into brlock.tdb

This implements an idea by metze: Right now Samba does not grant level2
oplocks where it should: After an initial no-oplock open that has been
written to, we don't have the FAKE_LEVEL2_OPLOCK entry in locking.tdb
around anymore, this downgraded to NO_OPLOCK. Windows in this case will
grant level2 if being asked, we don't.  Part of the reason for this
is that we don't have a proper mechanism to communicate the fact that
level2 needs to be broken to other smbds. Metze's insight was that we
have to look into brlock.tdb for every write anyway, so this might be
the right place to store this information.

My first reaction was that this is really hackish, but on further thought
this is not. oplocks depend on brlocks anyway, and we have the proper
mechanisms in place for brlocks.

The format for this change is to add one byte to the end of the brlock.tdb
record with value 1 if we have level2 oplocks around. Thus this patch
effectively reverts 8f41142 which I discovered while writing this
change. We now legally have unaligned records.

We can certainly talk about the format, but I'm not yet convinced we
need an idl for this yet. This is a potentially very hot code path,
and ndr marshalling has a cost.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/locking/brlock.c |   55 +++++++++++++++++++++++++++++++++++++---------
 source3/locking/proto.h  |    3 +++
 2 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index 0d45501..500b7f1 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -47,6 +47,7 @@ struct byte_range_lock {
 	struct files_struct *fsp;
 	unsigned int num_locks;
 	bool modified;
+	bool have_level2_oplocks;
 	struct lock_struct *lock_data;
 	struct db_record *record;
 };
@@ -81,6 +82,19 @@ struct files_struct *brl_fsp(struct byte_range_lock *brl)
 	return brl->fsp;
 }
 
+bool brl_have_level2_oplocks(const struct byte_range_lock *brl)
+{
+	return brl->have_level2_oplocks;
+}
+
+void brl_set_have_level2_oplocks(struct byte_range_lock *brl,
+				 bool have_level2)
+{
+	SMB_ASSERT(brl->record != NULL); /* otherwise we're readonly */
+	brl->have_level2_oplocks = have_level2;
+	brl->modified = true;
+}
+
 /****************************************************************************
  See if two locking contexts are equal.
 ****************************************************************************/
@@ -1878,11 +1892,18 @@ 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;
 	if (!br_lck->modified) {
 		goto done;
 	}
 
-	if (br_lck->num_locks == 0) {
+	data_len = br_lck->num_locks * sizeof(struct lock_struct);
+
+	if (br_lck->have_level2_oplocks) {
+		data_len += 1;
+	}
+
+	if (data_len == 0) {
 		/* No locks - delete this entry. */
 		NTSTATUS status = dbwrap_record_delete(br_lck->record);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -1894,10 +1915,19 @@ static void byte_range_lock_flush(struct byte_range_lock *br_lck)
 		TDB_DATA data;
 		NTSTATUS status;
 
-		data.dptr = (uint8 *)br_lck->lock_data;
-		data.dsize = br_lck->num_locks * sizeof(struct lock_struct);
+		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_level2_oplocks) {
+			data.dptr[data_len-1] = 1;
+		}
 
 		status = dbwrap_record_store(br_lck->record, data, TDB_REPLACE);
+		TALLOC_FREE(data.dptr);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(0, ("store returned %s\n", nt_errstr(status)));
 			smb_panic("Could not store byte range mode entry");
@@ -1932,6 +1962,7 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, files_struct *fsp)
 
 	br_lck->fsp = fsp;
 	br_lck->num_locks = 0;
+	br_lck->have_level2_oplocks = false;
 	br_lck->modified = False;
 
 	key.dptr = (uint8 *)&fsp->file_id;
@@ -1947,12 +1978,6 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, files_struct *fsp)
 
 	data = dbwrap_record_get_value(br_lck->record);
 
-	if ((data.dsize % sizeof(struct lock_struct)) != 0) {
-		DEBUG(3, ("Got invalid brlock data\n"));
-		TALLOC_FREE(br_lck);
-		return NULL;
-	}
-
 	br_lck->lock_data = NULL;
 
 	talloc_set_destructor(br_lck, byte_range_lock_destructor);
@@ -1968,7 +1993,12 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, files_struct *fsp)
 			return NULL;
 		}
 
-		memcpy(br_lck->lock_data, data.dptr, data.dsize);
+		memcpy(br_lck->lock_data, data.dptr,
+		       talloc_get_size(br_lck->lock_data));
+	}
+
+	if ((data.dsize % sizeof(struct lock_struct)) == 1) {
+		br_lck->have_level2_oplocks = (data.dptr[data.dsize-1] == 1);
 	}
 
 	if (!fsp->lockdb_clean) {
@@ -2038,6 +2068,10 @@ static void brl_get_locks_readonly_parser(TDB_DATA key, TDB_DATA data,
 		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_level2_oplocks = (data.dptr[data.dsize-1] == 1);
+	}
+
 	*state->br_lock = br_lock;
 }
 
@@ -2079,6 +2113,7 @@ struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
 		if (br_lock == NULL) {
 			goto fail;
 		}
+		br_lock->have_level2_oplocks = rw->have_level2_oplocks;
 		br_lock->num_locks = rw->num_locks;
 		br_lock->lock_data = (struct lock_struct *)talloc_memdup(
 			br_lock, rw->lock_data, lock_data_size);
diff --git a/source3/locking/proto.h b/source3/locking/proto.h
index 1573f6b..d5ff1d6 100644
--- a/source3/locking/proto.h
+++ b/source3/locking/proto.h
@@ -30,6 +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_level2_oplocks(const struct byte_range_lock *brl);
+void brl_set_have_level2_oplocks(struct byte_range_lock *brl,
+				 bool have_level2);
 
 NTSTATUS brl_lock_windows_default(struct byte_range_lock *br_lck,
 		struct lock_struct *plock,
-- 
1.7.9.5


From e73d0e0c838214c34a63488a739a212f64bf9840 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 11 Sep 2013 16:07:33 +0000
Subject: [PATCH 10/13] smbd: Remove FAKE_LEVEL_II_OPLOCK

FAKE_LEVEL_II_OPLOCK was an indicator to break level2 oplock holders
on write.  This information is now being held in brlock.tdb, which makes
the FAKE_LEVEL_II_OPLOCK type unnecessary.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/smb.h     |    5 ++--
 source3/locking/locking.c |   14 +--------
 source3/smbd/files.c      |    3 +-
 source3/smbd/open.c       |   41 ++++++++++---------------
 source3/smbd/oplock.c     |   73 ++++++++++++++++++++++++++++++++++-----------
 5 files changed, 77 insertions(+), 59 deletions(-)

diff --git a/source3/include/smb.h b/source3/include/smb.h
index 1288222..3afd176 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -678,7 +678,8 @@ enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT,
 
 /* The following are Samba-private. */
 #define INTERNAL_OPEN_ONLY 		0x8
-#define FAKE_LEVEL_II_OPLOCK 		0x10	/* Client requested no_oplock, but we have to
+/* #define FAKE_LEVEL_II_OPLOCK 	0x10 */	  /* Not used anymore */
+				/* Client requested no_oplock, but we have to
 				 * inform potential level2 holders on
 				 * write. */
 /* #define DEFERRED_OPEN_ENTRY 		0x20 */   /* Not used anymore */
@@ -690,7 +691,7 @@ enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT,
 
 #define EXCLUSIVE_OPLOCK_TYPE(lck) ((lck) & ((unsigned int)EXCLUSIVE_OPLOCK|(unsigned int)BATCH_OPLOCK))
 #define BATCH_OPLOCK_TYPE(lck) ((lck) & (unsigned int)BATCH_OPLOCK)
-#define LEVEL_II_OPLOCK_TYPE(lck) ((lck) & ((unsigned int)LEVEL_II_OPLOCK|(unsigned int)FAKE_LEVEL_II_OPLOCK))
+#define LEVEL_II_OPLOCK_TYPE(lck) ((lck) & (unsigned int)LEVEL_II_OPLOCK)
 
 /* kernel_oplock_message definition.
 
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index d4c68f8..bba8e8c 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -841,19 +841,7 @@ bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
 		return False;
 	}
 
-	if (EXCLUSIVE_OPLOCK_TYPE(e->op_type)) {
-		/*
-		 * Going from exclusive or batch,
- 		 * we always go through FAKE_LEVEL_II
- 		 * first.
- 		 */
-		if (!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-			smb_panic("remove_share_oplock: logic error");
-		}
-		e->op_type = FAKE_LEVEL_II_OPLOCK;
-	} else {
-		e->op_type = NO_OPLOCK;
-	}
+	e->op_type = NO_OPLOCK;
 	lck->data->modified = True;
 	return True;
 }
diff --git a/source3/smbd/files.c b/source3/smbd/files.c
index d94ee11..c64c841 100644
--- a/source3/smbd/files.c
+++ b/source3/smbd/files.c
@@ -318,8 +318,7 @@ files_struct *file_find_dif(struct smbd_server_connection *sconn,
 			}
 			/* Paranoia check. */
 			if ((fsp->fh->fd == -1) &&
-			    (fsp->oplock_type != NO_OPLOCK) &&
-			    (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) {
+			    (fsp->oplock_type != NO_OPLOCK)) {
 				DEBUG(0,("file_find_dif: file %s file_id = "
 					 "%s, gen = %u oplock_type = %u is a "
 					 "stat open with oplock type !\n",
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 1a86233..e75edcc 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1052,14 +1052,6 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
 			  "share entry with an open file\n");
 	}
 
-	if ((share_entry->op_type == NO_OPLOCK) &&
-	    (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK))
-	{
-		/* Someone has already written to it, but I haven't yet
-		 * noticed */
-		return;
-	}
-
 	if (((uint16)fsp->oplock_type) != share_entry->op_type) {
 		goto panic;
 	}
@@ -1409,24 +1401,10 @@ static void grant_fsp_oplock_type(files_struct *fsp,
  	 * what was found in the existing share modes.
  	 */
 
-	if (got_a_none_oplock) {
-		fsp->oplock_type = NO_OPLOCK;
-	} else if (got_level2_oplock) {
-		if (fsp->oplock_type == NO_OPLOCK ||
-				fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) {
-			/* Store a level2 oplock, but don't tell the client */
-			fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
-		} else {
+	if (got_level2_oplock || got_a_none_oplock) {
+		if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
 			fsp->oplock_type = LEVEL_II_OPLOCK;
 		}
-	} else {
-		/* All share_mode_entries are placeholders or deferred.
-		 * Silently upgrade to fake levelII if the client didn't
-		 * ask for an oplock. */
-		if (fsp->oplock_type == NO_OPLOCK) {
-			/* Store a level2 oplock, but don't tell the client */
-			fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
-		}
 	}
 
 	/*
@@ -1434,7 +1412,20 @@ static void grant_fsp_oplock_type(files_struct *fsp,
 	 * or if we've turned them off.
 	 */
 	if (fsp->oplock_type == LEVEL_II_OPLOCK && !allow_level2) {
-		fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+		fsp->oplock_type = NO_OPLOCK;
+	}
+
+	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_level2_oplocks(brl, true);
+			TALLOC_FREE(brl);
+		}
 	}
 
 	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 0b90d92..571a7de 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -67,7 +67,6 @@ NTSTATUS set_file_oplock(files_struct *fsp, int oplock_type)
 	}
 
 	if ((fsp->oplock_type != NO_OPLOCK) &&
-	    (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
 	    use_kernel &&
 	    !koplocks->ops->set_oplock(koplocks, fsp, oplock_type))
 	{
@@ -101,7 +100,6 @@ static void release_file_oplock(files_struct *fsp)
 	struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
 
 	if ((fsp->oplock_type != NO_OPLOCK) &&
-	    (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
 	    koplocks) {
 		koplocks->ops->release_oplock(koplocks, fsp, NO_OPLOCK);
 	}
@@ -115,12 +113,7 @@ static void release_file_oplock(files_struct *fsp)
 	SMB_ASSERT(sconn->oplocks.exclusive_open>=0);
 	SMB_ASSERT(sconn->oplocks.level_II_open>=0);
 
-	if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-		/* This doesn't matter for close. */
-		fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
-	} else {
-		fsp->oplock_type = NO_OPLOCK;
-	}
+	fsp->oplock_type = NO_OPLOCK;
 	fsp->sent_oplock_break = NO_BREAK_SENT;
 
 	flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH);
@@ -172,6 +165,45 @@ bool remove_oplock(files_struct *fsp)
 			 "file %s\n", fsp_str_dbg(fsp)));
 		return False;
 	}
+
+	if (fsp->oplock_type == LEVEL_II_OPLOCK) {
+
+		/*
+		 * If we're the only LEVEL_II holder, we have to remove the
+		 * have_level2_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_level2_oplocks(brl, false);
+				TALLOC_FREE(brl);
+			}
+		}
+	}
+
 	ret = remove_share_oplock(lck, fsp);
 	if (!ret) {
 		DEBUG(0,("remove_oplock: failed to remove share oplock for "
@@ -191,6 +223,7 @@ bool downgrade_oplock(files_struct *fsp)
 {
 	bool ret;
 	struct share_mode_lock *lck;
+	struct byte_range_lock *brl;
 
 	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
 	if (lck == NULL) {
@@ -207,6 +240,13 @@ bool downgrade_oplock(files_struct *fsp)
 	}
 
 	downgrade_file_oplock(fsp);
+
+	brl = brl_get_locks(talloc_tos(), fsp);
+	if (brl != NULL) {
+		brl_set_have_level2_oplocks(brl, true);
+		TALLOC_FREE(brl);
+	}
+
 	TALLOC_FREE(lck);
 	return ret;
 }
@@ -383,14 +423,6 @@ static void break_level2_to_none_async(files_struct *fsp)
 		return;
 	}
 
-	if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) {
-		/* Don't tell the client, just downgrade. */
-		DEBUG(3, ("process_oplock_async_level2_break_message: "
-			  "downgrading fake level 2 oplock.\n"));
-		remove_oplock(fsp);
-		return;
-	}
-
 	/* Ensure we're really at level2 state. */
 	SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK);
 
@@ -630,6 +662,7 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
 	struct smbd_server_connection *sconn = fsp->conn->sconn;
 	struct tevent_immediate *im;
 	struct break_to_none_state *state;
+	struct byte_range_lock *brl;
 
 	/*
 	 * If this file is level II oplocked then we need
@@ -639,8 +672,14 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
 	 * the shared memory area whilst doing this.
 	 */
 
-	if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+	brl = brl_get_locks_readonly(fsp);
+	if (brl == NULL) {
+		/* Can't tell if we have to downgrade level2 oplocks */
 		return;
+	}
+	if (!brl_have_level2_oplocks(brl)) {
+		return;
+	}
 
 	/*
 	 * When we get here we might have a brlock entry locked. Also
-- 
1.7.9.5


From c81f75e0c9de53ad6db2942e63d107f4ce8187d9 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 9 Sep 2013 18:53:15 +0000
Subject: [PATCH 11/13] torture: Extend raw.oplock.batch10

With FAKE_LEVEL_II_OPLOCKS around we did not grant LEVEL2 after
a NO_OPLOCK file got written to. Windows does grant LEVEL2 in this
case. With the have_level2_oplocks in brlocks.tdb we can now grant LEVEL2
in this case as well.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/torture/raw/oplock.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c
index c2e086a..ef9f973 100644
--- a/source4/torture/raw/oplock.c
+++ b/source4/torture/raw/oplock.c
@@ -1696,6 +1696,18 @@ static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_
 	CHECK_VAL(break_info.failures, 0);
 	CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
 
+	{
+		union smb_write wr;
+		wr.write.level = RAW_WRITE_WRITE;
+		wr.write.in.file.fnum = fnum;
+		wr.write.in.count = 1;
+		wr.write.in.offset = 0;
+		wr.write.in.remaining = 0;
+		wr.write.in.data = (const uint8_t *)"x";
+		status = smb_raw_write(cli1->tree, &wr);
+		CHECK_STATUS(tctx, status, NT_STATUS_OK);
+	}
+
 	smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
 
 	io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
-- 
1.7.9.5


From 774c3e8bbf6bc8416d97f62b59c19a1e84d5c6a9 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 13 Sep 2013 14:13:51 +0200
Subject: [PATCH 12/13] smbd: Add debugs to brlock.c

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/locking/brlock.c |   15 +++++++++++++++
 source3/smbd/oplock.c    |    8 ++++++++
 2 files changed, 23 insertions(+)

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index 500b7f1..d59ba2d 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -90,6 +90,8 @@ bool brl_have_level2_oplocks(const struct byte_range_lock *brl)
 void brl_set_have_level2_oplocks(struct byte_range_lock *brl,
 				 bool have_level2)
 {
+	DEBUG(10, ("Setting have_level2 to %s\n",
+		   have_level2 ? "true" : "false"));
 	SMB_ASSERT(brl->record != NULL); /* otherwise we're readonly */
 	brl->have_level2_oplocks = have_level2;
 	brl->modified = true;
@@ -1894,6 +1896,7 @@ static void byte_range_lock_flush(struct byte_range_lock *br_lck)
 {
 	size_t data_len;
 	if (!br_lck->modified) {
+		DEBUG(10, ("br_lck not modified\n"));
 		goto done;
 	}
 
@@ -1903,6 +1906,8 @@ static void byte_range_lock_flush(struct byte_range_lock *br_lck)
 		data_len += 1;
 	}
 
+	DEBUG(10, ("data_len=%d\n", (int)data_len));
+
 	if (data_len == 0) {
 		/* No locks - delete this entry. */
 		NTSTATUS status = dbwrap_record_delete(br_lck->record);
@@ -1934,6 +1939,8 @@ static void byte_range_lock_flush(struct byte_range_lock *br_lck)
 		}
 	}
 
+	DEBUG(10, ("seqnum=%d\n", dbwrap_get_seqnum(brlock_db)));
+
  done:
 	br_lck->modified = false;
 	TALLOC_FREE(br_lck->record);
@@ -1997,6 +2004,8 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, files_struct *fsp)
 		       talloc_get_size(br_lck->lock_data));
 	}
 
+	DEBUG(10, ("data.dsize=%d\n", (int)data.dsize));
+
 	if ((data.dsize % sizeof(struct lock_struct)) == 1) {
 		br_lck->have_level2_oplocks = (data.dptr[data.dsize-1] == 1);
 	}
@@ -2072,6 +2081,9 @@ static void brl_get_locks_readonly_parser(TDB_DATA key, TDB_DATA data,
 		br_lock->have_level2_oplocks = (data.dptr[data.dsize-1] == 1);
 	}
 
+	DEBUG(10, ("Got %d bytes, have_level2: %s\n", (int)data.dsize,
+		   br_lock->have_level2_oplocks ? "true" : "false"));
+
 	*state->br_lock = br_lock;
 }
 
@@ -2080,6 +2092,9 @@ struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp)
 	struct byte_range_lock *br_lock = NULL;
 	struct byte_range_lock *rw = NULL;
 
+	DEBUG(10, ("seqnum=%d, fsp->brlock_seqnum=%d\n",
+		   dbwrap_get_seqnum(brlock_db), fsp->brlock_seqnum));
+
 	if ((fsp->brlock_rec != NULL)
 	    && (dbwrap_get_seqnum(brlock_db) == fsp->brlock_seqnum)) {
 		/*
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 571a7de..a3a3f40 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -158,6 +158,9 @@ bool remove_oplock(files_struct *fsp)
 	bool ret;
 	struct share_mode_lock *lck;
 
+	DEBUG(10, ("remove_oplock called for %s\n",
+		   fsp_str_dbg(fsp)));
+
 	/* Remove the oplock flag from the sharemode. */
 	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
 	if (lck == NULL) {
@@ -225,6 +228,9 @@ bool downgrade_oplock(files_struct *fsp)
 	struct share_mode_lock *lck;
 	struct byte_range_lock *brl;
 
+	DEBUG(10, ("downgrade_oplock called for %s\n",
+		   fsp_str_dbg(fsp)));
+
 	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
 	if (lck == NULL) {
 		DEBUG(0,("downgrade_oplock: failed to lock share entry for "
@@ -674,10 +680,12 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
 
 	brl = brl_get_locks_readonly(fsp);
 	if (brl == NULL) {
+		DEBUG(10, ("brl_get_locks_readonly returned nothing\n"));
 		/* Can't tell if we have to downgrade level2 oplocks */
 		return;
 	}
 	if (!brl_have_level2_oplocks(brl)) {
+		DEBUG(10, ("No level2 oplocks around\n"));
 		return;
 	}
 
-- 
1.7.9.5


From d8ebfe45b17004555f78b4d6c1b2c42c80a2beec Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 13 Sep 2013 15:18:15 +0200
Subject: [PATCH 13/13] smbd: Remove some FAKE_LEVEL_II comments

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/oplock.c      |    6 +++---
 source3/smbd/smb2_create.c |    5 -----
 2 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index a3a3f40..cb9b598 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -450,8 +450,8 @@ static void break_level2_to_none_async(files_struct *fsp)
 /*******************************************************************
  This handles the case of a write triggering a break to none
  message on a level2 oplock.
- When we get this message we may be in any of three states :
- NO_OPLOCK, LEVEL_II, FAKE_LEVEL2. We only send a message to
+ When we get this message we may be in any of two states :
+ NO_OPLOCK, LEVEL_II. We only send a message to
  the client for LEVEL2.
 *******************************************************************/
 
@@ -746,7 +746,7 @@ static void do_break_to_none(struct tevent_context *ctx,
 		 * As there could have been multiple writes waiting at the
 		 * lock_share_entry gate we may not be the first to
 		 * enter. Hence the state of the op_types in the share mode
-		 * entries may be partly NO_OPLOCK and partly LEVEL_II or FAKE_LEVEL_II
+		 * entries may be partly NO_OPLOCK and partly LEVEL_II
 		 * oplock. It will do no harm to re-send break messages to
 		 * those smbd's that are still waiting their turn to remove
 		 * their LEVEL_II state, and also no harm to ignore existing
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 4f2edfc..11259a0 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -58,11 +58,6 @@ static uint8_t map_samba_oplock_levels_to_smb2(int oplock_type)
 	} else if (EXCLUSIVE_OPLOCK_TYPE(oplock_type)) {
 		return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
 	} else if (oplock_type == LEVEL_II_OPLOCK) {
-		/*
-		 * Don't use LEVEL_II_OPLOCK_TYPE here as
-		 * this also includes FAKE_LEVEL_II_OPLOCKs
-		 * which are internal only.
-		 */
 		return SMB2_OPLOCK_LEVEL_II;
 	} else {
 		return SMB2_OPLOCK_LEVEL_NONE;
-- 
1.7.9.5



More information about the samba-technical mailing list