Author: pjd
Date: Wed Jun 13 21:32:35 2012
New Revision: 237033
URL: http://svn.freebsd.org/changeset/base/237033

Log:
  Allocate descriptor number in dupfdopen() itself instead of depending on
  the caller using finstall().
  This saves us the filedesc lock/unlock cycle, fhold()/fdrop() cycle and closes
  a race between finstall() and dupfdopen().
  
  MFC after:    1 month

Modified:
  head/sys/kern/kern_descrip.c
  head/sys/kern/vfs_syscalls.c
  head/sys/sys/filedesc.h

Modified: head/sys/kern/kern_descrip.c
==============================================================================
--- head/sys/kern/kern_descrip.c        Wed Jun 13 21:22:35 2012        
(r237032)
+++ head/sys/kern/kern_descrip.c        Wed Jun 13 21:32:35 2012        
(r237033)
@@ -2588,13 +2588,13 @@ done2:
  * Duplicate the specified descriptor to a free descriptor.
  */
 int
-dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd, int 
mode, int error)
+dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode, int 
openerror, int *indxp)
 {
-       struct file *wfp;
        struct file *fp;
+       int error, indx;
 
-       KASSERT(error == ENODEV || error == ENXIO,
-           ("unexpected error %d in %s", error, __func__));
+       KASSERT(openerror == ENODEV || openerror == ENXIO,
+           ("unexpected error %d in %s", openerror, __func__));
 
        /*
         * If the to-be-dup'd fd number is greater than the allowed number
@@ -2603,11 +2603,17 @@ dupfdopen(struct thread *td, struct file
         */
        FILEDESC_XLOCK(fdp);
        if ((unsigned int)dfd >= fdp->fd_nfiles ||
-           (wfp = fdp->fd_ofiles[dfd]) == NULL) {
+           (fp = fdp->fd_ofiles[dfd]) == NULL) {
                FILEDESC_XUNLOCK(fdp);
                return (EBADF);
        }
 
+       error = fdalloc(td, 0, &indx);
+       if (error != 0) {
+               FILEDESC_XUNLOCK(fdp);
+               return (error);
+       }
+
        /*
         * There are two cases of interest here.
         *
@@ -2616,26 +2622,26 @@ dupfdopen(struct thread *td, struct file
         * For ENXIO steal away the file structure from (dfd) and store it in
         * (indx).  (dfd) is effectively closed by this operation.
         */
-       fp = fdp->fd_ofiles[indx];
-       switch (error) {
+       switch (openerror) {
        case ENODEV:
                /*
                 * Check that the mode the file is being opened for is a
                 * subset of the mode of the existing descriptor.
                 */
-               if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) {
+               if (((mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
+                       fdunused(fdp, indx);
                        FILEDESC_XUNLOCK(fdp);
                        return (EACCES);
                }
-               fdp->fd_ofiles[indx] = wfp;
+               fdp->fd_ofiles[indx] = fp;
                fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
-               fhold(wfp);
+               fhold(fp);
                break;
        case ENXIO:
                /*
                 * Steal away the file pointer from dfd and stuff it into indx.
                 */
-               fdp->fd_ofiles[indx] = wfp;
+               fdp->fd_ofiles[indx] = fp;
                fdp->fd_ofiles[dfd] = NULL;
                fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
                fdp->fd_ofileflags[dfd] = 0;
@@ -2643,11 +2649,7 @@ dupfdopen(struct thread *td, struct file
                break;
        }
        FILEDESC_XUNLOCK(fdp);
-       /*
-        * We now own the reference to fp that the ofiles[] array used to own.
-        * Release it.
-        */
-       fdrop(fp, td);
+       *indxp = indx;
        return (0);
 }
 

Modified: head/sys/kern/vfs_syscalls.c
==============================================================================
--- head/sys/kern/vfs_syscalls.c        Wed Jun 13 21:22:35 2012        
(r237032)
+++ head/sys/kern/vfs_syscalls.c        Wed Jun 13 21:32:35 2012        
(r237033)
@@ -1093,7 +1093,7 @@ kern_openat(struct thread *td, int fd, c
        struct file *fp;
        struct vnode *vp;
        int cmode;
-       int type, indx = -1, error, error_open;
+       int type, indx = -1, error;
        struct flock lf;
        struct nameidata nd;
        int vfslocked;
@@ -1143,9 +1143,7 @@ kern_openat(struct thread *td, int fd, c
                        goto success;
 
                /*
-                * Handle special fdopen() case. bleh. dupfdopen() is
-                * responsible for dropping the old contents of ofiles[indx]
-                * if it succeeds.
+                * Handle special fdopen() case. bleh.
                 *
                 * Don't do this for relative (capability) lookups; we don't
                 * understand exactly what would happen, and we don't think
@@ -1154,14 +1152,12 @@ kern_openat(struct thread *td, int fd, c
                if (nd.ni_strictrelative == 0 &&
                    (error == ENODEV || error == ENXIO) &&
                    td->td_dupfd >= 0) {
-                       /* XXX from fdopen */
-                       error_open = error;
-                       if ((error = finstall(td, fp, &indx, flags)) != 0)
-                               goto bad_unlocked;
-                       if ((error = dupfdopen(td, fdp, indx, td->td_dupfd,
-                           flags, error_open)) == 0)
+                       error = dupfdopen(td, fdp, td->td_dupfd, flags, error,
+                           &indx);
+                       if (error == 0)
                                goto success;
                }
+
                if (error == ERESTART)
                        error = EINTR;
                goto bad_unlocked;
@@ -4514,11 +4510,11 @@ sys_fhopen(td, uap)
                VFS_UNLOCK_GIANT(vfslocked);
                return (error);
        }
-
        /*
         * An extra reference on `fp' has been held for us by
         * falloc_noinstall().
         */
+
 #ifdef INVARIANTS
        td->td_dupfd = -1;
 #endif

Modified: head/sys/sys/filedesc.h
==============================================================================
--- head/sys/sys/filedesc.h     Wed Jun 13 21:22:35 2012        (r237032)
+++ head/sys/sys/filedesc.h     Wed Jun 13 21:32:35 2012        (r237033)
@@ -109,8 +109,8 @@ struct filedesc_to_leader {
 struct thread;
 
 int    closef(struct file *fp, struct thread *td);
-int    dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd,
-           int mode, int error);
+int    dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode,
+           int openerror, int *indxp);
 int    falloc(struct thread *td, struct file **resultfp, int *resultfd,
            int flags);
 int    falloc_noinstall(struct thread *td, struct file **resultfp);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to