smbd: Add debugs to brlock.c
[mat/samba.git] / source3 / smbd / oplock.c
index 434bafa3ca0535d3c4ca665a2708a06b98a6c018..fc6b0efddac74e1c6f42b505d05b6106f2481e31 100644 (file)
@@ -47,8 +47,7 @@ void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp)
 
 /****************************************************************************
  Attempt to set an oplock on a file. Succeeds if kernel oplocks are
- disabled (just sets flags) and no byte-range locks in the file. Returns True
- if oplock set.
+ disabled (just sets flags).
 ****************************************************************************/
 
 NTSTATUS set_file_oplock(files_struct *fsp, int oplock_type)
@@ -67,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))
        {
@@ -101,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);
        }
@@ -115,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);
@@ -165,6 +157,9 @@ bool remove_oplock(files_struct *fsp)
        bool ret;
        struct share_mode_lock *lck;
 
+       DEBUG(10, ("remove_oplock called for %s\n",
+                  fsp_str_dbg(fsp)));
+
        /* Remove the oplock flag from the sharemode. */
        lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
        if (lck == NULL) {
@@ -172,6 +167,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 "
@@ -191,6 +225,10 @@ bool downgrade_oplock(files_struct *fsp)
 {
        bool ret;
        struct share_mode_lock *lck;
+       struct byte_range_lock *brl;
+
+       DEBUG(10, ("downgrade_oplock called for %s\n",
+                  fsp_str_dbg(fsp)));
 
        lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
        if (lck == NULL) {
@@ -207,20 +245,17 @@ 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;
 }
 
-/*
- * Some kernel oplock implementations handle the notification themselves.
- */
-bool should_notify_deferred_opens(struct smbd_server_connection *sconn)
-{
-       struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
-       return !(koplocks &&
-               (koplocks->flags & KOPLOCKS_DEFERRED_OPEN_NOTIFICATION));
-}
-
 /****************************************************************************
  Set up an oplock break message.
 ****************************************************************************/
@@ -266,13 +301,11 @@ static files_struct *initial_break_processing(
 {
        files_struct *fsp = NULL;
 
-       if( DEBUGLVL( 3 ) ) {
-               dbgtext( "initial_break_processing: called for %s/%u\n",
-                        file_id_string_tos(&id), (int)file_id);
-               dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
-                       sconn->oplocks.exclusive_open,
-                       sconn->oplocks.level_II_open);
-       }
+       DEBUG(3, ("initial_break_processing: called for %s/%u\n"
+                 "Current oplocks_open (exclusive = %d, levelII = %d)\n",
+                 file_id_string_tos(&id), (int)file_id,
+                 sconn->oplocks.exclusive_open,
+                 sconn->oplocks.level_II_open));
 
        /*
         * We need to search the file open table for the
@@ -284,11 +317,9 @@ static files_struct *initial_break_processing(
 
        if(fsp == NULL) {
                /* The file could have been closed in the meantime - return success. */
-               if( DEBUGLVL( 3 ) ) {
-                       dbgtext( "initial_break_processing: cannot find open file with " );
-                       dbgtext( "file_id %s gen_id = %lu, ", file_id_string_tos(&id), file_id);
-                       dbgtext( "allowing break to succeed.\n" );
-               }
+               DEBUG(3, ("initial_break_processing: cannot find open file "
+                         "with file_id %s gen_id = %lu, allowing break to "
+                         "succeed.\n", file_id_string_tos(&id), file_id));
                return NULL;
        }
 
@@ -303,13 +334,10 @@ static files_struct *initial_break_processing(
         */
 
        if(fsp->oplock_type == NO_OPLOCK) {
-               if( DEBUGLVL( 3 ) ) {
-                       dbgtext( "initial_break_processing: file %s ",
-                                fsp_str_dbg(fsp));
-                       dbgtext( "(file_id = %s gen_id = %lu) has no oplock.\n",
-                                file_id_string_tos(&id), fsp->fh->gen_id );
-                       dbgtext( "Allowing break to succeed regardless.\n" );
-               }
+               DEBUG(3, ("initial_break_processing: file %s (file_id = %s "
+                         "gen_id = %lu) has no oplock. Allowing break to "
+                         "succeed regardless.\n", fsp_str_dbg(fsp),
+                         file_id_string_tos(&id), fsp->fh->gen_id));
                return NULL;
        }
 
@@ -393,14 +421,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);
 
@@ -535,7 +555,6 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
        use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks;
 
        if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
-           !(msg.op_type & FORCE_OPLOCK_BREAK_TO_NONE) &&
            !(use_kernel && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) &&
            lp_level2_oplocks(SNUM(fsp->conn))) {
                break_to_level2 = True;
@@ -641,6 +660,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
@@ -650,14 +670,24 @@ 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
         * locking the share mode entry would violate the locking
         * order. Breaking level2 oplocks to none is asynchronous
-        * anyway, so we postpone this into an immediate timed event.
+        * anyway, so we postpone this into an immediate event.
         */
 
        state = talloc(sconn, struct break_to_none_state);
@@ -764,8 +794,7 @@ static void do_break_to_none(struct tevent_context *ctx,
                        messaging_send_buf(state->sconn->msg_ctx,
                                        share_entry->pid,
                                        MSG_SMB_ASYNC_LEVEL2_BREAK,
-                                       (uint8 *)msg,
-                                       MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+                                       (uint8 *)msg, sizeof(msg));
                }
        }
 
@@ -830,7 +859,7 @@ void share_mode_entry_to_message(char *msg, const struct share_mode_entry *e)
  De-linearize an internal oplock break message to a share mode entry struct.
 ****************************************************************************/
 
-void message_to_share_mode_entry(struct share_mode_entry *e, char *msg)
+void message_to_share_mode_entry(struct share_mode_entry *e, const char *msg)
 {
        e->pid.pid = (pid_t)IVAL(msg,OP_BREAK_MSG_PID_OFFSET);
        e->op_mid = BVAL(msg,OP_BREAK_MSG_MID_OFFSET);