diff options
author | Jeremy Allison <jra@samba.org> | 2006-03-21 06:53:49 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:15:39 -0500 |
commit | 5067cca077ab8dde110f79ea9e60611dc25ddf64 (patch) | |
tree | c105e7aa1400abfb67c3773f0047c34971a20758 | |
parent | 97ee5b1afa342eea40f973f5370c9f620c63bd01 (diff) | |
download | samba-5067cca077ab8dde110f79ea9e60611dc25ddf64.tar.gz samba-5067cca077ab8dde110f79ea9e60611dc25ddf64.tar.bz2 samba-5067cca077ab8dde110f79ea9e60611dc25ddf64.zip |
r14602: Fix another logic bug in new oplock handling. Just
because lck->num_share_modes != 0 doesn't mean that
there *are* other valid share modes. They may be
all marked "UNUSED" or be deferred open entries.
In that case don't downgrade the granted oplock to
level2 needlessly - a client can have an exclusive
oplock in this case. The original code handled this
correctly in the lck->num_share_modes == 0 case but
not in the case where there were no valid share modes
but lck->num_share_modes != 0. I'll clean up my
Samba4 torture tester for this and commit it tomorrow.
Jeremy.
(This used to be commit 306061c93d9181262298516fefd83444f5a65ce5)
-rw-r--r-- | source3/smbd/open.c | 29 |
1 files changed, 17 insertions, 12 deletions
diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 0cf8b68c28..5de03b8dd7 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -612,6 +612,7 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck, files_struct *fsp) { int i; struct share_mode_entry *exclusive = NULL; + BOOL valid_entry = False; BOOL delay_it = False; BOOL have_level2 = False; @@ -620,33 +621,36 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck, files_struct *fsp) return False; } - if (lck->num_share_modes == 0) { - /* No files open at all: Directly grant whatever the client - * wants. */ - - if (fsp->oplock_type == NO_OPLOCK) { - /* Store a level2 oplock, but don't tell the client */ - fsp->oplock_type = FAKE_LEVEL_II_OPLOCK; - } - return False; - } - for (i=0; i<lck->num_share_modes; i++) { if (!is_valid_share_mode_entry(&lck->share_modes[i])) { continue; } + /* At least one entry is not an invalid or deferred entry. */ + valid_entry = True; + if (EXCLUSIVE_OPLOCK_TYPE(lck->share_modes[i].op_type)) { SMB_ASSERT(exclusive == NULL); exclusive = &lck->share_modes[i]; } if (lck->share_modes[i].op_type == LEVEL_II_OPLOCK) { + SMB_ASSERT(exclusive == NULL); have_level2 = True; } } + if (!valid_entry) { + /* All entries are placeholders or deferred. + * Directly grant whatever the client wants. */ + if (fsp->oplock_type == NO_OPLOCK) { + /* Store a level2 oplock, but don't tell the client */ + fsp->oplock_type = FAKE_LEVEL_II_OPLOCK; + } + return False; + } + if (exclusive != NULL) { /* Found an exclusive oplock */ SMB_ASSERT(!have_level2); delay_it = is_delete_request(fsp) ? @@ -654,7 +658,8 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck, files_struct *fsp) } if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { - /* We can at most grant level2 */ + /* We can at most grant level2 as there are other + * level2 or NO_OPLOCK entries. */ fsp->oplock_type = LEVEL_II_OPLOCK; } |