[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Mon Oct 14 19:43:01 MDT 2013


The branch, master has been updated
       via  9646dfc smbd: Inline break_level2_to_none_async
       via  1d2c6f4 smbd: Remove a special case for level2 break
       via  cc9cd51 smbd: Remove some FAKE_LEVEL_II comments
       via  47f65d5 smbd: Add debugs to brlock.c
       via  c92ac4c torture: Extend raw.oplock.batch10
       via  fcafaf6 smbd: Remove FAKE_LEVEL_II_OPLOCK
       via  eb50c18 smbd: Put "have_read_oplocks" into brlock.tdb
      from  54019ca docs: Explain why this option should not be used

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


- Log -----------------------------------------------------------------
commit 9646dfcdf2ffe0fbd56284a87007b63a9ab34a30
Author: Volker Lendecke <vl at samba.org>
Date:   Fri Oct 4 10:11:38 2013 +0000

    smbd: Inline break_level2_to_none_async
    
    With the special case for bug 5980 in do_break_to_none we only have
    one caller: process_oplock_async_level2_break_message. The further
    goal is to merge process_oplock_async_level2_break_message with
    process_oplock_break_message.
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Tue Oct 15 03:42:53 CEST 2013 on sn-devel-104

commit 1d2c6f477b5bc17ac8b940de56432c69d7039304
Author: Volker Lendecke <vl at samba.org>
Date:   Fri Oct 4 09:24:29 2013 +0000

    smbd: Remove a special case for level2 break
    
    With the level2 indicator in brlock.tdb this race condition does not
    exist anymore
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit cc9cd5142a861360861407fd6018385524bf150d
Author: Volker Lendecke <vl at samba.org>
Date:   Fri Sep 13 15:18:15 2013 +0200

    smbd: Remove some FAKE_LEVEL_II comments
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 47f65d5829167f061756621e50b480a8c16e4fbc
Author: Volker Lendecke <vl at samba.org>
Date:   Fri Sep 13 14:13:51 2013 +0200

    smbd: Add debugs to brlock.c
    
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit c92ac4c8eebf4ddaaab4e8b640650406b259b05d
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Sep 9 18:53:15 2013 +0000

    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>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit fcafaf6022832835fc8fa76a4c33056605dc53e4
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Sep 11 16:07:33 2013 +0000

    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>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit eb50c18c4a2d0caa3b8d21b2e1b536adc8dc0276
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Sep 11 12:48:14 2013 +0000

    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>
    Reviewed-by: Jeremy Allison <jra at samba.org>

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

Summary of changes:
 source3/include/smb.h        |    5 +-
 source3/locking/brlock.c     |   70 ++++++++++++++--
 source3/locking/locking.c    |   14 +---
 source3/locking/proto.h      |    3 +
 source3/smbd/files.c         |    3 +-
 source3/smbd/open.c          |   41 ++++------
 source3/smbd/oplock.c        |  186 +++++++++++++++++++++++------------------
 source3/smbd/smb2_create.c   |    5 -
 source4/torture/raw/oplock.c |   12 +++
 9 files changed, 200 insertions(+), 139 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/smb.h b/source3/include/smb.h
index 0d07f71..5c0dfdc 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -686,7 +686,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 */
@@ -698,7 +699,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/brlock.c b/source3/locking/brlock.c
index 0d45501..b5eebc8 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,21 @@ 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)
+{
+	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;
+}
+
 /****************************************************************************
  See if two locking contexts are equal.
 ****************************************************************************/
@@ -1878,11 +1894,21 @@ 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) {
+		DEBUG(10, ("br_lck not modified\n"));
 		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;
+	}
+
+	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);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -1894,16 +1920,27 @@ 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");
 		}
 	}
 
+	DEBUG(10, ("seqnum=%d\n", dbwrap_get_seqnum(brlock_db)));
+
  done:
 	br_lck->modified = false;
 	TALLOC_FREE(br_lck->record);
