mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-29 16:44:03 +00:00
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
This commit is contained in:
parent
7f35af0110
commit
3812dcd3de
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=237033
@ -2588,13 +2588,13 @@ sys_flock(struct thread *td, struct flock_args *uap)
|
||||
* 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 filedesc *fdp, int indx, int dfd, int mode,
|
||||
*/
|
||||
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 filedesc *fdp, int indx, int dfd, int mode,
|
||||
* 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 filedesc *fdp, int indx, int dfd, int mode,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1093,7 +1093,7 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
|
||||
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, char *path, enum uio_seg pathseg,
|
||||
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, char *path, enum uio_seg pathseg,
|
||||
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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user