svn commit: r237033 - in head/sys: kern sys
Pawel Jakub Dawidek
pjd at FreeBSD.org
Wed Jun 13 21:32:35 UTC 2012
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);
More information about the svn-src-head
mailing list