summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h2
-rw-r--r--source3/locking/locking.c59
-rw-r--r--source3/smbd/open.c120
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;