summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2001-08-22 00:56:25 +0000
committerJeremy Allison <jra@samba.org>2001-08-22 00:56:25 +0000
commitdde6dd34f266eb7b4f8106a270c52f6fa6ec0be4 (patch)
tree5a21443e1ebace7c8569398d4b38ddd1f489ff93
parenta37afda6ade3212e7fd1203d3ea4740c9db6f444 (diff)
downloadsamba-dde6dd34f266eb7b4f8106a270c52f6fa6ec0be4.tar.gz
samba-dde6dd34f266eb7b4f8106a270c52f6fa6ec0be4.tar.xz
samba-dde6dd34f266eb7b4f8106a270c52f6fa6ec0be4.zip
Tidyups for fnctl spin problem. Try and tidyup share mode table.
Jeremy
-rw-r--r--source/include/proto.h1
-rw-r--r--source/locking/locking.c41
-rw-r--r--source/smbd/close.c3
-rw-r--r--source/smbd/open.c54
-rw-r--r--source/smbd/oplock.c14
5 files changed, 86 insertions, 27 deletions
diff --git a/source/include/proto.h b/source/include/proto.h
index 79ad99b9e3b..6630d9be133 100644
--- a/source/include/proto.h
+++ b/source/include/proto.h
@@ -1298,6 +1298,7 @@ void unlock_share_entry_fsp(files_struct *fsp);
int get_share_modes(connection_struct *conn,
SMB_DEV_T dev, SMB_INO_T inode,
share_mode_entry **shares);
+BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2);
ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode,
share_mode_entry *entry, share_mode_entry **ppse);
ssize_t del_share_mode(files_struct *fsp, share_mode_entry **ppse);
diff --git a/source/locking/locking.c b/source/locking/locking.c
index 972c4f0b701..80537c8bc1b 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -479,7 +479,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 &&
@@ -519,6 +519,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)
@@ -527,6 +529,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++;
}
@@ -631,34 +636,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;
}
}
@@ -666,10 +665,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;
}
}
@@ -699,7 +698,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);
}
/*******************************************************************
@@ -721,7 +725,12 @@ 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);
}
/*******************************************************************
diff --git a/source/smbd/close.c b/source/smbd/close.c
index 217c81228f7..3c950f9ccb2 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 697f9930c68..e1911ab1a1c 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -3,6 +3,7 @@
Version 1.9.
file opening and share modes
Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -535,17 +536,51 @@ 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 by process %d after break ! For file %s,
+dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, 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 (del_share_entry(dev, inode, &broken_entry, NULL) == -1) {
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ return -1;
+ }
+
+ /*
+ * We must reload the share modes after deleting the
+ * other process's entry.
+ */
+
+ free((char *)old_shares);
+ num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+ break;
+ }
+ } /* end for paranoia... */
+ } /* end if broke_oplock */
+
} while(broke_oplock);
if(old_shares != 0)
@@ -578,6 +613,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");
}
}