Patchset: Remove FAKE_LEVEL_II_OPLOCK type

Volker Lendecke Volker.Lendecke at SerNet.DE
Thu Sep 26 02:04:57 CEST 2013


On Fri, Sep 13, 2013 at 06:53:06PM +0200, Stefan (metze) Metzmacher wrote:
> Hi Volker,
> 
> this looks really great, thanks! This looks like a big step in the direction
> of supporting leases:-)
> 
> > 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.
> 
> What is the exact reason why the seqnum trick doesn't work in cluster mode.
> I see that there might be cases where we would reload to often
> because the seqnum on the local tdb also changes if a record get migrated
> or a recovery happened. But wouldn't the exact same seqnum doesn't mean
> we could also change in cluster mode?

Well, true. Need to think about this. For now, I would like
to leave it as it is.

> > Subject: [PATCH 09/13] smbd: Put "have_level2_oplocks" into brlock.tdb
> 
> If possible I'd prefer the name 'read_oplocks' instead of 'level2_oplocks'
> for the new functions variable, so that we don't have to rename them
> when we get leases.

Done.

> > 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.
> 
> What about adding a uint32_t and use it as flags field, we may want to
> store more information
> in future.

We could, but I think 8 bits are okay for now, given that we
only use 1. This is relatively easy to change, there are soo
many changes pending right now that we can't take care of
rolling code upgrades at this point.

> > @@ -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))
> 
> I'd keep the optimization by using
> 
> if (EXCLUSIVE_OPLOCK_TYPE(fsp->ofsp->oplock_type)) {
>      return;
> }

Done.

> > +	brl = brl_get_locks_readonly(fsp);
> > +	if (brl == NULL) {
> > +		/* Can't tell if we have to downgrade level2 oplocks */
> 
> If we can't figure this out shouldn't we better downgrade the oplock?
> 
> >  		return;
> > +	}
> > +	if (!brl_have_level2_oplocks(brl)) {
> > +		return;
> > +	}
> 
> I'd use
> 
> if ((brl ! NULL) && !brl_have_level2_oplocks(brl)) {
>         return;
> }

Done.

> As optimization we could also think about relying on
> brl_get_locks_readonly() being called by strict_lock_default()
> so that we don't need it twice...

Patch for another time, okay? :-)

It's been a while, so I'm sending it again. I've also picked
up a few cleanup patches from my current work.

Please review & push.

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 a164578911c8306e171a5f88689729d3a5490eec Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 22 Sep 2013 19:16:56 -0700
Subject: [PATCH 01/22] smbd: Avoid calling serverid_exists twice

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

diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index d4c68f8..d0b6eaf 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -646,6 +646,12 @@ bool share_mode_stale_pid(struct share_mode_data *d, unsigned idx)
 		return false;
 	}
 	e = &d->share_modes[idx];
