diff options
-rw-r--r-- | source3/include/smb.h | 5 | ||||
-rw-r--r-- | source3/locking/locking.c | 14 | ||||
-rw-r--r-- | source3/smbd/files.c | 3 | ||||
-rw-r--r-- | source3/smbd/open.c | 41 | ||||
-rw-r--r-- | 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 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 |