summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/include/local.h2
-rw-r--r--source/include/proto.h2
-rw-r--r--source/include/smb.h4
-rw-r--r--source/locking/locking.c244
-rw-r--r--source/smbd/reply.c57
-rw-r--r--source/smbd/server.c199
-rw-r--r--source/utils/status.c61
7 files changed, 516 insertions, 53 deletions
diff --git a/source/include/local.h b/source/include/local.h
index e7eff2a300d..3ce75eeb4e7 100644
--- a/source/include/local.h
+++ b/source/include/local.h
@@ -162,6 +162,6 @@
/* Timout (in seconds) to wait for an oplock breal
message to return. */
-#define OPLOCK_BREAK_TIMEOUT 120
+#define OPLOCK_BREAK_TIMEOUT 30
#endif
diff --git a/source/include/proto.h b/source/include/proto.h
index 7a1ccc626f7..ac81f8cb370 100644
--- a/source/include/proto.h
+++ b/source/include/proto.h
@@ -300,12 +300,14 @@ int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode,
min_share_mode_entry **old_shares);
void del_share_mode(share_lock_token token, int fnum);
BOOL set_share_mode(share_lock_token token, int fnum, uint16 port, uint16 op_type);
+BOOL remove_share_oplock(int fnum, share_lock_token token);
BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok);
BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token);
int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode,
min_share_mode_entry **old_shares);
void del_share_mode(share_lock_token token, int fnum);
BOOL set_share_mode(share_lock_token token,int fnum, uint16 port, uint16 op_type);
+BOOL remove_share_oplock(int fnum, share_lock_token token);
/*The following definitions come from mangle.c */
diff --git a/source/include/smb.h b/source/include/smb.h
index c8de001fda9..509c1e1cf15 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -515,9 +515,9 @@ struct connect_record
#define SMF_HEADER_LENGTH 10
#ifdef USE_OPLOCKS
-#define SMF_ENTRY_LENGTH 16
-#else /* USE_OPLOCKS */
#define SMF_ENTRY_LENGTH 20
+#else /* USE_OPLOCKS */
+#define SMF_ENTRY_LENGTH 16
#endif /* USE_OPLOCKS */
/*
diff --git a/source/locking/locking.c b/source/locking/locking.c
index 7aa0e7dcf94..693beb74326 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -585,6 +585,122 @@ for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries
return(True);
}
+/*******************************************************************
+Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+BOOL remove_share_oplock(int fnum, share_lock_token token)
+{
+#ifdef USE_OPLOCKS
+ uint32 dev, inode;
+ smb_shm_offset_t *mode_array;
+ unsigned int hash_entry;
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ share_mode_entry *entry_scanner_p;
+ share_mode_entry *entry_prev_p;
+ BOOL found = False;
+ int pid = getpid();
+
+ dev = Files[fnum].fd_ptr->dev;
+ inode = Files[fnum].fd_ptr->inode;
+
+ hash_entry = HASH_ENTRY(dev, inode);
+
+ if(hash_entry > lp_shmem_hash_size() )
+ {
+ DEBUG(0,
+ ("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash_entry %d too large \
+(max = %d)\n",
+ hash_entry, lp_shmem_hash_size() ));
+ return False;
+ }
+
+ mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+
+ if(mode_array[hash_entry] == NULL_OFFSET)
+ {
+ DEBUG(0,("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash bucket %d empty\n",
+ hash_entry));
+ return False;
+ }
+
+ file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
+
+ while(file_scanner_p)
+ {
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)
+ smb_shm_offset2addr(file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR:remove_share_oplock (FAST_SHARE_MODES): no entry found for dev %d, \
+inode %d in hash bucket %d\n", dev, inode, hash_entry));
+ return False;
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): Deleting old share mode \
+record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
+ file_scanner_p->locking_version, dev, inode, hash_entry ));
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ smb_shm_free(smb_shm_addr2offset(file_scanner_p));
+ return False;
+ }
+
+ found = False;
+ entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ while(entry_scanner_p)
+ {
+ if( (pid == entry_scanner_p->pid) &&
+ (entry_scanner_p->op_port != 0) &&
+ (entry_scanner_p->op_type != 0) &&
+ (memcmp(&entry_scanner_p->time,
+ &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
+ {
+ /* Delete the oplock info. */
+ entry_scanner_p->op_port = 0;
+ entry_scanner_p->op_type = 0;
+ found = True;
+ break;
+ }
+ else
+ {
+ entry_prev_p = entry_scanner_p;
+ entry_scanner_p = (share_mode_entry *)
+ smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): No oplock granted share \
+mode record found dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
+ return False;
+ }
+
+ return True;
+#else /* USE_OPLOCKS */
+ return False;
+#endif /* USE_OPLOCKS */
+}
+
#else /* FAST_SHARE_MODES */
/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
@@ -941,8 +1057,8 @@ position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
SIVAL(p,SME_SEC_OFFSET,share_array[i].time.tv_sec);
SIVAL(p,SME_USEC_OFFSET,share_array[i].time.tv_usec);
#ifdef USE_OPLOCKS
- SIVAL(p,SME_PORT_OFFSET,share_array[i].op_port);
- SIVAL(p,SME_OPLOCK_TYPE_OFFSET,share_array[i].op_type);
+ SSVAL(p,SME_PORT_OFFSET,share_array[i].op_port);
+ SSVAL(p,SME_OPLOCK_TYPE_OFFSET,share_array[i].op_type);
#endif /* USE_OPLOCKS */
}
@@ -1272,4 +1388,128 @@ mode 0x%X pid=%d\n",fname,fs_p->share_mode,pid));
return True;
}
+
+/*******************************************************************
+Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+BOOL remove_share_oplock(int fnum, share_lock_token token)
+{
+#ifdef USE_OPLOCKS
+ pstring fname;
+ int fd = (int)token;
+ char *buf = 0;
+ char *base = 0;
+ int num_entries;
+ int fsize;
+ int i;
+ files_struct *fs_p = &Files[fnum];
+ int pid;
+ BOOL found = False;
+ BOOL new_file;
+
+ share_name(fs_p->cnum, fs_p->fd_ptr->dev,
+ fs_p->fd_ptr->inode, fname);
+
+ if(read_share_file( fs_p->cnum, fd, fname, &buf, &new_file) != 0)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: Failed to read share file %s\n",
+ fname));
+ return False;
+ }
+
+ if(new_file == True)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: share file %s is new (size zero), \
+deleting it.\n", fname));
+ delete_share_file(fs_p->cnum, fname);
+ return False;
+ }
+
+ num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+ DEBUG(5,("remove_share_oplock: share file %s has %d share mode entries.\n",
+ fname, num_entries));
+
+ /* PARANOIA TEST */
+ if(num_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:remove_share_oplock: num_share_mode_entries < 0 (%d) \
+for share file %d\n", num_entries, fname));
+ return False;
+ }
+
+ if(num_entries == 0)
+ {
+ /* No entries - just delete the file. */
+ DEBUG(0,("remove_share_oplock: share file %s has no share mode entries - deleting.\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum, fname);
+ return False;
+ }
+
+ pid = getpid();
+
+ /* Go through the entries looking for the particular one
+ we have set - remove the oplock settings on it.
+ */
+
+ base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+ for(i = 0; i < num_entries; i++)
+ {
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+
+ if((IVAL(p,SME_SEC_OFFSET) != fs_p->open_time.tv_sec) ||
+ (IVAL(p,SME_USEC_OFFSET) != fs_p->open_time.tv_usec) ||
+ (IVAL(p,SME_SHAREMODE_OFFSET) != fs_p->share_mode) ||
+ (IVAL(p,SME_PID_OFFSET) != pid) ||
+ (SVAL(p,SME_PORT_OFFSET) == 0) ||
+ (SVAL(p,SME_OPLOCK_TYPE_OFFSET) == 0))
+ continue;
+
+ DEBUG(5,("remove_share_oplock: clearing oplock on entry number %d (of %d) \
+from the share file %s\n", i, num_entries, fname));
+
+ SSVAL(p,SME_PORT_OFFSET,0);
+ SSVAL(p,SME_OPLOCK_TYPE_OFFSET,0);
+ found = True;
+ break;
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("remove_share_oplock: entry not found in share file %s\n", fname));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ /* Re-write the file - and truncate it at the correct point. */
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ fsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries);
+ if(write(fd, buf, fsize) != fsize)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ return True;
+
+#else /* USE_OPLOCKS */
+ return False;
+#endif /* USE_OPLOCKS */
+}
#endif /* FAST_SHARE_MODES */
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 8987e7c0c2b..1a896aa02aa 100644
--- a/source/smbd/reply.c
+++ b/source/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/source/smbd/server.c b/source/smbd/server.c
index 708a2c272b9..5f59af1bf19 100644
--- a/source/smbd/server.c
+++ b/source/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;
diff --git a/source/utils/status.c b/source/utils/status.c
index 6fa85c0a630..703105012ef 100644
--- a/source/utils/status.c
+++ b/source/utils/status.c
@@ -98,10 +98,10 @@ for share file %s (%s)\n", progname, fname, strerror(errno));
return 0;
}
- if (IVAL(buf,0) != LOCKING_VERSION) {
+ if (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION) {
printf("%s: ERROR: read_share_file: share file %s has incorrect \
locking version (was %d, should be %d).\n",fname,
- progname, IVAL(buf,0), LOCKING_VERSION);
+ progname, IVAL(buf,SMF_VERSION_OFFSET), LOCKING_VERSION);
if(buf)
free(buf);
return 0;
@@ -109,13 +109,13 @@ locking version (was %d, should be %d).\n",fname,
/* Sanity check for file contents */
size = sb.st_size;
- size -= 10; /* Remove the header */
+ size -= SMF_HEADER_LENGTH; /* Remove the header */
/* Remove the filename component. */
- size -= SVAL(buf, 8);
+ size -= SVAL(buf, SMF_FILENAME_LEN_OFFSET);
- /* The remaining size must be a multiple of 16 - error if not. */
- if((size % 16) != 0)
+ /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
+ if((size % SMF_ENTRY_LENGTH) != 0)
{
printf("%s: ERROR: read_share_file: share file %s is an incorrect length.\n",
progname, fname);
@@ -148,6 +148,9 @@ locking version (was %d, should be %d).\n",fname,
void *dir;
char *s;
#endif /* FAST_SHARE_MODES */
+#ifdef USE_OPLOCKS
+ int oplock_type;
+#endif /* USE_OPLOCKS */
int i;
struct session_record *ptr;
@@ -344,6 +347,10 @@ locking version (was %d, should be %d).\n",fname,
t.tv_sec = entry_scanner_p->time.tv_sec;
t.tv_usec = entry_scanner_p->time.tv_usec;
strcpy(fname, file_scanner_p->file_name);
+#ifdef USE_OPLOCKS
+ oplock_type = entry_scanner_p->op_type;
+#endif /* USE_OPLOCKS */
+
#else /* FAST_SHARE_MODES */
/* For slow share modes go through all the files in
@@ -394,16 +401,19 @@ locking version (was %d, should be %d).\n",fname,
strcpy( fname, &buf[10]);
close(fd);
- base = buf + 10 + SVAL(buf,8);
- for( i = 0; i < IVAL(buf, 4); i++)
+ base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+ for( i = 0; i < IVAL(buf, SMF_NUM_ENTRIES_OFFSET); i++)
{
- char *p = base + (i*16);
+ char *p = base + (i*SMF_ENTRY_LENGTH);
struct timeval t;
- int pid = IVAL(p,12);
- int mode = IVAL(p,8);
+ int pid = IVAL(p,SME_PID_OFFSET);
+ int mode = IVAL(p,SME_SHAREMODE_OFFSET);
- t.tv_sec = IVAL(p,0);
- t.tv_usec = IVAL(p,4);
+ t.tv_sec = IVAL(p,SME_SEC_OFFSET);
+ t.tv_usec = IVAL(p,SME_USEC_OFFSET);
+#ifdef USE_OPLOCKS
+ oplock_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
+#endif /* USE_OPLOCKS */
#endif /* FAST_SHARE_MODES */
fname[sizeof(fname)-1] = 0;
@@ -411,8 +421,13 @@ locking version (was %d, should be %d).\n",fname,
if (firstopen) {
firstopen=False;
printf("Locked files:\n");
- printf("Pid DenyMode R/W Name\n");
- printf("------------------------------\n");
+#ifdef USE_OPLOCKS
+ printf("Pid DenyMode R/W Oplock Name\n");
+ printf("--------------------------------------------------\n");
+#else /* USE_OPLOCKS */
+ printf("Pid DenyMode R/W Name\n");
+ printf("----------------------------------\n");
+#endif /* USE_OPLOCKS */
}
@@ -427,10 +442,20 @@ locking version (was %d, should be %d).\n",fname,
}
switch (mode&0xF)
{
- case 0: printf("RDONLY "); break;
- case 1: printf("WRONLY "); break;
- case 2: printf("RDWR "); break;
+ case 0: printf("RDONLY "); break;
+ case 1: printf("WRONLY "); break;
+ case 2: printf("RDWR "); break;
}
+#ifdef USE_OPLOCKS
+ if((oplock_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ printf("EXCLUSIVE+BATCH ");
+ else if (oplock_type & EXCLUSIVE_OPLOCK)
+ printf("EXCLUSIVE ");
+ else if (oplock_type & BATCH_OPLOCK)
+ printf("BATCH ");
+ else
+ printf("NONE ");
+#endif /* USE_OPLOCKS */
printf(" %s %s",fname,asctime(LocalTime((time_t *)&t.tv_sec)));
#ifdef FAST_SHARE_MODES