+	if (e->stale) {
+		/*
+		 * Checked before
+		 */
+		return true;
+	}
 	if (serverid_exists(&e->pid)) {
 		DEBUG(10, ("PID %s (index %u out of %u) still exists\n",
 			   procid_str_static(&e->pid), idx,
-- 
1.7.9.5


From c83a74214e081c82aa1a4c7629696c34ce22fca9 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 3 Sep 2013 13:31:27 +0000
Subject: [PATCH 02/22] smbd: Fix confusing comments

The brlock-check is done in grant_fsp_oplock_type

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

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 1a86233..858d2be 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -2676,8 +2676,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 	status = set_file_oplock(fsp, fsp->oplock_type);
 	if (!NT_STATUS_IS_OK(status)) {
 		/*
-		 * Could not get the kernel oplock or there are byte-range
-		 * locks on the file.
+		 * Could not get the kernel oplock
 		 */
 		fsp->oplock_type = NO_OPLOCK;
 	}
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 96c451c..efb37e1 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -47,8 +47,7 @@ void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp)
 
 /****************************************************************************
  Attempt to set an oplock on a file. Succeeds if kernel oplocks are
- disabled (just sets flags) and no byte-range locks in the file. Returns True
- if oplock set.
+ disabled (just sets flags).
 ****************************************************************************/
 
 NTSTATUS set_file_oplock(files_struct *fsp, int oplock_type)
-- 
1.7.9.5


From 1de1bab1892b0af1b2bdd1ec1b97a2fdec142672 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 22 Sep 2013 17:19:09 -0700
Subject: [PATCH 03/22] torture: Fix a typo

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/torture/raw/streams.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/torture/raw/streams.c b/source4/torture/raw/streams.c
index 1611c64..cbb7dcf 100644
--- a/source4/torture/raw/streams.c
+++ b/source4/torture/raw/streams.c
@@ -478,7 +478,7 @@ done:
  * A stream held open with FILE_SHARE_DELETE allows the file to be
  * deleted. After the main file is deleted, access to the open file descriptor
  * still works, but all name-based access to both the main file as well as the
- * stream is denied with DELETE ending.
+ * stream is denied with DELETE pending.
  *
  * This means, an open of the main file with SEC_STD_DELETE should walk all
  * streams and also open them with SEC_STD_DELETE. If any of these opens gives
-- 
1.7.9.5


From 7d387cff6904ca697000fedeb63770433c852129 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 18 Sep 2013 17:01:16 -0700
Subject: [PATCH 04/22] dbwrap: Make dbwrap_watch_db return bool

The next commit will make it possible this fails

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/dbwrap/dbwrap_watch.c |    3 ++-
 source3/lib/dbwrap/dbwrap_watch.h |    2 +-
 source3/lib/g_lock.c              |    6 +++++-
 source3/locking/share_mode_lock.c |    4 +++-
 source3/smbd/smbXsrv_session.c    |    5 ++++-
 5 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
index 7bdcd99..335c7f7 100644
--- a/source3/lib/dbwrap/dbwrap_watch.c
+++ b/source3/lib/dbwrap/dbwrap_watch.c
@@ -352,9 +352,10 @@ done:
 	return;
 }
 
-void dbwrap_watch_db(struct db_context *db, struct messaging_context *msg)
+bool dbwrap_watch_db(struct db_context *db, struct messaging_context *msg)
 {
 	dbwrap_set_stored_callback(db, dbwrap_watch_record_stored, msg);
+	return true;
 }
 
 static void dbwrap_record_watch_done(struct tevent_req *subreq)
diff --git a/source3/lib/dbwrap/dbwrap_watch.h b/source3/lib/dbwrap/dbwrap_watch.h
index 3362e45..feb89e1 100644
--- a/source3/lib/dbwrap/dbwrap_watch.h
+++ b/source3/lib/dbwrap/dbwrap_watch.h
@@ -24,7 +24,7 @@
 #include "dbwrap/dbwrap.h"
 #include "messages.h"
 
-void dbwrap_watch_db(struct db_context *db, struct messaging_context *msg);
+bool dbwrap_watch_db(struct db_context *db, struct messaging_context *msg);
 
 struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
 					    struct tevent_context *ev,
diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index 8c7a6c2..5b4f843 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -67,7 +67,11 @@ struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
 		TALLOC_FREE(result);
 		return NULL;
 	}
-	dbwrap_watch_db(result->db, msg);
+	if (!dbwrap_watch_db(result->db, msg)) {
+		DEBUG(1, ("g_lock_init: dbwrap_watch_db failed\n"));
+		TALLOC_FREE(result);
+		return NULL;
+	}
 	return result;
 }
 
diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c
index 342f910..4ea3a6b 100644
--- a/source3/locking/share_mode_lock.c
+++ b/source3/locking/share_mode_lock.c
@@ -77,7 +77,9 @@ static bool locking_init_internal(bool read_only)
 	if (!posix_locking_init(read_only))
 		return False;
 
-	dbwrap_watch_db(lock_db, server_messaging_context());
+	if (!dbwrap_watch_db(lock_db, server_messaging_context())) {
+		return false;
+	}
 
 	return True;
 }
diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index 017880c..33b3529 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -205,7 +205,10 @@ static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
 
 	table->global.db_ctx = smbXsrv_session_global_db_ctx;
 
