smbd: Simplify find_oplock_types a bit
[mat/samba.git] / source3 / smbd / open.c
index 1a86233fd9ff2faaf553a86bfa3f79bee5c4b204..29c6eb525d5d216c0f3fa274b2763986e9a35743 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;
        }
@@ -1093,6 +1085,26 @@ bool is_stat_open(uint32 access_mask)
                ((access_mask & ~stat_open_bits) == 0));
 }
 
+static bool has_delete_on_close(struct share_mode_lock *lck,
+                               uint32_t name_hash)
+{
+       struct share_mode_data *d = lck->data;
+       uint32_t i;
+
+       if (d->num_share_modes == 0) {
+               return false;
+       }
+       if (!is_delete_on_close_set(lck, name_hash)) {
+               return false;
+       }
+       for (i=0; i<d->num_share_modes; i++) {
+               if (!share_mode_stale_pid(d, i)) {
+                       return true;
+               }
+       }
+       return false;
+}
+
 /****************************************************************************
  Deal with share modes
  Invarient: Share mode must be locked on entry and exit.
@@ -1101,10 +1113,8 @@ bool is_stat_open(uint32 access_mask)
 
 static NTSTATUS open_mode_check(connection_struct *conn,
                                struct share_mode_lock *lck,
-                               uint32_t name_hash,
                                uint32 access_mask,
                                uint32 share_access,
-                               uint32 create_options,
                                bool *file_existed)
 {
        int i;
@@ -1113,25 +1123,6 @@ static NTSTATUS open_mode_check(connection_struct *conn,
                return NT_STATUS_OK;
        }
 
-       /* A delete on close prohibits everything */
-
-       if (is_delete_on_close_set(lck, name_hash)) {
-               /*
-                * Check the delete on close token
-                * is valid. It could have been left
-                * after a server crash.
-                */
-               for(i = 0; i < lck->data->num_share_modes; i++) {
-                       if (!share_mode_stale_pid(lck->data, i)) {
-
-                               *file_existed = true;
-
-                               return NT_STATUS_DELETE_PENDING;
-                       }
-               }
-               return NT_STATUS_OK;
-       }
-
        if (is_stat_open(access_mask)) {
                /* Stat open that doesn't trigger oplock breaks or share mode
                 * checks... ! JRA. */
@@ -1226,6 +1217,7 @@ static void find_oplock_types(files_struct *fsp,
                                bool *got_level2,
                                bool *got_no_oplock)
 {
+       struct share_mode_data *d = lck->data;
        int i;
 
        *pp_batch = NULL;
@@ -1241,8 +1233,8 @@ static void find_oplock_types(files_struct *fsp,
                return;
        }
 
-       for (i=0; i<lck->data->num_share_modes; i++) {
-               struct share_mode_entry *e = &lck->data->share_modes[i];
+       for (i=0; i<d->num_share_modes; i++) {
+               struct share_mode_entry *e = &d->share_modes[i];
 
                if (!is_valid_share_mode_entry(e)) {
                        continue;
@@ -1257,7 +1249,7 @@ static void find_oplock_types(files_struct *fsp,
 
                if (BATCH_OPLOCK_TYPE(e->op_type)) {
                        /* batch - can only be one. */
-                       if (share_mode_stale_pid(lck->data, i)) {
+                       if (share_mode_stale_pid(d, i)) {
                                DEBUG(10, ("Found stale batch oplock\n"));
                                continue;
                        }
@@ -1268,7 +1260,7 @@ static void find_oplock_types(files_struct *fsp,
                }
 
                if (EXCLUSIVE_OPLOCK_TYPE(e->op_type)) {
-                       if (share_mode_stale_pid(lck->data, i)) {
+                       if (share_mode_stale_pid(d, i)) {
                                DEBUG(10, ("Found stale duplicate oplock\n"));
                                continue;
                        }
@@ -1281,7 +1273,7 @@ static void find_oplock_types(files_struct *fsp,
 
                if (LEVEL_II_OPLOCK_TYPE(e->op_type)) {
                        if (*pp_batch || *pp_ex_or_batch) {
-                               if (share_mode_stale_pid(lck->data, i)) {
+                               if (share_mode_stale_pid(d, i)) {
                                        DEBUG(10, ("Found stale LevelII "
                                                   "oplock\n"));
                                        continue;
@@ -1293,7 +1285,7 @@ static void find_oplock_types(files_struct *fsp,
 
                if (e->op_type == NO_OPLOCK) {
                        if (*pp_batch || *pp_ex_or_batch) {
-                               if (share_mode_stale_pid(lck->data, i)) {
+                               if (share_mode_stale_pid(d, i)) {
                                        DEBUG(10, ("Found stale NO_OPLOCK "
                                                   "entry\n"));
                                        continue;
@@ -1409,24 +1401,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;
-               }
        }
 
        /*
@@ -1434,7 +1412,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",
@@ -2416,6 +2407,12 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                          &got_level2_oplock,
                          &got_a_none_oplock);
 
+       if (has_delete_on_close(lck, fsp->name_hash)) {
+               TALLOC_FREE(lck);
+               fd_close(fsp);
+               return NT_STATUS_DELETE_PENDING;
+       }
+
        /* First pass - send break only on batch oplocks. */
        if ((req != NULL) &&
            delay_for_batch_oplocks(fsp,
@@ -2428,9 +2425,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                return NT_STATUS_SHARING_VIOLATION;
        }
 
-       status = open_mode_check(conn, lck, fsp->name_hash,
+       status = open_mode_check(conn, lck,
                                 access_mask, share_access,
-                                create_options, &file_existed);
+                                &file_existed);
 
        if (NT_STATUS_IS_OK(status)) {
                /* We might be going to allow this open. Check oplock
@@ -2450,13 +2447,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                }
        }
 
-       if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
-               /* DELETE_PENDING is not deferred for a second */
-               TALLOC_FREE(lck);
-               fd_close(fsp);
-               return status;
-       }
-
        if (!NT_STATUS_IS_OK(status)) {
                uint32 can_access_mask;
                bool can_access = True;
@@ -2676,15 +2666,18 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        status = set_file_oplock(fsp, fsp->oplock_type);
        if (!NT_STATUS_IS_OK(status)) {
                /*
-                * Could not get the kernel oplock or there are byte-range
-                * locks on the file.
+                * Could not get the kernel oplock
                 */
                fsp->oplock_type = NO_OPLOCK;
        }
 
-       set_share_mode(lck, fsp, get_current_uid(conn),
-                       req ? req->mid : 0,
-                      fsp->oplock_type);
+       if (!set_share_mode(lck, fsp, get_current_uid(conn),
+                           req ? req->mid : 0,
+                           fsp->oplock_type)) {
+               TALLOC_FREE(lck);
+               fd_close(fsp);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        /* Handle strange delete on close create semantics. */
        if (create_options & FILE_DELETE_ON_CLOSE) {
@@ -3163,9 +3156,16 @@ static NTSTATUS open_directory(connection_struct *conn,
                return NT_STATUS_SHARING_VIOLATION;
        }
 
-       status = open_mode_check(conn, lck, fsp->name_hash,
+       if (has_delete_on_close(lck, fsp->name_hash)) {
+               TALLOC_FREE(lck);
+               fd_close(fsp);
+               file_free(req, fsp);
+               return NT_STATUS_DELETE_PENDING;
+       }
+
+       status = open_mode_check(conn, lck,
                                access_mask, share_access,
-                                create_options, &dir_existed);
+                                &dir_existed);
 
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(lck);
@@ -3174,14 +3174,20 @@ static NTSTATUS open_directory(connection_struct *conn,
                return status;
        }
 
-       set_share_mode(lck, fsp, get_current_uid(conn),
-                       req ? req->mid : 0, NO_OPLOCK);
+       if (!set_share_mode(lck, fsp, get_current_uid(conn),
+                           req ? req->mid : 0, NO_OPLOCK)) {
+               TALLOC_FREE(lck);
+               fd_close(fsp);
+               file_free(req, fsp);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        /* For directories the delete on close bit at open time seems
           always to be honored on close... See test 19 in Samba4 BASE-DELETE. */
        if (create_options & FILE_DELETE_ON_CLOSE) {
                status = can_set_delete_on_close(fsp, 0);
                if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) {
+                       del_share_mode(lck, fsp);
                        TALLOC_FREE(lck);
                        fd_close(fsp);
                        file_free(req, fsp);