summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2000-04-27 21:12:33 +0000
committerJeremy Allison <jra@samba.org>2000-04-27 21:12:33 +0000
commit0487841120a7584da9a2b83b9574562c415d7024 (patch)
treefcd7e6444990efa8668ea2757401d6476e731457 /source
parent5278ec016cb24d8263fe6e7c1d389f466270ef24 (diff)
downloadsamba-0487841120a7584da9a2b83b9574562c415d7024.tar.gz
samba-0487841120a7584da9a2b83b9574562c415d7024.tar.xz
samba-0487841120a7584da9a2b83b9574562c415d7024.zip
Did the rewrite Andrew wanted where all knowledge of POSIX locking is
removed from the smbd/open.c code. We now use a dlink list of structures indexed by dev/inode to store all pending fd's for close. This could be rewritten to use lib/hash.c if this is discovered to be too slow in use. Andrew, please take a look and let me know if this is what you had in mind. Jeremy.
Diffstat (limited to 'source')
-rw-r--r--source/include/proto.h1
-rw-r--r--source/include/smb.h3
-rw-r--r--source/locking/locking.c184
-rw-r--r--source/smbd/open.c115
4 files changed, 181 insertions, 122 deletions
diff --git a/source/include/proto.h b/source/include/proto.h
index 79ebe331ad0..8c6fcd56b74 100644
--- a/source/include/proto.h
+++ b/source/include/proto.h
@@ -831,6 +831,7 @@ int brl_forall(BRLOCK_FN(fn));
/*The following definitions come from locking/locking.c */
+BOOL fd_close_posix_locks(struct connection_struct *conn, files_struct *fsp);
BOOL is_locked(files_struct *fsp,connection_struct *conn,
SMB_BIG_UINT count,SMB_BIG_UINT offset,
enum brl_type lock_type);
diff --git a/source/include/smb.h b/source/include/smb.h
index 2e11d667298..6a3964e0f3e 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -489,9 +489,6 @@ typedef struct files_struct
time_t pending_modtime;
int oplock_type;
int sent_oplock_break;
- int num_posix_locks;
- unsigned int num_posix_pending_closes;
- int *posix_pending_close_fds;
BOOL can_lock;
BOOL can_read;
BOOL can_write;
diff --git a/source/locking/locking.c b/source/locking/locking.c
index b61e8acedc6..9d407bf16b5 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -2,7 +2,8 @@
Unix SMB/Netbios implementation.
Version 3.0
Locking functions
- Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 1992-2000
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
@@ -30,6 +31,8 @@
support.
rewrtten completely to use new tdb code. Tridge, Dec '99
+
+ Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
*/
#include "includes.h"
@@ -40,6 +43,179 @@ static TDB_CONTEXT *tdb;
int global_smbpid;
+/*
+ * Doubly linked list to hold pending closes needed for
+ * POSIX locks. This may be changed to use a hash table (as
+ * in lib/hash.c if this is too slow in use.... JRA.
+ */
+
+struct pending_closes {
+ struct pending_closes *next;
+ struct pending_closes *prev;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ int num_posix_locks;
+ size_t fd_array_size;
+ int *fd_array;
+};
+
+static struct pending_closes *pending_close_list = NULL;
+
+/****************************************************************************
+ Find a dev/inode pair in the pending close list.
+****************************************************************************/
+
+static struct pending_closes *find_pending_close_entry(SMB_DEV_T dev, SMB_INO_T inode)
+{
+ struct pending_closes *pc;
+
+ for(pc = pending_close_list; pc; pc = pc->next) {
+ if (dev == pc->dev && inode == pc->inode) {
+ DLIST_PROMOTE(pending_close_list,pc);
+ return pc;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Add an fd into the pending close array.
+****************************************************************************/
+
+static BOOL add_fd_to_close_entry(struct pending_closes *pc, int fd)
+{
+ if ((pc->fd_array = (int *)Realloc(pc->fd_array, (pc->fd_array_size + 1)*sizeof(int))) == NULL) {
+ DEBUG(0,("add_fd_to_close_entry: Unable to increase fd_array !\n"));
+ return False;
+ }
+
+ pc->fd_array[pc->fd_array_size] = fd;
+ pc->fd_array_size++;
+
+ DEBUG(10,("add_fd_to_close_entry: added fd = %d, size = %u : dev = %.0f, ino = %.0f\n",
+ fd, (unsigned int)pc->fd_array_size, (double)pc->dev, (double)pc->inode ));
+
+ return True;
+}
+
+/****************************************************************************
+ Deal with pending closes needed by POSIX locking support.
+****************************************************************************/
+
+BOOL fd_close_posix_locks(struct connection_struct *conn, files_struct *fsp)
+{
+ struct pending_closes *pc;
+ int saved_errno = 0;
+ size_t i;
+
+ if (!lp_posix_locking(SNUM(conn)))
+ return True;
+
+ pc = find_pending_close_entry(fsp->dev, fsp->inode);
+
+ if (!pc) {
+ /*
+ * No other open with a POSIX lock on this dev/inode within this smbd.
+ * Just exit.
+ */
+ return True;
+ }
+
+ if (pc->num_posix_locks) {
+ /*
+ * There are outstanding locks on this dev/inode pair.
+ * Add our fd to the list and set fsp->fd to -1 to
+ * stop the close.
+ */
+
+ if (!add_fd_to_close_entry(pc, fsp->fd))
+ return False;
+
+ fsp->fd = -1;
+ return True;
+ }
+
+ DEBUG(10,("fd_close_posix_locks: doing close on %u fd's.\n", (unsigned int)pc->fd_array_size ));
+
+ /*
+ * This is the last close. If there are pending fd's close them
+ * now. Save the errno just in case.
+ */
+
+ for(i = 0; i < pc->fd_array_size; i++) {
+ if (pc->fd_array[i] != -1) {
+ if (conn->vfs_ops.close(pc->fd_array[i]) == -1) {
+ saved_errno = errno;
+ }
+ }
+ }
+
+ if (pc->fd_array)
+ free((char *)pc->fd_array);
+
+ DLIST_REMOVE(pending_close_list, pc);
+
+ free((char *)pc);
+
+ if (saved_errno != 0) {
+ errno = saved_errno;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ A POSIX lock was granted. Increment the lock list count (create if needed).
+****************************************************************************/
+
+static void increment_posix_lock_list(files_struct *fsp)
+{
+ struct pending_closes *pc;
+
+ if ((pc = find_pending_close_entry(fsp->dev, fsp->inode)) == NULL) {
+ if (!(pc = (struct pending_closes *)malloc(sizeof(struct pending_closes)))) {
+ DEBUG(0,("increment_lock_list: malloc fail.\n"));
+ return;
+ }
+ ZERO_STRUCTP(pc);
+ pc->dev = fsp->dev;
+ pc->inode = fsp->inode;
+ DLIST_ADD(pending_close_list, pc);
+
+ DEBUG(10,("increment_posix_lock_list: creating entry for file %s: dev = %.0f, ino = %.0f\n",
+ fsp->fsp_name, (double)fsp->dev, (double)fsp->inode ));
+ }
+
+ pc->num_posix_locks++;
+
+ DEBUG(10,("increment_posix_lock_list: entry for file %s: dev = %.0f, ino = %.0f, num_locks = %d\n",
+ fsp->fsp_name, (double)pc->dev, (double)pc->inode, pc->num_posix_locks ));
+}
+
+
+/****************************************************************************
+ A POSIX lock was granted. Decrement the lock list count.
+****************************************************************************/
+
+static void decrement_posix_lock_list(files_struct *fsp)
+{
+ struct pending_closes *pc;
+
+ pc = find_pending_close_entry(fsp->dev, fsp->inode);
+
+ if (pc == NULL) {
+ smb_panic("decrement_lock_list: Unlock not found !\n");
+ }
+
+ pc->num_posix_locks--;
+
+ DEBUG(10,("decrement_posix_lock_list: entry for file %s: dev = %.0f, ino = %.0f, num_locks = %d\n",
+ fsp->fsp_name, (double)pc->dev, (double)pc->inode, pc->num_posix_locks ));
+
+ SMB_ASSERT(pc->num_posix_locks >= 0);
+}
+
/****************************************************************************
Debugging aid :-).
****************************************************************************/
@@ -444,7 +620,7 @@ BOOL do_lock(files_struct *fsp,connection_struct *conn,
*/
if((ok = set_posix_lock(fsp, offset, count, lock_type)) == True)
- fsp->num_posix_locks++;
+ increment_posix_lock_list(fsp);
else {
/*
* We failed to map - we must now remove the brl
@@ -558,9 +734,7 @@ BOOL do_unlock(files_struct *fsp,connection_struct *conn,
* if it may have been split into multiple smaller POSIX unlock ranges.
*/
- fsp->num_posix_locks--;
-
- SMB_ASSERT(fsp->num_posix_locks >= 0);
+ decrement_posix_lock_list(fsp);
return True; /* Did unlock */
}
diff --git a/source/smbd/open.c b/source/smbd/open.c
index c7ca8256d21..737b9b5ef36 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -50,129 +50,25 @@ static int fd_open(struct connection_struct *conn, char *fname,
}
/****************************************************************************
- Take care of moving any POSIX pending close fd's to another fsp.
-****************************************************************************/
-
-static BOOL fd_close_posix_locks(files_struct *fsp)
-{
- files_struct *other_fsp;
-
- DEBUG(10,("fd_close_posix_locks: file %s: fsp->num_posix_pending_closes = %u \
-fsp->posix_pending_close_fds = %lx.\n", fsp->fsp_name,
- (unsigned int)fsp->num_posix_pending_closes, (unsigned long)fsp->posix_pending_close_fds ));
-
- for(other_fsp = file_find_di_first(fsp->dev, fsp->inode); other_fsp;
- other_fsp = file_find_di_next(other_fsp)) {
-
- if(other_fsp == fsp)
- continue;
-
- if ((other_fsp->fd != -1) && other_fsp->num_posix_locks) {
-
- /*
- * POSIX locks pending on another fsp held open, transfer
- * the fd in this fsp and all the pending fd's in this fsp pending close array
- * to the other_fsp pending close array.
- */
-
- unsigned int extra_fds = fsp->num_posix_pending_closes + 1;
-
- DEBUG(10,("fd_close_posix_locks: file %s: Transferring to \
-file %s, extra_fds = %u, other_fsp->num_posix_pending_closes = %u.\n",
- fsp->fsp_name, other_fsp->fsp_name, extra_fds, (unsigned int)other_fsp->num_posix_pending_closes ));
-
- other_fsp->posix_pending_close_fds = (int *)Realloc(other_fsp->posix_pending_close_fds,
- (other_fsp->num_posix_pending_closes +
- extra_fds)*sizeof(int));
-
- if(other_fsp->posix_pending_close_fds == NULL) {
- DEBUG(0,("fd_close_posix_locks: Unable to increase posix_pending_close_fds array size !\n"));
- return False;
- }
-
- /*
- * Copy over any fd's in the existing fsp's pending array.
- */
-
- if(fsp->posix_pending_close_fds) {
- memcpy(&other_fsp->posix_pending_close_fds[other_fsp->num_posix_pending_closes],
- &fsp->posix_pending_close_fds[0], fsp->num_posix_pending_closes * sizeof(int) );
-
- free((char *)fsp->posix_pending_close_fds);
- fsp->posix_pending_close_fds = NULL;
- fsp->num_posix_pending_closes = 0;
- }
-
- other_fsp->posix_pending_close_fds[other_fsp->num_posix_pending_closes+extra_fds-1] = fsp->fd;
- other_fsp->num_posix_pending_closes += extra_fds;
-
- fsp->fd = -1; /* We have moved this fd to other_fsp's pending close array.... */
-
- break;
- }
- }
-
- return True;
-}
-
-/****************************************************************************
Close the file associated with a fsp.
-
- This is where we must deal with POSIX "first close drops all locks"
- locking braindamage. We do this by searching for any other fsp open
- on the same dev/inode with open POSIX locks, and then transferring this
- fd (and all pending fd's attached to this fsp) to the posix_pending_close_fds
- array in that fsp.
-
- If there are no open fsp's on the same dev/inode then we close all the
- fd's in the posix_pending_close_fds array and then close the fd.
-
****************************************************************************/
int fd_close(struct connection_struct *conn, files_struct *fsp)
{
int ret = 0;
- int saved_errno = 0;
- unsigned int i;
/*
* Deal with transferring any pending fd's if there
* are POSIX locks outstanding.
*/
- if(!fd_close_posix_locks(fsp))
+ if(!fd_close_posix_locks(conn,fsp))
return -1;
- /*
- * Close and free any pending closes given to use from
- * other fsp's.
- */
-
- if (fsp->posix_pending_close_fds) {
-
- for(i = 0; i < fsp->num_posix_pending_closes; i++) {
- if (fsp->posix_pending_close_fds[i] != -1) {
- if (conn->vfs_ops.close(fsp->posix_pending_close_fds[i]) == -1) {
- saved_errno = errno;
- }
- }
- }
-
- free((char *)fsp->posix_pending_close_fds);
- fsp->posix_pending_close_fds = NULL;
- fsp->num_posix_pending_closes = 0;
- }
-
if(fsp->fd != -1)
ret = conn->vfs_ops.close(fsp->fd);
fsp->fd = -1;
-
- if (saved_errno != 0) {
- errno = saved_errno;
- ret = -1;
- }
-
return ret;
}
@@ -278,9 +174,6 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
fsp->modified = False;
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
- fsp->num_posix_locks = 0;
- fsp->num_posix_pending_closes = 0;
- fsp->posix_pending_close_fds = NULL;
fsp->is_directory = False;
fsp->stat_open = False;
fsp->directory_delete_on_close = False;
@@ -914,9 +807,6 @@ files_struct *open_file_stat(connection_struct *conn,
fsp->modified = False;
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
- fsp->num_posix_locks = 0;
- fsp->num_posix_pending_closes = 0;
- fsp->posix_pending_close_fds = NULL;
fsp->is_directory = False;
fsp->stat_open = True;
fsp->directory_delete_on_close = False;
@@ -1040,9 +930,6 @@ files_struct *open_directory(connection_struct *conn,
fsp->modified = False;
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
- fsp->num_posix_locks = 0;
- fsp->num_posix_pending_closes = 0;
- fsp->posix_pending_close_fds = NULL;
fsp->is_directory = True;
fsp->directory_delete_on_close = False;
fsp->conn = conn;