r17105: Fix the race Volker found - we had a non-locked
authorJeremy Allison <jra@samba.org>
Tue, 18 Jul 2006 01:05:51 +0000 (01:05 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:38:12 +0000 (11:38 -0500)
region between detecting a pending lock was needed
and when we added the blocking lock record. Make
sure that we hold the lock over all this period.
Removed the old code for doing blocking locks on
SMB requests that never block (the old SMBlock
and friends).
Discovered something interesting about the strange
NT_STATUS_FILE_LOCK_CONFLICT return. If we asked
for a lock with zero timeout, and we got an error
of NT_STATUS_FILE_LOCK_CONFLICT, treat it as though
it was a blocking lock with a timeout of 150 - 300ms.
This only happens when timeout is sent as zero and
can be seen quite clearly in ethereal. This is the
real replacement for old do_lock_spin() code.
Re-worked the blocking lock select timeout to correctly
use milliseconds instead of the old second level
resolution (far too coarse for this work).
Jeremy.
(This used to be commit b81d6d1ae95a3d3e449dde629884b565eac289d9)

source3/locking/brlock.c
source3/locking/locking.c
source3/smbd/blocking.c
source3/smbd/process.c
source3/smbd/reply.c
source3/smbd/trans2.c

index f251ff57ec794f355be79289387fbf3e3e312fc2..20bb4314b6398889f3635b3471df86a62a079909 100644 (file)
@@ -216,14 +216,14 @@ static BOOL brl_conflict_other(const struct lock_struct *lck1, const struct lock
  app depends on this ?
 ****************************************************************************/
 
-static NTSTATUS brl_lock_failed(files_struct *fsp, const struct lock_struct *lock, int32 lock_timeout)
+static NTSTATUS brl_lock_failed(files_struct *fsp, const struct lock_struct *lock, BOOL blocking_lock)
 {
        if (lock->start >= 0xEF000000 && (lock->start >> 63) == 0) {
                /* amazing the little things you learn with a test
                   suite. Locks beyond this offset (as a 64 bit
                   number!) always generate the conflict error code,
                   unless the top bit is set */
-               if (lock_timeout == 0) {
+               if (!blocking_lock) {
                        fsp->last_lock_failure = *lock;
                }
                return NT_STATUS_FILE_LOCK_CONFLICT;
@@ -236,7 +236,7 @@ static NTSTATUS brl_lock_failed(files_struct *fsp, const struct lock_struct *loc
                return NT_STATUS_FILE_LOCK_CONFLICT;
        }
 
-       if (lock_timeout == 0) {
+       if (!blocking_lock) {
                fsp->last_lock_failure = *lock;
        }
        return NT_STATUS_LOCK_NOT_GRANTED;
@@ -297,7 +297,7 @@ static int lock_compare(const struct lock_struct *lck1,
 ****************************************************************************/
 
 static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
-                       const struct lock_struct *plock, int32 lock_timeout)
+                       const struct lock_struct *plock, BOOL blocking_lock)
 {
        unsigned int i;
        files_struct *fsp = br_lck->fsp;
@@ -306,7 +306,7 @@ static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
        for (i=0; i < br_lck->num_locks; i++) {
                /* Do any Windows or POSIX locks conflict ? */
                if (brl_conflict(&locks[i], plock)) {
-                       return brl_lock_failed(fsp,plock,lock_timeout);
+                       return brl_lock_failed(fsp,plock,blocking_lock);
                }
 #if ZERO_ZERO
                if (plock->start == 0 && plock->size == 0 && 
@@ -676,7 +676,7 @@ NTSTATUS brl_lock(struct byte_range_lock *br_lck,
                br_off size, 
                enum brl_type lock_type,
                enum brl_flavour lock_flav,
-               int32 lock_timeout)
+               BOOL blocking_lock)
 {
        NTSTATUS ret;
        struct lock_struct lock;
@@ -697,7 +697,7 @@ NTSTATUS brl_lock(struct byte_range_lock *br_lck,
        lock.lock_flav = lock_flav;
 
        if (lock_flav == WINDOWS_LOCK) {
-               ret = brl_lock_windows(br_lck, &lock, lock_timeout);
+               ret = brl_lock_windows(br_lck, &lock, blocking_lock);
        } else {
                ret = brl_lock_posix(br_lck, &lock);
        }
index cd1d9547f3d32207f488d13f11ce611cb7e17a3d..a7cadd3a400826927b93a3129062ef3497e96809 100644 (file)
@@ -179,23 +179,25 @@ NTSTATUS query_lock(files_struct *fsp,
  Utility function called by locking requests.
 ****************************************************************************/
 
-NTSTATUS do_lock(files_struct *fsp,
+struct byte_range_lock *do_lock(files_struct *fsp,
                        uint32 lock_pid,
                        SMB_BIG_UINT count,
                        SMB_BIG_UINT offset,
                        enum brl_type lock_type,
                        enum brl_flavour lock_flav,
-                       int32 lock_timeout)
+                       BOOL blocking_lock,
+                       NTSTATUS *perr)
 {
        struct byte_range_lock *br_lck = NULL;
-       NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED;
 
        if (!fsp->can_lock) {
-               return fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
+               *perr = fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
+               return NULL;
        }
 
        if (!lp_locking(SNUM(fsp->conn))) {
-               return NT_STATUS_OK;
+               *perr = NT_STATUS_OK;
+               return NULL;
        }
 
        /* NOTE! 0 byte long ranges ARE allowed and should be stored  */
@@ -206,20 +208,20 @@ NTSTATUS do_lock(files_struct *fsp,
 
        br_lck = brl_get_locks(NULL, fsp);
        if (!br_lck) {
-               return NT_STATUS_NO_MEMORY;
+               *perr = NT_STATUS_NO_MEMORY;
+               return NULL;
        }
 
-       status = brl_lock(br_lck,
+       *perr = brl_lock(br_lck,
                        lock_pid,
                        procid_self(),
                        offset,
                        count, 
                        lock_type,
                        lock_flav,
-                       lock_timeout);
+                       blocking_lock);
 
-       TALLOC_FREE(br_lck);
-       return status;
+       return br_lck;
 }
 
 /****************************************************************************
index 941e87d3ad70b9098f54afe2c0c3b4cefa68924c..a0b93f5032034fd2fb6f57058c44c3ef524e0402 100644 (file)
@@ -32,7 +32,7 @@ typedef struct _blocking_lock_record {
        struct _blocking_lock_record *prev;
        int com_type;
        files_struct *fsp;
-       time_t expire_time;
+       struct timeval expire_time;
        int lock_num;
        SMB_BIG_UINT offset;
        SMB_BIG_UINT count;
@@ -75,7 +75,8 @@ static void received_unlock_msg(int msg_type, struct process_id src,
  Function to push a blocking lock request onto the lock queue.
 ****************************************************************************/
 
-BOOL push_blocking_lock_request( char *inbuf, int length,
+BOOL push_blocking_lock_request( struct byte_range_lock *br_lck,
+               char *inbuf, int length,
                files_struct *fsp,
                int lock_timeout,
                int lock_num,
@@ -86,7 +87,6 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
 {
        static BOOL set_lock_msg;
        blocking_lock_record *blr, *tmp;
-       struct byte_range_lock *br_lck = NULL;
        NTSTATUS status;
 
        if(in_chained_smb() ) {
@@ -115,7 +115,13 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
 
        blr->com_type = CVAL(inbuf,smb_com);
        blr->fsp = fsp;
-       blr->expire_time = (lock_timeout == -1) ? (time_t)-1 : time(NULL) + (time_t)lock_timeout;
+       if (lock_timeout == -1) {
+               blr->expire_time.tv_sec = 0;
+               blr->expire_time.tv_usec = 0; /* Never expire. */
+       } else {
+               blr->expire_time = timeval_current_ofs(lock_timeout/1000,
+                                       (lock_timeout % 1000) * 1000);
+       }
        blr->lock_num = lock_num;
        blr->lock_pid = lock_pid;
        blr->lock_flav = lock_flav;
@@ -125,13 +131,6 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
        memcpy(blr->inbuf, inbuf, length);
        blr->length = length;
 
-       br_lck = brl_get_locks(NULL, blr->fsp);
-       if (!br_lck) {
-               DLIST_REMOVE(blocking_lock_queue, blr);
-               free_blocking_lock_record(blr);
-               return False;
-       }
-
        /* Add a pending lock record for this. */
        status = brl_lock(br_lck,
                        lock_pid,
@@ -140,8 +139,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
                        count,
                        PENDING_LOCK,
                        blr->lock_flav,
-                       lock_timeout);
-       TALLOC_FREE(br_lck);
+                       lock_timeout ? True : False); /* blocking_lock. */
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
@@ -158,8 +156,10 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
                set_lock_msg = True;
        }
 
-       DEBUG(3,("push_blocking_lock_request: lock request length=%d blocked with expiry time %d (+%d) \
-for fnum = %d, name = %s\n", length, (int)blr->expire_time, lock_timeout,
+       DEBUG(3,("push_blocking_lock_request: lock request length=%d blocked with "
+               "expiry time (%u sec. %u usec) (+%d msec) for fnum = %d, name = %s\n",
+               length, (unsigned int)blr->expire_time.tv_sec,
+               (unsigned int)blr->expire_time.tv_usec, lock_timeout,
                blr->fsp->fnum, blr->fsp->fsp_name ));
 
        /* Push the MID of this packet on the signing queue. */
@@ -305,13 +305,6 @@ static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
 static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
 {
        switch(blr->com_type) {
-#if 0
-       /* We no longer push blocking lock requests for anything but lockingX and trans2. */
-       case SMBlock:
-       case SMBlockread:
-               generic_blocking_lock_error(blr, status);
-               break;
-#endif
        case SMBlockingX:
                reply_lockingX_error(blr, status);
                break;
@@ -337,146 +330,6 @@ static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status
        }
 }
 
-#if 0
-/* We no longer push blocking lock requests for anything but lockingX and trans2. */
-
-/****************************************************************************
- Attempt to finish off getting all pending blocking locks for a lockread call.
- Returns True if we want to be removed from the list.
-*****************************************************************************/
-
-static BOOL process_lockread(blocking_lock_record *blr)
-{
-       char *outbuf = get_OutBuffer();
-       char *inbuf = blr->inbuf;
-       ssize_t nread = -1;
-       char *data, *p;
-       int outsize = 0;
-       SMB_BIG_UINT startpos;
-       size_t numtoread;
-       NTSTATUS status;
-       files_struct *fsp = blr->fsp;
-
-       numtoread = SVAL(inbuf,smb_vwv1);
-       startpos = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv2);
-       
-       numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
-       data = smb_buf(outbuf) + 3;
-       status = do_lock(fsp,
-                       (uint32)SVAL(inbuf,smb_pid),
-                       (SMB_BIG_UINT)numtoread,
-                       startpos,
-                       READ_LOCK,
-                       WINDOWS_LOCK,
-                       (int32)-1);
-
-       if (NT_STATUS_V(status)) {
-               if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
-                       !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
-                       /*
-                        * We have other than a "can't get lock"
-                        * error. Send an error.
-                        * Return True so we get dequeued.
-                        */
-                       generic_blocking_lock_error(blr, status);
-                       return True;
-               }
-
-               /*
-                * Still waiting for lock....
-                */
-               
-               DEBUG(10,("process_lockread: failed to get lock for file = %s. Still waiting....\n",
-                         fsp->fsp_name));
-               return False;
-       }
-
-       nread = read_file(fsp,data,startpos,numtoread);
-
-       if (nread < 0) {
-               generic_blocking_lock_error(blr,NT_STATUS_ACCESS_DENIED);
-               return True;
-       }
-       
-       construct_reply_common(inbuf, outbuf);
-       outsize = set_message(outbuf,5,0,True);
-       
-       outsize += nread;
-       SSVAL(outbuf,smb_vwv0,nread);
-       SSVAL(outbuf,smb_vwv5,nread+3);
-       p = smb_buf(outbuf);
-       *p++ = 1;
-       SSVAL(p,0,nread); p += 2;
-       set_message_end(outbuf, p+nread);
-       
-       DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%lu nread=%ld\n",
-                  fsp->fsp_name, fsp->fnum, (unsigned long)numtoread, (long)nread ) );
-       
-       send_blocking_reply(outbuf,outsize);
-       return True;
-}
-
-/****************************************************************************
- Attempt to finish off getting all pending blocking locks for a lock call.
- Returns True if we want to be removed from the list.
-*****************************************************************************/
-
-static BOOL process_lock(blocking_lock_record *blr)
-{
-       char *outbuf = get_OutBuffer();
-       char *inbuf = blr->inbuf;
-       int outsize;
-       SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
-       NTSTATUS status;
-       files_struct *fsp = blr->fsp;
-
-       count = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
-       offset = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
-
-       errno = 0;
-       status = do_lock(fsp,
-                       (uint32)SVAL(inbuf,smb_pid),
-                       count,
-                       offset,
-                       WRITE_LOCK,
-                       WINDOWS_LOCK,
-                       (int32)-1);
-
-       if (NT_STATUS_IS_ERR(status)) {
-               if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
-                       !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
-                       /*
-                        * We have other than a "can't get lock"
-                        * error. Send an error.
-                        * Return True so we get dequeued.
-                        */
-                       
-                       blocking_lock_reply_error(blr, status);
-                       return True;
-               }
-               /*
-                * Still can't get the lock - keep waiting.
-                */
-               DEBUG(10,("process_lock: failed to get lock for file = %s. Still waiting....\n",
-                         fsp->fsp_name));
-               return False;
-       }
-
-       /*
-        * Success - we got the lock.
-        */
-       
-       DEBUG(3,("process_lock : file=%s fnum=%d offset=%.0f count=%.0f\n",
-                fsp->fsp_name, fsp->fnum, (double)offset, (double)count));
-       
-       construct_reply_common(inbuf, outbuf);
-       outsize = set_message(outbuf,0,0,True);
-       send_blocking_reply(outbuf,outsize);
-       return True;
-}
-#endif
-
 /****************************************************************************
  Attempt to finish off getting all pending blocking locks for a lockingX call.
  Returns True if we want to be removed from the list.
@@ -501,8 +354,9 @@ static BOOL process_lockingX(blocking_lock_record *blr)
         * Data now points at the beginning of the list
         * of smb_lkrng structs.
         */
-       
+
        for(; blr->lock_num < num_locks; blr->lock_num++) {
+               struct byte_range_lock *br_lck = NULL;
                BOOL err;
 
                lock_pid = get_lock_pid( data, blr->lock_num, large_file_format);
@@ -514,14 +368,17 @@ static BOOL process_lockingX(blocking_lock_record *blr)
                 * request would never have been queued. JRA.
                 */
                errno = 0;
-               status = do_lock(fsp,
+               br_lck = do_lock(fsp,
                                lock_pid,
                                count,
                                offset, 
                                ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
                                        READ_LOCK : WRITE_LOCK),
                                WINDOWS_LOCK,
-                               (int32)-1);
+                               True,
+                               &status);
+
+               TALLOC_FREE(br_lck);
 
                if (NT_STATUS_IS_ERR(status)) {
                        break;
@@ -573,14 +430,15 @@ static BOOL process_trans2(blocking_lock_record *blr)
        char *outbuf;
        char params[2];
        NTSTATUS status;
-
-       status = do_lock(blr->fsp,
-                       blr->lock_pid,
-                       blr->count,
-                       blr->offset,
-                       blr->lock_type,
-                       blr->lock_flav,
-                       (int32)-1);
+       struct byte_range_lock *br_lck = do_lock(blr->fsp,
+                                               blr->lock_pid,
+                                               blr->count,
+                                               blr->offset,
+                                               blr->lock_type,
+                                               blr->lock_flav,
+                                               True,
+                                               &status);
+       TALLOC_FREE(br_lck);
 
        if (!NT_STATUS_IS_OK(status)) {
                if (ERROR_WAS_LOCK_DENIED(status)) {
@@ -613,13 +471,6 @@ static BOOL process_trans2(blocking_lock_record *blr)
 static BOOL blocking_lock_record_process(blocking_lock_record *blr)
 {
        switch(blr->com_type) {
-#if 0
-               /* We no longer push blocking lock requests for anything but lockingX and trans2. */
-               case SMBlock:
-                       return process_lock(blr);
-               case SMBlockread:
-                       return process_lockread(blr);
-#endif
                case SMBlockingX:
                        return process_lockingX(blr);
                case SMBtrans2:
@@ -714,44 +565,60 @@ static void received_unlock_msg(int msg_type, struct process_id src,
                                void *buf, size_t len)
 {
        DEBUG(10,("received_unlock_msg\n"));
-       process_blocking_lock_queue(time(NULL));
+       process_blocking_lock_queue();
 }
 
 /****************************************************************************
- Return the number of seconds to the next blocking locks timeout, or default_timeout
+ Return the number of milliseconds to the next blocking locks timeout, or default_timeout
 *****************************************************************************/
 
-unsigned blocking_locks_timeout(unsigned default_timeout)
+unsigned int blocking_locks_timeout_ms(unsigned int default_timeout_ms)
 {
-       unsigned timeout = default_timeout;
-       time_t t;
+       unsigned int timeout_ms = default_timeout_ms;
+       struct timeval tv_curr;
+       SMB_BIG_INT min_tv_dif_us = 0x7FFFFFFF; /* A large +ve number. */
        blocking_lock_record *blr = blocking_lock_queue;
 
-       /* note that we avoid the time() syscall if there are no blocking locks */
-       if (!blr)
-               return timeout;
+       /* note that we avoid the GetTimeOfDay() syscall if there are no blocking locks */
+       if (!blr) {
+               return timeout_ms;
+       }
 
-       t = time(NULL);
+       tv_curr = timeval_current();
 
        for (; blr; blr = blr->next) {
-               if ((blr->expire_time != (time_t)-1) &&
-                                       (timeout > (blr->expire_time - t))) {
-                       timeout = blr->expire_time - t;
+               SMB_BIG_INT tv_dif_us;
+
+               if (timeval_is_zero(&blr->expire_time)) {
+                       continue; /* Never timeout. */
                }
+
+               tv_dif_us = usec_time_diff(&blr->expire_time, &tv_curr);
+               min_tv_dif_us = MIN(min_tv_dif_us, tv_dif_us);
+       }
+
+       if (min_tv_dif_us < 0) {
+               min_tv_dif_us = 0;
+       }
+
+       timeout_ms = (unsigned int)(min_tv_dif_us / (SMB_BIG_INT)1000);
+
+       if (timeout_ms < 1) {
+               timeout_ms = 1;
        }
 
-       if (timeout < 1)
-               timeout = 1;
+       DEBUG(10,("blocking_locks_timeout_ms: returning %u\n", timeout_ms));
 
-       return timeout;
+       return timeout_ms;
 }
 
 /****************************************************************************
  Process the blocking lock queue. Note that this is only called as root.
 *****************************************************************************/
 
-void process_blocking_lock_queue(time_t t)
+void process_blocking_lock_queue(void)
 {
+       struct timeval tv_curr = timeval_current();
        blocking_lock_record *blr, *next = NULL;
 
        /*
@@ -780,7 +647,7 @@ void process_blocking_lock_queue(time_t t)
                DEBUG(5,("process_blocking_lock_queue: examining pending lock fnum = %d for file %s\n",
                        fsp->fnum, fsp->fsp_name ));
 
-               if((blr->expire_time != -1) && (blr->expire_time <= t)) {
+               if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) {
                        struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
 
                        /*
index ce352adfd7d079f7c6d7d7a8f8790a15caf8d6a8..f8c66d93eaebdd261d9f8f5dcea055a56d73bb3d 100644 (file)
@@ -1276,7 +1276,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
 }
 
 /****************************************************************************
- Setup the needed select timeout.
+ Setup the needed select timeout in milliseconds.
 ****************************************************************************/
 
 static int setup_select_timeout(void)
@@ -1284,16 +1284,17 @@ static int setup_select_timeout(void)
        int select_timeout;
        int t;
 
-       select_timeout = blocking_locks_timeout(SMBD_SELECT_TIMEOUT);
-       select_timeout *= 1000;
+       select_timeout = blocking_locks_timeout_ms(SMBD_SELECT_TIMEOUT*1000);
 
        t = change_notify_timeout();
        DEBUG(10, ("change_notify_timeout: %d\n", t));
-       if (t != -1)
+       if (t != -1) {
                select_timeout = MIN(select_timeout, t*1000);
+       }
 
-       if (print_notify_messages_pending())
+       if (print_notify_messages_pending()) {
                select_timeout = MIN(select_timeout, 1000);
+       }
 
        return select_timeout;
 }
@@ -1482,7 +1483,7 @@ machine %s in domain %s.\n", global_myname(), lp_workgroup()));
         * Check to see if we have any blocking locks
         * outstanding on the queue.
         */
-       process_blocking_lock_queue(t);
+       process_blocking_lock_queue();
 
        /* update printer queue caches if necessary */
   
index ec618db3f854b6aa934b90030e76837ad5810647..6176edb52d0e907f50b498876219bfaec859b588 100644 (file)
@@ -2371,6 +2371,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
        size_t numtoread;
        NTSTATUS status;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       struct byte_range_lock *br_lck = NULL;
        START_PROFILE(SMBlockread);
 
        CHECK_FSP(fsp,conn);
@@ -2395,42 +2396,17 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
         * Note that the requested lock size is unaffected by max_recv.
         */
        
-       status = do_lock(fsp,
+       br_lck = do_lock(fsp,
                        (uint32)SVAL(inbuf,smb_pid), 
                        (SMB_BIG_UINT)numtoread,
                        (SMB_BIG_UINT)startpos,
                        WRITE_LOCK,
                        WINDOWS_LOCK,
-                       0 /* zero timeout. */);
+                       False, /* Non-blocking lock. */
+                       &status);
+       TALLOC_FREE(br_lck);
 
        if (NT_STATUS_V(status)) {
-#if 0
-               /*
-                * We used to make lockread a blocking lock. It turns out
-                * that this isn't on W2k. Found by the Samba 4 RAW-READ torture
-                * tester. JRA.
-                */
-
-               if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
-                       /*
-                        * A blocking lock was requested. Package up
-                        * this smb into a queued request and push it
-                        * onto the blocking lock queue.
-                        */
-                       if(push_blocking_lock_request(inbuf, length,
-                                       fsp,
-                                       -1,
-                                       0,
-                                       SVAL(inbuf,smb_pid),
-                                       WRITE_LOCK,
-                                       WINDOWS_LOCK,
-                                       (SMB_BIG_UINT)startpos,
-                                       (SMB_BIG_UINT)numtoread)) {
-                               END_PROFILE(SMBlockread);
-                               return -1;
-                       }
-               }
-#endif
                END_PROFILE(SMBlockread);
                return ERROR_NT(status);
        }
@@ -3417,6 +3393,7 @@ int reply_lock(connection_struct *conn,
        SMB_BIG_UINT count,offset;
        NTSTATUS status;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       struct byte_range_lock *br_lck = NULL;
 
        START_PROFILE(SMBlock);
 
@@ -3430,36 +3407,18 @@ int reply_lock(connection_struct *conn,
        DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
                 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
 
-       status = do_lock(fsp,
+       br_lck = do_lock(fsp,
                        (uint32)SVAL(inbuf,smb_pid),
                        count,
                        offset,
                        WRITE_LOCK,
                        WINDOWS_LOCK,
-                       0 /* zero timeout. */);
+                       False, /* Non-blocking lock. */
+                       &status);
+
+       TALLOC_FREE(br_lck);
 
        if (NT_STATUS_V(status)) {
-#if 0
-               /* Tests using Samba4 against W2K show this call never creates a blocking lock. */
-               if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
-                       /*
-                        * A blocking lock was requested. Package up
-                        * this smb into a queued request and push it
-                        * onto the blocking lock queue.
-                        */
-                       if(push_blocking_lock_request(inbuf, length,
-                               fsp,
-                               -1,
-                               0,
-                               SVAL(inbuf,smb_pid),
-                               WRITE_LOCK,
-                               WINDOWS_LOCK,
-                               offset, count)) {
-                               END_PROFILE(SMBlock);
-                               return -1;
-                       }
-               }
-#endif
                END_PROFILE(SMBlock);
                return ERROR_NT(status);
        }
@@ -5353,9 +5312,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
 
        /* Setup the timeout in seconds. */
 
-       if (lp_blocking_locks(SNUM(conn))) {
-               lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000);
-       } else {
+       if (!lp_blocking_locks(SNUM(conn))) {
                lock_timeout = 0;
        }
        
@@ -5410,42 +5367,57 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                                offset,
                                                WINDOWS_LOCK);
                } else {
-                       status = do_lock(fsp,
+                       BOOL blocking_lock = lock_timeout ? True : False;
+                       BOOL defer_lock = False;
+                       struct byte_range_lock *br_lck;
+
+                       br_lck = do_lock(fsp,
                                        lock_pid,
                                        count,
                                        offset, 
                                        lock_type,
                                        WINDOWS_LOCK,
-                                       lock_timeout);
+                                       blocking_lock,
+                                       &status);
 
-                       if (NT_STATUS_V(status)) {
+                       if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
+                               defer_lock = True;
+                       }
+
+                       /* This heuristic seems to match W2K3 very well. If a
+                          lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
+                          it pretends we asked for a timeout of between 150 - 300 milliseconds as
+                          far as I can tell. Replacement for do_lock_spin(). JRA. */
+
+                       if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
+                                       NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
+                               defer_lock = True;
+                               lock_timeout = 200;
+                       }
+
+                       if (br_lck && defer_lock) {
                                /*
-                                * Interesting fact found by IFSTEST /t
-                                * LockOverlappedTest...  Even if it's our own lock
-                                * context, we need to wait here as there may be an
-                                * unlock on the way. JRA.
+                                * A blocking lock was requested. Package up
+                                * this smb into a queued request and push it
+                                * onto the blocking lock queue.
                                 */
-                               if ((lock_timeout != 0) &&
-                                   ERROR_WAS_LOCK_DENIED(status)) {
-                                       /*
-                                        * A blocking lock was requested. Package up
-                                        * this smb into a queued request and push it
-                                        * onto the blocking lock queue.
-                                        */
-                                       if(push_blocking_lock_request(inbuf, length,
-                                                             fsp,
-                                                             lock_timeout,
-                                                             i,
-                                                             lock_pid,
-                                                             lock_type,
-                                                             WINDOWS_LOCK,
-                                                             offset,
-                                                             count)) {
-                                               END_PROFILE(SMBlockingX);
-                                               return -1;
-                                       }
+                               if(push_blocking_lock_request(br_lck,
+                                                       inbuf, length,
+                                                       fsp,
+                                                       lock_timeout,
+                                                       i,
+                                                       lock_pid,
+                                                       lock_type,
+                                                       WINDOWS_LOCK,
+                                                       offset,
+                                                       count)) {
+                                       TALLOC_FREE(br_lck);
+                                       END_PROFILE(SMBlockingX);
+                                       return -1;
                                }
                        }
+
+                       TALLOC_FREE(br_lck);
                }
 
                if (NT_STATUS_V(status)) {
index 199204684f96e6a92274d03ba67c2330d3f2e5c8..5acce13e52d78e8ce15abbae9127ab41090afd56 100644 (file)
@@ -4503,7 +4503,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        SMB_BIG_UINT count;
                        SMB_BIG_UINT offset;
                        uint32 lock_pid;
-                       BOOL lock_blocking = False;
+                       BOOL blocking_lock = False;
                        enum brl_type lock_type;
 
                        if (fsp == NULL || fsp->fh->fd == -1) {
@@ -4533,15 +4533,15 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        }
 
                        if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
-                               lock_blocking = False;
+                               blocking_lock = False;
                        } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
-                               lock_blocking = True;
+                               blocking_lock = True;
                        } else {
                                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
                        }
 
                        if (!lp_blocking_locks(SNUM(conn))) { 
-                               lock_blocking = False;
+                               blocking_lock = False;
                        }
 
                        lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
@@ -4562,21 +4562,23 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                                offset,
                                                POSIX_LOCK);
                        } else {
-                               status = do_lock(fsp,
-                                               lock_pid,
-                                               count,
-                                               offset,
-                                               lock_type,
-                                               lock_blocking ? -1 : 0,                                         
-                                               POSIX_LOCK);
-
-                               if (lock_blocking && ERROR_WAS_LOCK_DENIED(status)) {
+                               struct byte_range_lock *br_lck = do_lock(fsp,
+                                                                       lock_pid,
+                                                                       count,
+                                                                       offset,
+                                                                       lock_type,
+                                                                       blocking_lock,
+                                                                       POSIX_LOCK,
+                                                                       &status);
+
+                               if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
                                        /*
                                         * A blocking lock was requested. Package up
                                         * this smb into a queued request and push it
                                         * onto the blocking lock queue.
                                         */
-                                       if(push_blocking_lock_request(inbuf, length,
+                                       if(push_blocking_lock_request(br_lck,
+                                                               inbuf, length,
                                                                fsp,
                                                                -1, /* infinite timeout. */
                                                                0,
@@ -4585,9 +4587,11 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                                                POSIX_LOCK,
                                                                offset,
                                                                count)) {
+                                               TALLOC_FREE(br_lck);
                                                return -1;
                                        }
                                }
+                               TALLOC_FREE(br_lck);
                        }
 
                        if (!NT_STATUS_IS_OK(status)) {