summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/locking/brlock.c9
-rw-r--r--source3/locking/locking.c11
-rw-r--r--source3/smbd/blocking.c14
-rw-r--r--source3/smbd/reply.c47
4 files changed, 61 insertions, 20 deletions
diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index 20d76c9c79..c51a5a2aac 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -172,7 +172,8 @@ static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck
}
if (lck1->start >= (lck2->start + lck2->size) ||
- lck2->start >= (lck1->start + lck1->size)) return False;
+ lck2->start >= (lck1->start + lck1->size))
+ return False;
return True;
}
@@ -305,7 +306,7 @@ static int lock_compare(struct lock_struct *lck1,
NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
uint16 smbpid, pid_t pid, uint16 tid,
br_off start, br_off size,
- enum brl_type lock_type)
+ enum brl_type lock_type, BOOL *my_lock_ctx)
{
TDB_DATA kbuf, dbuf;
int count, i;
@@ -315,6 +316,7 @@ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
static int last_failed = -1;
static br_off last_failed_start;
+ *my_lock_ctx = False;
kbuf = locking_key(dev,ino);
dbuf.dptr = NULL;
@@ -343,6 +345,9 @@ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
for (i=0; i<count; i++) {
if (brl_conflict(&locks[i], &lock)) {
status = NT_STATUS_LOCK_NOT_GRANTED;
+ /* Did we block ourselves ? */
+ if (brl_same_context(&locks[i].context, &lock.context))
+ *my_lock_ctx = True;
goto fail;
}
#if ZERO_ZERO
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index 91bc20af90..c3abd63818 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -98,7 +98,7 @@ BOOL is_locked(files_struct *fsp,connection_struct *conn,
****************************************************************************/
static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
- SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type)
+ SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type, BOOL *my_lock_ctx)
{
NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED;
@@ -114,7 +114,7 @@ static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_p
status = brl_lock(fsp->dev, fsp->inode, fsp->fnum,
lock_pid, sys_getpid(), conn->cnum,
offset, count,
- lock_type);
+ lock_type, my_lock_ctx);
if (NT_STATUS_IS_OK(status) && lp_posix_locking(SNUM(conn))) {
@@ -153,7 +153,7 @@ static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_p
****************************************************************************/
NTSTATUS do_lock_spin(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
- SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type)
+ SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type, BOOL *my_lock_ctx)
{
int j, maxj = lp_lock_spin_count();
int sleeptime = lp_lock_sleep_time();
@@ -165,7 +165,7 @@ NTSTATUS do_lock_spin(files_struct *fsp,connection_struct *conn, uint16 lock_pid
ret = NT_STATUS_OK; /* to keep dumb compilers happy */
for (j = 0; j < maxj; j++) {
- status = do_lock(fsp, conn, lock_pid, count, offset, lock_type);
+ status = do_lock(fsp, conn, lock_pid, count, offset, lock_type, my_lock_ctx);
if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED) &&
!NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
return status;
@@ -173,6 +173,9 @@ NTSTATUS do_lock_spin(files_struct *fsp,connection_struct *conn, uint16 lock_pid
/* if we do fail then return the first error code we got */
if (j == 0) {
ret = status;
+ /* Don't spin if we blocked ourselves. */
+ if (*my_lock_ctx)
+ return ret;
}
if (sleeptime)
sys_usleep(sleeptime);
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 8fa2a6494e..5c6ddbc6b7 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -91,6 +91,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
{
static BOOL set_lock_msg;
blocking_lock_record *blr;
+ BOOL my_lock_ctx = False;
NTSTATUS status;
if(in_chained_smb() ) {
@@ -127,7 +128,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
/* Add a pending lock record for this. */
status = brl_lock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
lock_pid, sys_getpid(), blr->fsp->conn->cnum,
- offset, count, PENDING_LOCK);
+ offset, count, PENDING_LOCK, &my_lock_ctx);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
@@ -302,6 +303,7 @@ static BOOL process_lockread(blocking_lock_record *blr)
NTSTATUS status;
connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
files_struct *fsp = blr->fsp;
+ BOOL my_lock_ctx = False;
numtoread = SVAL(inbuf,smb_vwv1);
startpos = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv2);
@@ -309,8 +311,7 @@ static BOOL process_lockread(blocking_lock_record *blr)
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
- status = do_lock_spin( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread,
- startpos, READ_LOCK);
+ status = do_lock_spin( fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, startpos, READ_LOCK, &my_lock_ctx);
if (NT_STATUS_V(status)) {
if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
!NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
@@ -371,13 +372,13 @@ static BOOL process_lock(blocking_lock_record *blr)
NTSTATUS status;
connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
files_struct *fsp = blr->fsp;
+ BOOL my_lock_ctx = False;
count = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
offset = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
errno = 0;
- status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count,
- offset, WRITE_LOCK);
+ status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx);
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)) {
@@ -428,6 +429,7 @@ static BOOL process_lockingX(blocking_lock_record *blr)
uint16 lock_pid;
BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
char *data;
+ BOOL my_lock_ctx = False;
NTSTATUS status = NT_STATUS_OK;
data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
@@ -450,7 +452,7 @@ static BOOL process_lockingX(blocking_lock_record *blr)
*/
errno = 0;
status = do_lock_spin(fsp,conn,lock_pid,count,offset,
- ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
+ ((locktype & 1) ? READ_LOCK : WRITE_LOCK), &my_lock_ctx);
if (NT_STATUS_IS_ERR(status)) break;
}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 2c8b768d70..5c1d7915c2 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1567,8 +1567,13 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
if (nread > 0) {
ret = read_file(fsp,outbuf+4,startpos,nread);
+#if 0 /* mincount appears to be ignored in a W2K server. JRA. */
if (ret < mincount)
ret = 0;
+#else
+ if (ret < nread)
+ ret = 0;
+#endif
}
_smb_setlen(outbuf,ret);
@@ -1668,7 +1673,6 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
/* ensure we don't overrun the packet size */
maxcount = MIN(65535,maxcount);
- maxcount = MAX(mincount,maxcount);
if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
SMB_OFF_T size = fsp->size;
@@ -1688,8 +1692,10 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
nread = MIN(maxcount,(size - startpos));
}
+#if 0 /* mincount appears to be ignored in a W2K server. JRA. */
if (nread < mincount)
nread = 0;
+#endif
DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos,
(int)maxcount, (int)mincount, (int)nread ) );
@@ -1714,6 +1720,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);
+ BOOL my_lock_ctx = False;
START_PROFILE(SMBlockread);
CHECK_FSP(fsp,conn);
@@ -1733,13 +1740,21 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
* protocol request that predates the read/write lock concept.
* Thus instead of asking for a read lock here we need to ask
* for a write lock. JRA.
+ * Note that the requested lock size is unaffected by max_recv.
*/
status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid),
- (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
+ (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &my_lock_ctx);
if (NT_STATUS_V(status)) {
- if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(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)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) {
/*
* A blocking lock was requested. Package up
* this smb into a queued request and push it
@@ -1751,10 +1766,16 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
return -1;
}
}
+#endif
END_PROFILE(SMBlockread);
return ERROR_NT(status);
}
+ /*
+ * However the requested READ size IS affected by max_recv. Insanity.... JRA.
+ */
+
+ numtoread = MIN(numtoread,max_recv);
nread = read_file(fsp,data,startpos,numtoread);
if (nread < 0) {
@@ -1796,6 +1817,11 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int
outsize = set_message(outbuf,5,3,True);
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
+ /*
+ * The requested read size cannot be greater than max_recv. JRA.
+ */
+ numtoread = MIN(numtoread,max_recv);
+
data = smb_buf(outbuf) + 3;
if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
@@ -1863,6 +1889,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
* correct amount of data).
*/
+ SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
SSVAL(outbuf,smb_vwv5,smb_maxcnt);
SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
@@ -1901,6 +1928,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
+ SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
SSVAL(outbuf,smb_vwv5,nread);
SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(smb_buf(outbuf),-2,nread);
@@ -1993,7 +2021,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
START_PROFILE(SMBwritebraw);
if (srv_is_signing_active()) {
- exit_server("reply_readbraw: SMB signing is active - raw reads/writes are disallowed.");
+ exit_server("reply_writebraw: SMB signing is active - raw reads/writes are disallowed.");
}
CHECK_FSP(fsp,conn);
@@ -2626,6 +2654,8 @@ int reply_lock(connection_struct *conn,
SMB_BIG_UINT count,offset;
NTSTATUS status;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ BOOL my_lock_ctx = False;
+
START_PROFILE(SMBlock);
CHECK_FSP(fsp,conn);
@@ -2638,9 +2668,9 @@ int reply_lock(connection_struct *conn,
DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
fsp->fd, fsp->fnum, (double)offset, (double)count));
- status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
+ status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx);
if (NT_STATUS_V(status)) {
- if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
+ if (lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) {
/*
* A blocking lock was requested. Package up
* this smb into a queued request and push it
@@ -4140,6 +4170,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
char *data;
BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
BOOL err;
+ BOOL my_lock_ctx = False;
NTSTATUS status;
START_PROFILE(SMBlockingX);
@@ -4260,9 +4291,9 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
fsp->fsp_name, (int)lock_timeout ));
status = do_lock_spin(fsp,conn,lock_pid, count,offset,
- ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
+ ((locktype & 1) ? READ_LOCK : WRITE_LOCK), &my_lock_ctx);
if (NT_STATUS_V(status)) {
- if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
+ if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) {
/*
* A blocking lock was requested. Package up
* this smb into a queued request and push it