Added the code that keeps fd's open across a close if there are other fsp's
authorJeremy Allison <jra@samba.org>
Mon, 24 Apr 2000 20:48:40 +0000 (20:48 +0000)
committerJeremy Allison <jra@samba.org>
Mon, 24 Apr 2000 20:48:40 +0000 (20:48 +0000)
open on the same dev/inode pair with existing POSIX locks.

This is done at the smbd/open layer, so smbd just calls fd_close() and
the transfer of any open fd's is done under the covers of fd_close().
When an fsp is closed and no other fsp's open on the same dev/inode
pair have existing POSIX locks then all fd's associated with this fsp
are closed.

Now only the hard part of doing the POSIX range unlock code when read
locks overlap remains for full POSIX/SMB lock integration....

Jeremy.

source/include/smb.h
source/locking/locking.c
source/smbd/open.c

index 7fef3f40b7123ae40abfbc785d40c704674fb47e..5147a567b401fd69d103ea41dc296605b5d7cdba 100644 (file)
@@ -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;
index 9f33cba338fdacf20f114beb830703d9ca1ad398..a73af8fd076c99375f28c826130a40ad0b45aad7 100644 (file)
@@ -40,42 +40,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 :-).
 ****************************************************************************/
@@ -416,6 +380,29 @@ static BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG
        return True;
 }
 
+/****************************************************************************
+ 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.
 ****************************************************************************/
index 353e20df8a22fc53ceff40fc7d310cf71913f454..44bb6ebaf7d94cb27adfa08cea26affbf32a6b99 100644 (file)
@@ -49,14 +49,126 @@ static int fd_open(struct connection_struct *conn, char *fname,
        return fd;
 }
 
+/****************************************************************************
+  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;