diff options
author | Jeremy Allison <jra@samba.org> | 2000-04-27 21:12:33 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2000-04-27 21:12:33 +0000 |
commit | 0487841120a7584da9a2b83b9574562c415d7024 (patch) | |
tree | fcd7e6444990efa8668ea2757401d6476e731457 /source | |
parent | 5278ec016cb24d8263fe6e7c1d389f466270ef24 (diff) | |
download | samba-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.h | 1 | ||||
-rw-r--r-- | source/include/smb.h | 3 | ||||
-rw-r--r-- | source/locking/locking.c | 184 | ||||
-rw-r--r-- | source/smbd/open.c | 115 |
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; |