diff options
-rw-r--r-- | source3/locking/brlock.c | 9 | ||||
-rw-r--r-- | source3/locking/locking.c | 11 | ||||
-rw-r--r-- | source3/smbd/blocking.c | 14 | ||||
-rw-r--r-- | source3/smbd/reply.c | 47 |
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 |