summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/locking/brlock.c14
-rw-r--r--source3/locking/locking.c22
-rw-r--r--source3/smbd/blocking.c261
-rw-r--r--source3/smbd/process.c13
-rw-r--r--source3/smbd/reply.c134
-rw-r--r--source3/smbd/trans2.c32
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)) {