summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h5
-rw-r--r--source3/locking/locking.c14
-rw-r--r--source3/smbd/files.c3
-rw-r--r--source3/smbd/open.c41
-rw-r--r--source3/smbd/oplock.c77
5 files changed, 81 insertions, 59 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 0d07f71750..5c0dfdcbc8 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/locking.c b/source3/locking/locking.c
index b9db27cb86..7ac04a45e3 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/smbd/files.c b/source3/smbd/files.c
index d94ee11952..c64c84173c 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 f6df03595f..93b69d5afd 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 70f168ed72..f18ac657b8 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);
@@ -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