r14602: Fix another logic bug in new oplock handling. Just
authorJeremy Allison <jra@samba.org>
Tue, 21 Mar 2006 06:53:49 +0000 (06:53 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:15:39 +0000 (11:15 -0500)
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)

source3/smbd/open.c

index 0cf8b68c28b5fe7bf2f39971d45d9683ce94a766..5de03b8dd7636ff68bf33e9efb727866642101bd 100644 (file)
@@ -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;
        }