diff options
-rw-r--r-- | source3/locking/brlock.c | 14 | ||||
-rw-r--r-- | source3/locking/locking.c | 22 | ||||
-rw-r--r-- | source3/smbd/blocking.c | 261 | ||||
-rw-r--r-- | source3/smbd/process.c | 13 | ||||
-rw-r--r-- | source3/smbd/reply.c | 134 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 32 |
6 files changed, 161 insertions, 315 deletions
diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index f251ff57ec..20bb4314b6 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -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); } diff --git a/source3/locking/locking.c b/source3/locking/locking.c index cd1d9547f3..a7cadd3a40 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -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; } /**************************************************************************** diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 941e87d3ad..a0b93f5032 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -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); /* diff --git a/source3/smbd/process.c b/source3/smbd/process.c index ce352adfd7..f8c66d93ea 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -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 */ diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index ec618db3f8..6176edb52d 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -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)) { diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 199204684f..5acce13e52 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -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)) { |