-	dbwrap_watch_db(table->global.db_ctx, conn->msg_ctx);
+	if (!dbwrap_watch_db(table->global.db_ctx, conn->msg_ctx)) {
+		TALLOC_FREE(table);
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	ret = msg_channel_init(table, conn->msg_ctx,
 			       MSG_SMBXSRV_SESSION_CLOSE,
-- 
1.7.9.5


From 6c0822b1ccdf60b847627fc4fa54b8ee5db46139 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 18 Sep 2013 17:30:50 -0700
Subject: [PATCH 05/22] dbwrap: Don't trigger an update if we're watching a
 modified record

In a future commit there will be code that wants to watch a record after
it got modified. This will lead to a false wakeup and possibly to an
endless retry loop. There's no point in triggering a watcher immediately,
it does know it just modified something. Convoluted code, I know, but
I don't know how to do this better right now...

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/dbwrap/dbwrap_watch.c |   83 ++++++++++++++++++++++++++++++++++---
 1 file changed, 78 insertions(+), 5 deletions(-)

diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
index 335c7f7..02f600a 100644
--- a/source3/lib/dbwrap/dbwrap_watch.c
+++ b/source3/lib/dbwrap/dbwrap_watch.c
@@ -20,6 +20,7 @@
 #include "includes.h"
 #include "system/filesys.h"
 #include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_private.h"
 #include "dbwrap_watch.h"
 #include "dbwrap_open.h"
 #include "msg_channel.h"
@@ -239,6 +240,7 @@ struct dbwrap_record_watch_state {
 static void dbwrap_record_watch_done(struct tevent_req *subreq);
 static int dbwrap_record_watch_state_destructor(
 	struct dbwrap_record_watch_state *state);
+static NTSTATUS dbwrap_record_protect_this_record(struct db_record *rec);
 
 struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
 					    struct tevent_context *ev,
@@ -287,6 +289,11 @@ struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
 	}
 	talloc_set_destructor(state, dbwrap_record_watch_state_destructor);
 
+	status = dbwrap_record_protect_this_record(rec);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
 	subreq = msg_read_send(state, state->ev, state->channel);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
@@ -305,12 +312,65 @@ static int dbwrap_record_watch_state_destructor(
 	return 0;
 }
 
+struct dbwrap_watch_db_state {
+	struct messaging_context *msg;
+	struct db_record *just_watched;
+};
+
+struct dbwrap_record_protector {
+	struct db_record *rec;
+	struct dbwrap_watch_db_state *state;
+};
+
+static int dbwrap_record_protector_destructor(
+	struct dbwrap_record_protector *p)
+{
+	SMB_ASSERT(p->rec == p->state->just_watched);
+	p->state->just_watched = NULL;
+	return 0;
+}
+
+static NTSTATUS dbwrap_record_protect_this_record(struct db_record *rec)
+{
+	struct dbwrap_watch_db_state *state = talloc_get_type_abort(
+		rec->db->stored_callback_private_data,
+		struct dbwrap_watch_db_state);
+	struct dbwrap_record_protector *p;
+
+	if (state->just_watched != NULL) {
+		/*
+		 * Can only watch a record once
+		 */
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	/*
+	 * We can't trigger a message for the record we just watched if it got
+	 * modified. This is indicated by
+	 * dbwrap_watch_db_state->just_watched. dbwrap_record_protector is
+	 * just there to carry a destructor, triggered as a child destructor
+	 * for "rec". The only purpose of this destructor is to set
+	 * just_watched to NULL, so that we can start triggering changes in
+	 * dbwrap_watch_record_stored.
+	 */
+
+	p = talloc(rec, struct dbwrap_record_protector);
+	if (p == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	p->rec = rec;
+	p->state = state;
+	state->just_watched = rec;
+	talloc_set_destructor(p, dbwrap_record_protector_destructor);
+	return NT_STATUS_OK;
+}
+
 static void dbwrap_watch_record_stored(struct db_context *db,
 				       struct db_record *rec,
 				       void *private_data)
 {
-	struct messaging_context *msg = talloc_get_type_abort(
-		private_data, struct messaging_context);
+	struct dbwrap_watch_db_state *state = talloc_get_type_abort(
+		private_data, struct dbwrap_watch_db_state);
 	struct server_id *ids = NULL;
 	size_t num_ids = 0;
 	TDB_DATA w_key = { 0, };
@@ -318,6 +378,10 @@ static void dbwrap_watch_record_stored(struct db_context *db,
 	NTSTATUS status;
 	uint32_t i;
 
+	if (rec == state->just_watched) {
+		return;
+	}
+
 	status = dbwrap_record_get_watchers(db, rec, talloc_tos(),
 					    &ids, &num_ids);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
@@ -337,8 +401,8 @@ static void dbwrap_watch_record_stored(struct db_context *db,
 	w_blob.length = w_key.dsize;
 
 	for (i=0; i<num_ids; i++) {
-		status = messaging_send(msg, ids[i], MSG_DBWRAP_MODIFIED,
-					&w_blob);
+		status = messaging_send(state->msg, ids[i],
+					MSG_DBWRAP_MODIFIED, &w_blob);
 		if (!NT_STATUS_IS_OK(status)) {
 			char *str = procid_str_static(&ids[i]);
 			DEBUG(1, ("messaging_send to %s failed: %s\n",
@@ -354,7 +418,16 @@ done:
 
 bool dbwrap_watch_db(struct db_context *db, struct messaging_context *msg)
 {
-	dbwrap_set_stored_callback(db, dbwrap_watch_record_stored, msg);
+	struct dbwrap_watch_db_state *state;
+
+	state = talloc(db, struct dbwrap_watch_db_state);
+	if (state == NULL) {
+		return false;
+	}
+	state->msg = msg;
+	state->just_watched = NULL;
+
+	dbwrap_set_stored_callback(db, dbwrap_watch_record_stored, state);
 	return true;
 }
 
-- 
1.7.9.5


From aeae4c426dd3a51579c8c700a38fb33294e7ee1e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 14 Sep 2013 13:43:03 +0200
Subject: [PATCH 06/22] libndr: Fix ndr_print_bitmap_flag for value=0

Don't endlessly loop

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 librpc/ndr/ndr_basic.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/librpc/ndr/ndr_basic.c b/librpc/ndr/ndr_basic.c
index 5c653c8..dc93120 100644
--- a/librpc/ndr/ndr_basic.c
+++ b/librpc/ndr/ndr_basic.c
@@ -1019,6 +1019,10 @@ _PUBLIC_ void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const ch
 	/* this is an attempt to support multi-bit bitmap masks */
 	value &= flag;
 
+	if (value == 0) {
+		return;
+	}
+
 	while (!(flag & 1)) {
 		flag >>= 1;
 		value >>= 1;
-- 
1.7.9.5


From 6589f52ed12b5dcb447f6298702d0c5dbea93691 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 14 Sep 2013 13:44:54 +0200
Subject: [PATCH 07/22] librpc: Fix blank line endings

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 librpc/ndr/ndr_basic.c |   16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/librpc/ndr/ndr_basic.c b/librpc/ndr/ndr_basic.c
index dc93120..aa62a27 100644
--- a/librpc/ndr/ndr_basic.c
+++ b/librpc/ndr/ndr_basic.c
@@ -1,20 +1,20 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
 
    routines for marshalling/unmarshalling basic types
 
    Copyright (C) Andrew Tridgell 2003
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
@@ -1004,7 +1004,7 @@ _PUBLIC_ void ndr_print_null(struct ndr_print *ndr)
 	ndr->print(ndr, "UNEXPECTED NULL POINTER");
 }
 
-_PUBLIC_ void ndr_print_enum(struct ndr_print *ndr, const char *name, const char *type, 
+_PUBLIC_ void ndr_print_enum(struct ndr_print *ndr, const char *name, const char *type,
 		    const char *val, uint32_t value)
 {
 	if (ndr->flags & LIBNDR_PRINT_ARRAY_HEX) {
@@ -1026,7 +1026,7 @@ _PUBLIC_ void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const ch
 	while (!(flag & 1)) {
 		flag >>= 1;
 		value >>= 1;
-	}	
+	}
 	if (flag == 1) {
 		ndr->print(ndr, "   %d: %-25s", value, flag_name);
 	} else {
@@ -1164,7 +1164,7 @@ _PUBLIC_ void ndr_print_bad_level(struct ndr_print *ndr, const char *name, uint1
 	ndr->print(ndr, "UNKNOWN LEVEL %u", level);
 }
 
-_PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name, 
+_PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name,
 			   const uint8_t *data, uint32_t count)
 {
 	int i;
@@ -1199,7 +1199,7 @@ _PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name,
 			free(idx);
 		}
 	}
-	ndr->depth--;	
+	ndr->depth--;
 #undef _ONELINE_LIMIT
 }
 
-- 
1.7.9.5


From b69861cbeb738ffffb1e5aa8fbda44d0430b2401 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 15 Sep 2013 19:18:41 -0700
Subject: [PATCH 08/22] smbd: Convert some dbgtxt to DEBUG

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/oplock.c |   31 ++++++++++++-------------------
 1 file changed, 12 insertions(+), 19 deletions(-)

diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index efb37e1..818606a 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -255,13 +255,11 @@ static files_struct *initial_break_processing(
 {
 	files_struct *fsp = NULL;
 
-	if( DEBUGLVL( 3 ) ) {
-		dbgtext( "initial_break_processing: called for %s/%u\n",
-			 file_id_string_tos(&id), (int)file_id);
-		dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
-			sconn->oplocks.exclusive_open,
-			sconn->oplocks.level_II_open);
-	}
+	DEBUG(3, ("initial_break_processing: called for %s/%u\n"
+		  "Current oplocks_open (exclusive = %d, levelII = %d)\n",
+		  file_id_string_tos(&id), (int)file_id,
+		  sconn->oplocks.exclusive_open,
+		  sconn->oplocks.level_II_open));
 
 	/*
 	 * We need to search the file open table for the
@@ -273,11 +271,9 @@ static files_struct *initial_break_processing(
 
 	if(fsp == NULL) {
 		/* The file could have been closed in the meantime - return success. */
-		if( DEBUGLVL( 3 ) ) {
-			dbgtext( "initial_break_processing: cannot find open file with " );
-			dbgtext( "file_id %s gen_id = %lu, ", file_id_string_tos(&id), file_id);
-			dbgtext( "allowing break to succeed.\n" );
-		}
+		DEBUG(3, ("initial_break_processing: cannot find open file "
+			  "with file_id %s gen_id = %lu, allowing break to "
+			  "succeed.\n", file_id_string_tos(&id), file_id));
 		return NULL;
 	}
 
@@ -292,13 +288,10 @@ static files_struct *initial_break_processing(
 	 */
 
 	if(fsp->oplock_type == NO_OPLOCK) {
-		if( DEBUGLVL( 3 ) ) {
-			dbgtext( "initial_break_processing: file %s ",
-				 fsp_str_dbg(fsp));
-			dbgtext( "(file_id = %s gen_id = %lu) has no oplock.\n",
-				 file_id_string_tos(&id), fsp->fh->gen_id );
-			dbgtext( "Allowing break to succeed regardless.\n" );
-		}
+		DEBUG(3, ("initial_break_processing: file %s (file_id = %s "
+			  "gen_id = %lu) has no oplock. Allowing break to "
+			  "succeed regardless.\n", fsp_str_dbg(fsp),
+			  file_id_string_tos(&id), fsp->fh->gen_id));
 		return NULL;
 	}
 
-- 
1.7.9.5


From 0fa5ca7400ed0939686e9d5495876e41a6705aa0 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 21 Aug 2013 10:27:43 +0000
Subject: [PATCH 09/22] libcli: Add const to smb2_lease_pull

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/smb/smb2_lease.c |    3 ++-
 libcli/smb/smb2_lease.h |    3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/libcli/smb/smb2_lease.c b/libcli/smb/smb2_lease.c
index 10beaca..9e6c950 100644
--- a/libcli/smb/smb2_lease.c
+++ b/libcli/smb/smb2_lease.c
@@ -23,7 +23,8 @@
 #include "includes.h"
 #include "../libcli/smb/smb_common.h"
 
-ssize_t smb2_lease_pull(uint8_t *buf, size_t len, struct smb2_lease *lease)
+ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
+			struct smb2_lease *lease)
 {
 	int version;
 
diff --git a/libcli/smb/smb2_lease.h b/libcli/smb/smb2_lease.h
index fa8e7af..73f97ac 100644
--- a/libcli/smb/smb2_lease.h
+++ b/libcli/smb/smb2_lease.h
@@ -44,7 +44,8 @@ struct smb2_lease {
  * Parse a smb2 lease create context. Return -1 on error, buffer.length on
  * success. V1 and V2 differ only by length of buffer.length
  */
-ssize_t smb2_lease_pull(uint8_t *buf, size_t len, struct smb2_lease *lease);
+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);
 
 #endif /* _LIBCLI_SMB_SMB2_LEASE_H_ */
-- 
1.7.9.5


From 1bc6759579a8d5c5d5d6763c02ff69abe673f4c2 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 10/22] smbd: Use remove_oplock() in close_normal_file

remove_oplock is a wrapper around release_file_oplock. This streamlines
the exports of 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 8e18a064045316ffc8e97ab86c1249dd5e7d3503 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 11/22] 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 818606a..8dd696d 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -94,7 +94,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 bdc079e24b35ccda8c20175a23d93e0414013f51 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 12/22] 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 b2e122929b68d9d97434706c7961e7f9e2fd8f92 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 13/22] 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 8a97a593157cadf971fb7abd3ecdf56d5ae5a1d6 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 14/22] 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 abddba788a7564697bf84e782ac754351000ca53 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 15/22] 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 25ece8b5dbbfa4efeb9d496fc572b94fd8d32e4c 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 16/22] 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 6ba6734cf2bf890c5b6a5e6353fc782f1eeeea73 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 17/22] 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 b37a920e4a322eb22767a72e45f00202425e456b 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 18/22] smbd: Put "have_read_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..67b1701 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_read_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_read_oplocks(const struct byte_range_lock *brl)
+{
+	return brl->have_read_oplocks;
+}
+
+void brl_set_have_read_oplocks(struct byte_range_lock *brl,
+			       bool have_read_oplocks)
+{
+	SMB_ASSERT(brl->record != NULL); /* otherwise we're readonly */
+	brl->have_read_oplocks = have_read_oplocks;
+	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_read_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_read_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_read_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_read_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_read_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_read_oplocks = rw->have_read_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..b9c01e5 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_read_oplocks(const struct byte_range_lock *brl);
+void brl_set_have_read_oplocks(struct byte_range_lock *brl,
+			       bool have_read_oplocks);
 
 NTSTATUS brl_lock_windows_default(struct byte_range_lock *br_lck,
 		struct lock_struct *plock,
-- 
1.7.9.5


From 9b209221134cc4087a0978c30d21964bea7f962a 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 19/22] 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     |   77 +++++++++++++++++++++++++++++++++++----------
 5 files changed, 81 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 d0b6eaf..bab49b5 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -847,19 +847,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 858d2be..c96bbb5 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_read_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 8dd696d..88936f2 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -66,7 +66,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))
 	{
@@ -100,7 +99,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);
 	}
@@ -114,12 +112,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);
@@ -171,6 +164,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_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 "
@@ -190,6 +222,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) {
@@ -206,6 +239,13 @@ bool downgrade_oplock(files_struct *fsp)
 	}
 
 	downgrade_file_oplock(fsp);
