diff options
-rw-r--r-- | source3/include/smb.h | 2 | ||||
-rw-r--r-- | source3/locking/locking.c | 59 | ||||
-rw-r--r-- | source3/smbd/open.c | 120 |
3 files changed, 144 insertions, 37 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h index 7fef3f40b7..5147a567b4 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -490,6 +490,8 @@ typedef struct files_struct int oplock_type; int sent_oplock_break; unsigned 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/source3/locking/locking.c b/source3/locking/locking.c index 9f33cba338..a73af8fd07 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -41,42 +41,6 @@ static TDB_CONTEXT *tdb; int global_smbpid; /**************************************************************************** - Remove any locks on this fd. -****************************************************************************/ - -void locking_close_file(files_struct *fsp) -{ - if (!lp_locking(SNUM(fsp->conn))) - return; - - if(lp_posix_locking(SNUM(fsp->conn))) { - /* - * We need to release all POSIX locks we have on this - * fd. - */ - } - - /* - * Now release all the tdb locks. - */ - - /* Placeholder for code here.... */ -#if 0 - brl_close(fsp->dev, fsp->inode, getpid(), fsp->conn->cnum, fsp->fnum); - - /* - * We now need to search our open file list for any other - * fd open on this file with outstanding POSIX locks. If we - * don't find one, great, just return. If we do find one then - * we have to add this file descriptor to the 'pending close' - * list of that fd, to stop the POSIX problem where the locks - * on *that* fd will get lost when we close this one. POSIX - * braindamage... JRA. - */ -#endif -} - -/**************************************************************************** Debugging aid :-). ****************************************************************************/ @@ -417,6 +381,29 @@ static BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG } /**************************************************************************** + Remove any locks on this fd. Called from file_close(). +****************************************************************************/ + +void locking_close_file(files_struct *fsp) +{ + if (!lp_locking(SNUM(fsp->conn))) + return; + + if(lp_posix_locking(SNUM(fsp->conn))) { + /* + * We need to release all POSIX locks we have on this + * fd. + */ + } + + /* + * Now release all the tdb locks. + */ + + brl_close(fsp->dev, fsp->inode, getpid(), fsp->conn->cnum, fsp->fnum); +} + +/**************************************************************************** Utility function called to see if a file region is locked. ****************************************************************************/ diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 353e20df8a..44bb6ebaf7 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -50,13 +50,125 @@ 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.\n", fsp->fsp_name, + (unsigned int)fsp->num_posix_pending_closes )); + + for(other_fsp = file_find_di_first(fsp->dev, fsp->inode); other_fsp; + other_fsp = file_find_di_next(other_fsp)) { + + 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, other_fsp->num_posix_pending_closes = %u.\n", + fsp->fsp_name, other_fsp->fsp_name, (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 = conn->vfs_ops.close(fsp->fd); + 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)) + 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; } @@ -163,6 +275,8 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, 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; @@ -797,6 +911,8 @@ files_struct *open_file_stat(connection_struct *conn, 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; @@ -921,6 +1037,8 @@ files_struct *open_directory(connection_struct *conn, 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; |