smbd: Remove FAKE_LEVEL_II_OPLOCK
authorVolker Lendecke <vl@samba.org>
Wed, 11 Sep 2013 16:07:33 +0000 (16:07 +0000)
committerJeremy Allison <jra@samba.org>
Mon, 14 Oct 2013 23:52:29 +0000 (01:52 +0200)
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@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/include/smb.h
source3/locking/locking.c
source3/smbd/files.c
source3/smbd/open.c
source3/smbd/oplock.c

index 0d07f71750954e6dbf759fa5799f4e455271fc12..5c0dfdcbc8d88a8b7ec200f140e53b0a8da2ad88 100644 (file)
@@ -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.
 
index b9db27cb8600a323179ffc2e6e35aaae077ffa4a..7ac04a45e3fcfc7bf89da49aac43653298d9ed56 100644 (file)
@@ -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;
 }
index d94ee119527b524af2c3bb14180191e2cd746082..c64c84173cfcc10119418f6091801c13d578e980 100644 (file)
@@ -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",
index f6df03595f06ee04969b1418a103756d5221be0c..93b69d5afd7549b719a1134fc8c9ebb81ddd0f52 100644 (file)
@@ -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",
index 70f168ed728fe5ae76788c818405f33beb99cb61..f18ac657b8d3d68eed6ead5eb33b3cbb277b33c8 100644 (file)
@@ -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