From 5864551aef50295addd1c8aa690a52870f70626d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 1 Oct 1997 23:32:22 +0000 Subject: OPLOCK CHECK-IN - oplocks are now *OPERATIONAL* !!!! Yipeee. At least as far as I can check in a short time :-). local.h: Changed OPLOCK_BREAK_TIMEOUT to 30 seconds. locking.c: Big changes to delete oplocks on a share mode entry. proto.h: updated. reply.c: Added oplock break code in lockingX reply & readbraw reply. server.c: Add batch oplock code. Force server shutdown if client fails to respond to oplock break. smb.h: Fix silly slow share mode oplock define bug. status.c: Add oplock status info. Jeremy (jallison@whistle.com) (This used to be commit 4c83d37239f15f855fc10f01d7b4bf4217fb9eda) --- source3/include/local.h | 2 +- source3/include/proto.h | 2 + source3/include/smb.h | 4 +- source3/locking/locking.c | 244 +++++++++++++++++++++++++++++++++++++++++++++- source3/smbd/reply.c | 57 ++++++++++- source3/smbd/server.c | 199 ++++++++++++++++++++++++++++++++----- source3/utils/status.c | 61 ++++++++---- 7 files changed, 516 insertions(+), 53 deletions(-) (limited to 'source3') diff --git a/source3/include/local.h b/source3/include/local.h index e7eff2a300..3ce75eeb4e 100644 --- a/source3/include/local.h +++ b/source3/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/source3/include/proto.h b/source3/include/proto.h index 7a1ccc626f..ac81f8cb37 100644 --- a/source3/include/proto.h +++ b/source3/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/source3/include/smb.h b/source3/include/smb.h index c8de001fda..509c1e1cf1 100644 --- a/source3/include/smb.h +++ b/source3/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/source3/locking/locking.c b/source3/locking/locking.c index 7aa0e7dcf9..693beb7432 100644 --- a/source3/locking/locking.c +++ b/source3/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/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; diff --git a/source3/utils/status.c b/source3/utils/status.c index 6fa85c0a63..703105012e 100644 --- a/source3/utils/status.c +++ b/source3/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 -- cgit