Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/kern_descrip.c
Show First 20 Lines • Show All 864 Lines • ▼ Show 20 Lines | |||||
* Common code for dup, dup2, fcntl(F_DUPFD) and fcntl(F_DUP2FD). | * Common code for dup, dup2, fcntl(F_DUPFD) and fcntl(F_DUP2FD). | ||||
*/ | */ | ||||
int | int | ||||
kern_dup(struct thread *td, u_int mode, int flags, int old, int new) | kern_dup(struct thread *td, u_int mode, int flags, int old, int new) | ||||
{ | { | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct filedescent *oldfde, *newfde; | struct filedescent *oldfde, *newfde; | ||||
struct proc *p; | struct proc *p; | ||||
struct file *delfp; | struct file *delfp, *oldfp; | ||||
u_long *oioctls, *nioctls; | u_long *oioctls, *nioctls; | ||||
int error, maxfd; | int error, maxfd; | ||||
p = td->td_proc; | p = td->td_proc; | ||||
fdp = p->p_fd; | fdp = p->p_fd; | ||||
oioctls = NULL; | oioctls = NULL; | ||||
MPASS((flags & ~(FDDUP_FLAG_CLOEXEC)) == 0); | MPASS((flags & ~(FDDUP_FLAG_CLOEXEC)) == 0); | ||||
Show All 23 Lines | if ((mode == FDDUP_FIXED || mode == FDDUP_MUSTREPLACE) && old == new) { | ||||
td->td_retval[0] = new; | td->td_retval[0] = new; | ||||
if (flags & FDDUP_FLAG_CLOEXEC) | if (flags & FDDUP_FLAG_CLOEXEC) | ||||
fdp->fd_ofiles[new].fde_flags |= UF_EXCLOSE; | fdp->fd_ofiles[new].fde_flags |= UF_EXCLOSE; | ||||
error = 0; | error = 0; | ||||
goto unlock; | goto unlock; | ||||
} | } | ||||
oldfde = &fdp->fd_ofiles[old]; | oldfde = &fdp->fd_ofiles[old]; | ||||
if (!fhold(oldfde->fde_file)) | oldfp = oldfde->fde_file; | ||||
if (!fhold(oldfp)) | |||||
goto unlock; | goto unlock; | ||||
/* | /* | ||||
* If the caller specified a file descriptor, make sure the file | * If the caller specified a file descriptor, make sure the file | ||||
* table is large enough to hold it, and grab it. Otherwise, just | * table is large enough to hold it, and grab it. Otherwise, just | ||||
* allocate a new descriptor the usual way. | * allocate a new descriptor the usual way. | ||||
*/ | */ | ||||
switch (mode) { | switch (mode) { | ||||
case FDDUP_NORMAL: | case FDDUP_NORMAL: | ||||
case FDDUP_FCNTL: | case FDDUP_FCNTL: | ||||
if ((error = fdalloc(td, new, &new)) != 0) { | if ((error = fdalloc(td, new, &new)) != 0) { | ||||
fdrop(oldfde->fde_file, td); | fdrop(oldfp, td); | ||||
goto unlock; | goto unlock; | ||||
} | } | ||||
break; | break; | ||||
case FDDUP_MUSTREPLACE: | case FDDUP_MUSTREPLACE: | ||||
/* Target file descriptor must exist. */ | /* Target file descriptor must exist. */ | ||||
if (fget_locked(fdp, new) == NULL) { | if (fget_locked(fdp, new) == NULL) { | ||||
fdrop(oldfde->fde_file, td); | fdrop(oldfp, td); | ||||
goto unlock; | goto unlock; | ||||
} | } | ||||
break; | break; | ||||
case FDDUP_FIXED: | case FDDUP_FIXED: | ||||
if (new >= fdp->fd_nfiles) { | if (new >= fdp->fd_nfiles) { | ||||
/* | /* | ||||
* The resource limits are here instead of e.g. | * The resource limits are here instead of e.g. | ||||
* fdalloc(), because the file descriptor table may be | * fdalloc(), because the file descriptor table may be | ||||
* shared between processes, so we can't really use | * shared between processes, so we can't really use | ||||
* racct_add()/racct_sub(). Instead of counting the | * racct_add()/racct_sub(). Instead of counting the | ||||
* number of actually allocated descriptors, just put | * number of actually allocated descriptors, just put | ||||
* the limit on the size of the file descriptor table. | * the limit on the size of the file descriptor table. | ||||
*/ | */ | ||||
#ifdef RACCT | #ifdef RACCT | ||||
if (RACCT_ENABLED()) { | if (RACCT_ENABLED()) { | ||||
error = racct_set_unlocked(p, RACCT_NOFILE, new + 1); | error = racct_set_unlocked(p, RACCT_NOFILE, new + 1); | ||||
if (error != 0) { | if (error != 0) { | ||||
error = EMFILE; | error = EMFILE; | ||||
fdrop(oldfde->fde_file, td); | fdrop(oldfp, td); | ||||
goto unlock; | goto unlock; | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
fdgrowtable_exp(fdp, new + 1); | fdgrowtable_exp(fdp, new + 1); | ||||
} | } | ||||
if (!fdisused(fdp, new)) | if (!fdisused(fdp, new)) | ||||
fdused(fdp, new); | fdused(fdp, new); | ||||
break; | break; | ||||
default: | default: | ||||
KASSERT(0, ("%s unsupported mode %d", __func__, mode)); | KASSERT(0, ("%s unsupported mode %d", __func__, mode)); | ||||
} | } | ||||
KASSERT(old != new, ("new fd is same as old")); | KASSERT(old != new, ("new fd is same as old")); | ||||
/* Refetch oldfde because the table may have grown and old one freed. */ | |||||
oldfde = &fdp->fd_ofiles[old]; | |||||
KASSERT(oldfp == oldfde->fde_file, | |||||
("fdt_ofiles shift from growth observed at fd %d", | |||||
old)); | |||||
newfde = &fdp->fd_ofiles[new]; | newfde = &fdp->fd_ofiles[new]; | ||||
delfp = newfde->fde_file; | delfp = newfde->fde_file; | ||||
nioctls = filecaps_copy_prep(&oldfde->fde_caps); | nioctls = filecaps_copy_prep(&oldfde->fde_caps); | ||||
/* | /* | ||||
* Duplicate the source descriptor. | * Duplicate the source descriptor. | ||||
▲ Show 20 Lines • Show All 3,918 Lines • Show Last 20 Lines |