s3: Remove share mode handling before we open the file
authorVolker Lendecke <vl@samba.org>
Thu, 13 Sep 2012 13:40:17 +0000 (15:40 +0200)
committerVolker Lendecke <vl@samba.org>
Sat, 29 Sep 2012 15:42:49 +0000 (08:42 -0700)
This is a significant behaviour change: We do not open the file under
the share mode lock anymore. This might lead to more open calls in case
of oplock breaks or sharing violations, but those are slow error paths
and as such might be not too performance sensitive. The benefit of this
patch is a significant reduction of complexity of open_file_ntcreate()

source3/smbd/open.c

index 9c9eff5..a67f810 100644 (file)
@@ -2214,209 +2214,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                request_time = fsp->open_time;
        }
 
-       if (file_existed) {
-               struct share_mode_entry *batch_entry = NULL;
-               struct share_mode_entry *exclusive_entry = NULL;
-               bool got_level2_oplock = false;
-               bool got_a_none_oplock = false;
-               struct file_id id;
-
-               struct timespec old_write_time = smb_fname->st.st_ex_mtime;
-               id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
-
-               lck = get_share_mode_lock(talloc_tos(), id,
-                                         conn->connectpath,
-                                         smb_fname, &old_write_time);
-               if (lck == NULL) {
-                       DEBUG(0, ("Could not get share mode lock\n"));
-                       return NT_STATUS_SHARING_VIOLATION;
-               }
-
-               /* Get the types we need to examine. */
-               find_oplock_types(fsp,
-                               oplock_request,
-                               lck,
-                               &batch_entry,
-                               &exclusive_entry,
-                               &got_level2_oplock,
-                               &got_a_none_oplock);
-
-               /* First pass - send break only on batch oplocks. */
-               if ((req != NULL) &&
-                               delay_for_batch_oplocks(fsp,
-                                       req->mid,
-                                       oplock_request,
-                                       batch_entry)) {
-                       schedule_defer_open(lck, request_time, req);
-                       TALLOC_FREE(lck);
-                       return NT_STATUS_SHARING_VIOLATION;
-               }
-
-               /* Use the client requested access mask here, not the one we
-                * open with. */
-               status = open_mode_check(conn, lck, fsp->name_hash,
-                                       access_mask, share_access,
-                                        create_options, &file_existed);
-
-               if (NT_STATUS_IS_OK(status)) {
-                       /* We might be going to allow this open. Check oplock
-                        * status again. */
-                       /* Second pass - send break for both batch or
-                        * exclusive oplocks. */
-                       if ((req != NULL) &&
-                                       delay_for_exclusive_oplocks(
-                                               fsp,
-                                               req->mid,
-                                               oplock_request,
-                                               exclusive_entry)) {
-                               schedule_defer_open(lck, request_time, req);
-                               TALLOC_FREE(lck);
-                               return NT_STATUS_SHARING_VIOLATION;
-                       }
-               }
-
-               if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
-                       /* DELETE_PENDING is not deferred for a second */
-                       TALLOC_FREE(lck);
-                       return status;
-               }
-
-               grant_fsp_oplock_type(fsp,
-                                oplock_request,
-                                got_level2_oplock,
-                                got_a_none_oplock);
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       uint32 can_access_mask;
-                       bool can_access = True;
-
-                       SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
-
-                       /* Check if this can be done with the deny_dos and fcb
-                        * calls. */
-                       if (private_flags &
-                           (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
-                            NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
-                               if (req == NULL) {
-                                       DEBUG(0, ("DOS open without an SMB "
-                                                 "request!\n"));
-                                       TALLOC_FREE(lck);
-                                       return NT_STATUS_INTERNAL_ERROR;
-                               }
-
-                               /* Use the client requested access mask here,
-                                * not the one we open with. */
-                               status = fcb_or_dos_open(req,
-                                                       conn,
-                                                       fsp,
-                                                       smb_fname,
-                                                       id,
-                                                       req->smbpid,
-                                                       req->vuid,
-                                                       access_mask,
-                                                       share_access,
-                                                       create_options);
-
-                               if (NT_STATUS_IS_OK(status)) {
-                                       TALLOC_FREE(lck);
-                                       if (pinfo) {
-                                               *pinfo = FILE_WAS_OPENED;
-                                       }
-                                       return NT_STATUS_OK;
-                               }
-                       }
-
-                       /*
-                        * This next line is a subtlety we need for
-                        * MS-Access. If a file open will fail due to share
-                        * permissions and also for security (access) reasons,
-                        * we need to return the access failed error, not the
-                        * share error. We can't open the file due to kernel
-                        * oplock deadlock (it's possible we failed above on
-                        * the open_mode_check()) so use a userspace check.
-                        */
-
-                       if (flags & O_RDWR) {
-                               can_access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
-                       } else if (flags & O_WRONLY) {
-                               can_access_mask = FILE_WRITE_DATA;
-                       } else {
-                               can_access_mask = FILE_READ_DATA;
-                       }
-
-                       if (((can_access_mask & FILE_WRITE_DATA) &&
-                               !CAN_WRITE(conn)) ||
-                               !NT_STATUS_IS_OK(smbd_check_access_rights(conn,
-                                                       smb_fname,
-                                                       false,
-                                                       can_access_mask))) {
-                               can_access = False;
-                       }
-
-                       /*
-                        * If we're returning a share violation, ensure we
-                        * cope with the braindead 1 second delay.
-                        */
-
-                       if (!(oplock_request & INTERNAL_OPEN_ONLY) &&
-                           lp_defer_sharing_violations()) {
-                               struct timeval timeout;
-                               struct deferred_open_record state;
-                               int timeout_usecs;
-
-                               /* this is a hack to speed up torture tests
-                                  in 'make test' */
-                               timeout_usecs = lp_parm_int(SNUM(conn),
-                                                           "smbd","sharedelay",
-                                                           SHARING_VIOLATION_USEC_WAIT);
-
-                               /* This is a relative time, added to the absolute
-                                  request_time value to get the absolute timeout time.
-                                  Note that if this is the second or greater time we enter
-                                  this codepath for this particular request mid then
-                                  request_time is left as the absolute time of the *first*
-                                  time this request mid was processed. This is what allows
-                                  the request to eventually time out. */
-
-                               timeout = timeval_set(0, timeout_usecs);
-
-                               /* Nothing actually uses state.delayed_for_oplocks
-                                  but it's handy to differentiate in debug messages
-                                  between a 30 second delay due to oplock break, and
-                                  a 1 second delay for share mode conflicts. */
-
-                               state.delayed_for_oplocks = False;
-                               state.async_open = false;
-                               state.id = id;
-
-                               if ((req != NULL)
-                                   && !request_timed_out(request_time,
-                                                         timeout)) {
-                                       defer_open(lck, request_time, timeout,
-                                                  req, &state);
-                               }
-                       }
-
-                       TALLOC_FREE(lck);
-                       if (can_access) {
-                               /*
-                                * We have detected a sharing violation here
-                                * so return the correct error code
-                                */
-                               status = NT_STATUS_SHARING_VIOLATION;
-                       } else {
-                               status = NT_STATUS_ACCESS_DENIED;
-                       }
-                       return status;
-               }
-
-               /*
-                * We exit this block with the share entry *locked*.....
-                */
-       }
-
-       SMB_ASSERT(!file_existed || (lck != NULL));
-
        /*
         * Ensure we pay attention to default ACLs on directories if required.
         */
@@ -2468,7 +2265,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       if (!file_existed) {
+       {
                struct share_mode_entry *batch_entry = NULL;
                struct share_mode_entry *exclusive_entry = NULL;
                bool got_level2_oplock = false;