Date: Wed, 13 Jun 2012 21:32:35 +0000 (UTC) From: Pawel Jakub Dawidek <pjd@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r237033 - in head/sys: kern sys Message-ID: <201206132132.q5DLWZfo050195@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201206132132.q5DLWZfo050195>