summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/reply.c57
-rw-r--r--source3/smbd/server.c199
2 files changed, 226 insertions, 30 deletions
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 8987e7c0c2..1a896aa02a 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1254,10 +1254,13 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
smb_action |= EXTENDED_OPLOCK_GRANTED;
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- if(fsp->granted_oplock)
+ if(fsp->granted_oplock) {
smb_action |= EXTENDED_OPLOCK_GRANTED;
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
set_message(outbuf,15,0,True);
SSVAL(outbuf,smb_vwv2,fnum);
@@ -1609,6 +1612,22 @@ int reply_readbraw(char *inbuf, char *outbuf)
int fd;
char *fname;
+#ifdef USE_OPLOCKS
+ /*
+ * Special check if an oplock break has been issued
+ * and the readraw request croses on the wire, we must
+ * return a zero length response here.
+ */
+
+ if(global_oplock_break)
+ {
+ _smb_setlen(header,0);
+ transfer_file(0,Client,0,header,4,0);
+ DEBUG(5,("readbraw - oplock break finished\n"));
+ return -1;
+ }
+#endif
+
cnum = SVAL(inbuf,smb_tid);
fnum = GETFNUM(inbuf,smb_vwv0);
@@ -3342,7 +3361,10 @@ int reply_setdir(char *inbuf,char *outbuf)
int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
{
int fnum = GETFNUM(inbuf,smb_vwv2);
- uint16 locktype = SVAL(inbuf,smb_vwv3);
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+#if 0
+ unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
+#endif /* USE_OPLOCKS */
uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
uint16 num_locks = SVAL(inbuf,smb_vwv7);
uint32 count, offset;
@@ -3359,6 +3381,35 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
CHECK_ERROR(fnum);
data = smb_buf(inbuf);
+
+#ifdef USE_OPLOCKS
+ /* Check if this is an oplock break on a file
+ we have granted an oplock on.
+ */
+ if((locktype == LOCKING_ANDX_OPLOCK_RELEASE) &&
+ (num_ulocks == 0) && (num_locks == 0) &&
+ (CVAL(inbuf,smb_vwv0) == 0xFF))
+ {
+ DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
+ fnum));
+ /*
+ * Make sure we have granted an oplock on this file.
+ */
+ if(!Files[fnum].granted_oplock)
+ {
+ DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
+oplock granted on this file.\n", fnum));
+ return ERROR(ERRDOS,ERRlock);
+ }
+
+ /* Just clear the granted flag and return. oplock_break()
+ will handle changing the share_mode_entry. */
+
+ Files[fnum].granted_oplock = 0;
+ return -1;
+ }
+#endif /* USE_OPLOCKS */
+
/* Data now points at the beginning of the list
of smb_unlkrng structs */
for(i = 0; i < (int)num_ulocks; i++) {
@@ -3393,7 +3444,7 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
set_message(outbuf,2,0,True);
DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
- timestring(),fnum,cnum,locktype,num_locks,num_ulocks));
+ timestring(),fnum,cnum,(unsigned int)locktype,num_locks,num_ulocks));
chain_fnum = fnum;
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 708a2c272b..5f59af1bf1 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -1458,23 +1458,74 @@ BOOL check_file_sharing(int cnum,char *fname)
struct stat sbuf;
share_lock_token token;
int pid = getpid();
+ uint32 dev, inode;
if(!lp_share_modes(SNUM(cnum)))
return True;
if (stat(fname,&sbuf) == -1) return(True);
- lock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &token);
- num_share_modes = get_share_modes(cnum, token,
- (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &old_shares);
+ dev = (uint32)sbuf.st_dev;
+ inode = (uint32)sbuf.st_ino;
- for( i = 0; i < num_share_modes; i++)
+ lock_share_entry(cnum, dev, inode, &token);
+ num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
+
+ /*
+ * Check if the share modes will give us access.
+ */
+
+ if(num_share_modes != 0)
{
- if (old_shares[i].share_mode != DENY_DOS)
- goto free_and_exit;
+ BOOL broke_oplock;
+
+ do
+ {
+
+ broke_oplock = False;
+ for(i = 0; i < num_share_modes; i++)
+ {
+ min_share_mode_entry *share_entry = &old_shares[i];
+
+ /* someone else has a share lock on it, check to see
+ if we can too */
+ if ((share_entry->share_mode != DENY_DOS) || (share_entry->pid != pid))
+ goto free_and_exit;
+
+#ifdef USE_OPLOCKS
+ /*
+ * The share modes would give us access. Check if someone
+ * has an oplock on this file. If so we must break it before
+ * continuing.
+ */
+ if(share_entry->op_type & BATCH_OPLOCK)
+ {
+
+ DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
- if(old_shares[i].pid != pid)
- goto free_and_exit;
+ /* Oplock break.... */
+ unlock_share_entry(cnum, dev, inode, token);
+ if(request_oplock_break(share_entry, dev, inode) == False)
+ {
+ free((char *)old_shares);
+ DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
+ return False;
+ }
+ lock_share_entry(cnum, dev, inode, &token);
+ broke_oplock = True;
+ break;
+ }
+#endif /* USE_OPLOCKS */
+ } /* end for */
+
+ if(broke_oplock)
+ {
+ free((char *)old_shares);
+ num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
+ }
+ } while(broke_oplock);
}
/* XXXX exactly what share mode combinations should be allowed for
@@ -1485,7 +1536,7 @@ BOOL check_file_sharing(int cnum,char *fname)
free_and_exit:
- unlock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, token);
+ unlock_share_entry(cnum, dev, inode, token);
if(old_shares != NULL)
free((char *)old_shares);
return(ret);
@@ -1576,6 +1627,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
share_lock_token token;
uint32 dev = 0;
uint32 inode = 0;
+ int num_share_modes = 0;
fs_p->open = False;
fs_p->fd_ptr = 0;
@@ -1647,7 +1699,6 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
if (lp_share_modes(SNUM(cnum)))
{
- int num_shares = 0;
int i;
min_share_mode_entry *old_shares = 0;
@@ -1657,14 +1708,14 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
inode = (uint32)sbuf.st_ino;
lock_share_entry(cnum, dev, inode, &token);
share_locked = True;
- num_shares = get_share_modes(cnum, token, dev, inode, &old_shares);
+ num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
}
/*
* Check if the share modes will give us access.
*/
- if(share_locked && (num_shares != 0))
+ if(share_locked && (num_share_modes != 0))
{
BOOL broke_oplock;
@@ -1672,7 +1723,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
{
broke_oplock = False;
- for(i = 0; i < num_shares; i++)
+ for(i = 0; i < num_share_modes; i++)
{
min_share_mode_entry *share_entry = &old_shares[i];
@@ -1696,7 +1747,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
if(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
{
- DEBUG(5,("open file shared: breaking oplock (%x) on file %s, \
+ DEBUG(5,("open_file_shared: breaking oplock (%x) on file %s, \
dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
/* Oplock break.... */
@@ -1704,7 +1755,7 @@ dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
if(request_oplock_break(share_entry, dev, inode) == False)
{
free((char *)old_shares);
- DEBUG(0,("open file shared: FAILED when breaking oplock (%x) on file %s, \
+ DEBUG(0,("open_file_shared: FAILED when breaking oplock (%x) on file %s, \
dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
errno = EACCES;
unix_ERR_class = ERRDOS;
@@ -1721,7 +1772,7 @@ dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
if(broke_oplock)
{
free((char *)old_shares);
- num_shares = get_share_modes(cnum, token, dev, inode, &old_shares);
+ num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
}
} while(broke_oplock);
}
@@ -1782,7 +1833,27 @@ dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
file (which expects the share_mode_entry to be there).
*/
if (lp_share_modes(SNUM(cnum)))
- set_share_mode(token, fnum, 0, 0);
+ {
+ uint16 port = 0;
+#ifdef USE_OPLOCKS
+ /* JRA. Currently this only services Exlcusive and batch
+ oplocks (no other opens on this file). This needs to
+ be extended to level II oplocks (multiple reader
+ oplocks). */
+
+ if(oplock_request && (num_share_modes == 0))
+ {
+ fs_p->granted_oplock = True;
+ global_oplocks_open++;
+ port = oplock_port;
+
+ DEBUG(5,("open_file_shared: granted oplock (%x) on file %s, \
+dev = %x, inode = %x\n", oplock_request, fname, dev, inode));
+ }
+
+#endif /* USE_OPLOCKS */
+ set_share_mode(token, fnum, port, oplock_request);
+ }
if ((flags2&O_TRUNC) && file_existed)
truncate_unless_locked(fnum,cnum,token,&share_locked);
@@ -2444,7 +2515,7 @@ should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN));
struct sockaddr_in toaddr;
DEBUG(5,("process_local_message: oplock break request from \
-pid %d, dev %d, inode %d\n", remotepid, dev, inode));
+pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
/*
* If we have no record of any currently open oplocks,
@@ -2483,6 +2554,11 @@ oplocks. Returning success.\n"));
remotepid, strerror(errno)));
return False;
}
+
+ DEBUG(5,("process_local_message: oplock break reply sent to \
+pid %d, port %d, for file dev = %x, inode = %x\n", remotepid,
+ from_port, dev, inode));
+
}
break;
default:
@@ -2503,6 +2579,9 @@ BOOL oplock_break(uint32 dev, uint32 inode)
static char *outbuf = NULL;
files_struct *fsp = NULL;
int fnum;
+ share_lock_token token;
+ time_t start_time;
+ BOOL shutdown_server = False;
if(inbuf == NULL)
{
@@ -2579,24 +2658,90 @@ allowing break to succeed.\n", dev, inode, fnum));
global_oplock_break = True;
/* Process incoming messages. */
- while(global_oplock_break && OPEN_FNUM(fnum))
+
+ /* JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT
+ seconds we should just die.... */
+
+ start_time = time(NULL);
+
+ while(OPEN_FNUM(fnum) && fsp->granted_oplock)
{
if(receive_smb(Client,inbuf,OPLOCK_BREAK_TIMEOUT * 1000) == False)
{
+ /*
+ * Die if we got an error.
+ */
+
if (smb_read_error == READ_EOF)
- {
- DEBUG(3,("oplock_break: end of file from client\n"));
- return False;
- }
+ DEBUG(0,("oplock_break: end of file from client\n"));
if (smb_read_error == READ_ERROR)
- {
- DEBUG(3,("oplock_break: receive_smb error (%s)\n",
+ DEBUG(0,("oplock_break: receive_smb error (%s)\n",
strerror(errno)));
- return False;
- }
+
+ if (smb_read_error == READ_TIMEOUT)
+ DEBUG(0,("oplock_break: receive_smb timed out after %d seconds.\n",
+ OPLOCK_BREAK_TIMEOUT));
+
+ DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", fsp->name, fnum, dev, inode));
+ shutdown_server = True;
+ break;
}
process_smb(inbuf, outbuf);
+
+ /* We only need this in case a readraw crossed on the wire. */
+ global_oplock_break = False;
+
+ /*
+ * Die if we go over the time limit.
+ */
+
+ if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
+ {
+ DEBUG(0,("oplock_break: no break received from client within \
+%d seconds.\n", OPLOCK_BREAK_TIMEOUT));
+ DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", fsp->name, fnum, dev, inode));
+ shutdown_server = True;
+ break;
+ }
+ }
+
+ /*
+ * If the client did not respond we must die.
+ */
+
+ if(shutdown_server)
+ {
+ DEBUG(0,("oplock_break: client failure in break - shutting down this smbd.\n"));
+ close_sockets();
+ close(oplock_sock);
+ exit_server("oplock break failure");
+ }
+
+ if(OPEN_FNUM(fnum))
+ {
+ /* Remove the oplock flag from the sharemode. */
+ lock_share_entry(fsp->cnum, dev, inode, &token);
+ if(remove_share_oplock( fnum, token)==False)
+ {
+ DEBUG(0,("oplock_break: failed to remove share oplock for fnum %d, \
+dev = %x, inode = %x\n", fnum, dev, inode));
+ unlock_share_entry(fsp->cnum, dev, inode, token);
+ return False;
+ }
+ unlock_share_entry(fsp->cnum, dev, inode, token);
+ }
+
+ global_oplocks_open--;
+
+ /* Santity check - remove this later. JRA */
+ if(global_oplocks_open < 0)
+ {
+ DEBUG(0,("oplock_break: global_oplocks_open < 0 (%d). PANIC ERROR\n",
+ global_oplocks_open));
+ abort();
}
return True;