@@ -1932,6 +1969,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 +1985,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 +2000,14 @@ 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));
+	}
+
+	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);
 	}
 
 	if (!fsp->lockdb_clean) {
@@ -2038,6 +2077,13 @@ 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);
+	}
+
+	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;
 }
 
@@ -2046,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)) {
 		/*
@@ -2079,6 +2128,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/locking.c b/source3/locking/locking.c
index b9db27c..7ac04a4 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -823,19 +823,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/locking/proto.h b/source3/locking/proto.h
index 02e2bf5..f6ae462 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,
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 f6df035..93b69d5 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;
 	}
@@ -1408,24 +1400,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;
-		}
 	}
 
 	/*
@@ -1433,7 +1411,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 70f168e..e2880c5 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 @@ 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 @@ 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);
@@ -164,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) {
@@ -171,6 +167,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 +225,10 @@ bool downgrade_oplock(files_struct *fsp)
 {
 	bool ret;
 	struct share_mode_lock *lck;
+	struct byte_range_lock *brl;
+
+	DEBUG(10, ("downgrade_oplock called for %s\n",
+		   fsp_str_dbg(fsp)));
 
 	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
 	if (lck == NULL) {
@@ -206,6 +245,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;
 }
@@ -363,49 +409,11 @@ static void send_break_message_smb1(files_struct *fsp, int level)
 	}
 }
 
-static void break_level2_to_none_async(files_struct *fsp)
-{
-	struct smbd_server_connection *sconn = fsp->conn->sconn;
-
-	if (fsp->oplock_type == NO_OPLOCK) {
-		/* We already got a "break to none" message and we've handled
-		 * it.  just ignore. */
-		DEBUG(3, ("process_oplock_async_level2_break_message: already "
-			  "broken to none, ignoring.\n"));
-		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);
-
-	DEBUG(10,("process_oplock_async_level2_break_message: sending break "
-		  "to none message for %s, file %s\n", fsp_fnum_dbg(fsp),
-		  fsp_str_dbg(fsp)));
-
-	/* Now send a break to none message to our client. */
-	if (sconn->using_smb2) {
-		send_break_message_smb2(fsp, OPLOCKLEVEL_NONE);
-	} else {
-		send_break_message_smb1(fsp, OPLOCKLEVEL_NONE);
-	}
-
-	/* Async level2 request, don't send a reply, just remove the oplock. */
-	remove_oplock(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.
 *******************************************************************/
 
@@ -420,6 +428,7 @@ static void process_oplock_async_level2_break_message(struct messaging_context *
 	struct smbd_server_connection *sconn =
 		talloc_get_type_abort(private_data,
 		struct smbd_server_connection);
+	struct server_id self = messaging_server_id(sconn->msg_ctx);
 
 	if (data->data == NULL) {
 		DEBUG(0, ("Got NULL buffer\n"));
@@ -449,7 +458,37 @@ static void process_oplock_async_level2_break_message(struct messaging_context *
 		return;
 	}
 
-	break_level2_to_none_async(fsp);
+
+	if (fsp->oplock_type == NO_OPLOCK) {
+		/* We already got a "break to none" message and we've handled
+		 * it.  just ignore. */
+		DEBUG(3, ("process_oplock_async_level2_break_message: already "
+			  "broken to none, ignoring.\n"));
+		return;
+	}
+
+	/* Ensure we're really at level2 state. */
+	SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK);
+
+	DEBUG(10,("process_oplock_async_level2_break_message: sending break "
+		  "to none message for %s, file %s\n", fsp_fnum_dbg(fsp),
+		  fsp_str_dbg(fsp)));
+
+	/* Need to wait before sending a break
+	   message if we sent ourselves this message. */
+	if (serverid_equal(&self, &src)) {
+		wait_before_sending_break();


-- 
Samba Shared Repository


More information about the samba-cvs mailing list