+
+	brl = brl_get_locks(talloc_tos(), fsp);
+	if (brl != NULL) {
+		brl_set_have_read_oplocks(brl, true);
+		TALLOC_FREE(brl);
+	}
+
 	TALLOC_FREE(lck);
 	return ret;
 }
@@ -375,14 +415,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);
 
@@ -622,6 +654,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
@@ -631,8 +664,18 @@ 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))
+	if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+		/*
+		 * There can't be any level2 oplocks, we're alone.
+		 */
 		return;
+	}
+
+	brl = brl_get_locks_readonly(fsp);
+	if ((brl != NULL) && !brl_have_read_oplocks(brl)) {
+		DEBUG(10, ("No read oplocks around\n"));
+		return;
+	}
 
 	/*
 	 * When we get here we might have a brlock entry locked. Also
-- 
1.7.9.5


From f5267f6db49733b8b06479e094e401be81b5e254 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 20/22] 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 83a21c1141768859f390b98ab99c48eff8d2cb0b 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 21/22] smbd: Add debugs to brlock.c

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

diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index 67b1701..b5eebc8 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -90,6 +90,8 @@ 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)
 {
+	DEBUG(10, ("Setting have_read_oplocks to %s\n",
+		   have_read_oplocks ? "true" : "false"));
 	SMB_ASSERT(brl->record != NULL); /* otherwise we're readonly */
 	brl->have_read_oplocks = have_read_oplocks;
 	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_read_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_read_oplocks = (data.dptr[data.dsize-1] == 1);
 	}
 
+	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;
 }
 
@@ -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 88936f2..4c6fe95 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -157,6 +157,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) {
@@ -224,6 +227,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 "
-- 
1.7.9.5


From 0aa765e0756874c7e6bb93c3f0f05bcb0ded4bd8 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 22/22] 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 4c6fe95..1ceb4a5 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -442,8 +442,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.
 *******************************************************************/
 
@@ -740,7 +740,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