diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/locking/locking.c | 52 | ||||
-rw-r--r-- | source/smbd/close.c | 3 | ||||
-rw-r--r-- | source/smbd/open.c | 44 | ||||
-rw-r--r-- | source/smbd/oplock.c | 14 |
4 files changed, 85 insertions, 28 deletions
diff --git a/source/locking/locking.c b/source/locking/locking.c index a9bcada0267..fea821baa17 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -451,7 +451,7 @@ static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_t and port info. ********************************************************************/ -static BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2) +BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2) { return (e1->pid == e2->pid && e1->share_mode == e2->share_mode && @@ -465,7 +465,7 @@ static BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2) Ignore if no entry deleted. ********************************************************************/ -ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, +static ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry, share_mode_entry **ppse) { TDB_DATA dbuf; @@ -491,6 +491,8 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, * from the record. */ + DEBUG(10,("del_share_mode: num_share_modes = %d\n", data->num_share_mode_entries )); + for (i=0;i<data->num_share_mode_entries;) { if (share_modes_identical(&shares[i], entry)) { if (ppse) @@ -499,6 +501,9 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, memmove(&shares[i], &shares[i+1], dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))); del_count++; + + DEBUG(10,("del_share_mode: deleting entry %d\n", i )); + } else { i++; } @@ -603,34 +608,28 @@ BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type) A generic in-place modification call for share mode entries. ********************************************************************/ -static BOOL mod_share_mode(files_struct *fsp, +static BOOL mod_share_mode( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry, void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *), void *param) { TDB_DATA dbuf; struct locking_data *data; int i; - share_mode_entry *shares, entry; + share_mode_entry *shares; BOOL need_store=False; /* read in the existing share modes */ - dbuf = tdb_fetch(tdb, locking_key_fsp(fsp)); + dbuf = tdb_fetch(tdb, locking_key(dev, inode)); if (!dbuf.dptr) return False; data = (struct locking_data *)dbuf.dptr; shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); - /* - * Fake up a share_mode_entry for comparisons. - */ - - fill_share_mode((char *)&entry, fsp, 0, 0); - /* find any with our pid and call the supplied function */ for (i=0;i<data->num_share_mode_entries;i++) { - if (share_modes_identical(&entry, &shares[i])) { - mod_fn(&shares[i], fsp->dev, fsp->inode, param); + if (share_modes_identical(entry, &shares[i])) { + mod_fn(&shares[i], dev, inode, param); need_store=True; } } @@ -638,10 +637,10 @@ static BOOL mod_share_mode(files_struct *fsp, /* if the mod fn was called then store it back */ if (need_store) { if (data->num_share_mode_entries == 0) { - if (tdb_delete(tdb, locking_key_fsp(fsp)) == -1) + if (tdb_delete(tdb, locking_key(dev, inode)) == -1) need_store = False; } else { - if (tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE) == -1) + if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1) need_store = False; } } @@ -671,7 +670,12 @@ static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_I BOOL remove_share_oplock(files_struct *fsp) { - return mod_share_mode(fsp, remove_share_oplock_fn, NULL); + share_mode_entry entry; + /* + * Fake up an entry for comparisons... + */ + fill_share_mode((char *)&entry, fsp, 0, 0); + return mod_share_mode(fsp->dev, fsp->inode, &entry, remove_share_oplock_fn, NULL); } /******************************************************************* @@ -693,7 +697,21 @@ static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SM BOOL downgrade_share_oplock(files_struct *fsp) { - return mod_share_mode(fsp, downgrade_share_oplock_fn, NULL); + share_mode_entry entry; + /* + * Fake up an entry for comparisons... + */ + fill_share_mode((char *)&entry, fsp, 0, 0); + return mod_share_mode(fsp->dev, fsp->inode, &entry, downgrade_share_oplock_fn, NULL); +} + +/******************************************************************* + Delete an exclusive share oplock owned by a defunct smbd.. +********************************************************************/ + +BOOL clear_share_entry(SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry) +{ + return mod_share_mode(dev, inode, entry, remove_share_oplock_fn, NULL); } /******************************************************************* diff --git a/source/smbd/close.c b/source/smbd/close.c index 6b72a8563a4..dd1a25293d8 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -153,6 +153,9 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) lock_share_entry_fsp(fsp); share_entry_count = del_share_mode(fsp, &share_entry); + DEBUG(10,("close_normal_file: share_entry_count = %d for file %s\n", + share_entry_count, fsp->fsp_name )); + /* * We delete on close if it's the last open, and the * delete on close flag was set in the entry we just deleted. diff --git a/source/smbd/open.c b/source/smbd/open.c index 143aa934a68..633cf718179 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -527,17 +527,42 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou if(broke_oplock) { free((char *)old_shares); - if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) { - DEBUG(0,("open_mode_check: cannot delete entry when breaking oplock (%x) on file %s, \ -dev = %x, inode = %.0f\n", broken_entry.op_type, fname, (unsigned int)dev, (double)inode)); - errno = EACCES; - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; - return -1; - } num_share_modes = get_share_modes(conn, dev, inode, &old_shares); oplock_contention_count++; - } + + /* Paranoia check that this is no longer an exlusive entry. */ + for(i = 0; i < num_share_modes; i++) { + share_mode_entry *share_entry = &old_shares[i]; + + if (share_modes_identical(&broken_entry, share_entry) && + EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) { + + /* + * This should not happen. The target left this oplock + * as exlusive.... The process *must* be dead.... + */ + + DEBUG(0,("open_mode_check: exlusive oplock left after break ! For file %s, +dev = %x, inode = %.0f\n", fname, (unsigned int)dev, (double)inode)); + + if (process_exists(broken_entry.pid)) { + pstring errmsg; + slprintf(errmsg, sizeof(errmsg)-1, + "open_mode_check: Existant process %d left active oplock.\n", + broken_entry.pid ); + smb_panic(errmsg); + } + + if (!clear_share_entry(dev, inode, &broken_entry)) { + errno = EACCES; + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadshare; + return -1; + } + } + } /* end for paranoia... */ + } /* end if broke_oplock */ + } while(broke_oplock); if(old_shares != 0) @@ -570,6 +595,7 @@ static void kernel_flock(files_struct *fsp, int deny_mode) else if (deny_mode == DENY_ALL) kernel_mode = LOCK_MAND; if (kernel_mode) flock(fsp->fd, kernel_mode); #endif + ;; } diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 4bc8fce6980..f841432960b 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -1141,6 +1141,9 @@ void release_level_2_oplocks_on_change(files_struct *fsp) num_share_modes = get_share_modes(fsp->conn, fsp->dev, fsp->inode, &share_list); + DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n", + num_share_modes )); + for(i = 0; i < num_share_modes; i++) { share_mode_entry *share_entry = &share_list[i]; @@ -1153,6 +1156,9 @@ void release_level_2_oplocks_on_change(files_struct *fsp) * also no harm to ignore existing NO_OPLOCK states. JRA. */ + DEBUG(10,("release_level_2_oplocks_on_change: share_entry[%i]->op_type == %d\n", + i, share_entry->op_type )); + if (share_entry->op_type == NO_OPLOCK) continue; @@ -1179,6 +1185,8 @@ void release_level_2_oplocks_on_change(files_struct *fsp) abort(); } + DEBUG(10,("release_level_2_oplocks_on_change: breaking our own oplock.\n")); + oplock_break_level2(new_fsp, True, token); } else { @@ -1188,17 +1196,19 @@ void release_level_2_oplocks_on_change(files_struct *fsp) * message. */ + DEBUG(10,("release_level_2_oplocks_on_change: breaking remote oplock.\n")); request_oplock_break(share_entry, fsp->dev, fsp->inode); } } - free((char *)share_list); + if (share_list) + free((char *)share_list); unlock_share_entry_fsp(fsp); /* Paranoia check... */ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) { DEBUG(0,("release_level_2_oplocks_on_change: PANIC. File %s still has a level II oplock.\n", fsp->fsp_name)); - abort(); + smb_panic("release_level_2_oplocks_on_change"); } } |