filedesc: make fdinit return with source filedesc locked and new one sized

appropriately

Assert FILEDESC_XLOCK_ASSERT only for already used tables in fdgrowtable.
We don't have to call it with the lock held if we are just creating new
filedesc.

As a side note, strictly speaking processes can have fdtables with
fd_lastfile = -1, but then they cannot enter fdgrowtable. Very first file
descriptor they get will be 0 and the only syscall allowing to choose fd number
requires an active file descriptor. Should this ever change, we can add an 'init'
(or similar) parameter to fdgrowtable.
This commit is contained in:
Mateusz Guzik 2014-10-31 09:25:28 +00:00
parent ffeb890592
commit f652d856ab
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=273895

View File

@ -1524,7 +1524,13 @@ fdgrowtable(struct filedesc *fdp, int nfd)
int nnfiles, onfiles;
NDSLOTTYPE *nmap, *omap;
FILEDESC_XLOCK_ASSERT(fdp);
/*
* If lastfile is -1 this struct filedesc was just allocated and we are
* growing it to accomodate for the one we are going to copy from. There
* is no need to have a lock on this one as it's not visible to anyone.
*/
if (fdp->fd_lastfile != -1)
FILEDESC_XLOCK_ASSERT(fdp);
KASSERT(fdp->fd_nfiles > 0, ("zero-length file table"));
@ -1791,37 +1797,52 @@ finstall(struct thread *td, struct file *fp, int *fd, int flags,
/*
* Build a new filedesc structure from another.
* Copy the current, root, and jail root vnode references.
*
* If fdp is not NULL, return with it shared locked.
*/
struct filedesc *
fdinit(struct filedesc *fdp)
{
struct filedesc0 *newfdp;
struct filedesc0 *newfdp0;
struct filedesc *newfdp;
newfdp = malloc(sizeof *newfdp, M_FILEDESC, M_WAITOK | M_ZERO);
FILEDESC_LOCK_INIT(&newfdp->fd_fd);
if (fdp != NULL) {
FILEDESC_SLOCK(fdp);
newfdp->fd_fd.fd_cdir = fdp->fd_cdir;
if (newfdp->fd_fd.fd_cdir)
VREF(newfdp->fd_fd.fd_cdir);
newfdp->fd_fd.fd_rdir = fdp->fd_rdir;
if (newfdp->fd_fd.fd_rdir)
VREF(newfdp->fd_fd.fd_rdir);
newfdp->fd_fd.fd_jdir = fdp->fd_jdir;
if (newfdp->fd_fd.fd_jdir)
VREF(newfdp->fd_fd.fd_jdir);
FILEDESC_SUNLOCK(fdp);
}
newfdp0 = malloc(sizeof *newfdp0, M_FILEDESC, M_WAITOK | M_ZERO);
newfdp = &newfdp0->fd_fd;
/* Create the file descriptor table. */
newfdp->fd_fd.fd_refcnt = 1;
newfdp->fd_fd.fd_holdcnt = 1;
newfdp->fd_fd.fd_cmask = CMASK;
newfdp->fd_dfiles.fdt_nfiles = NDFILE;
newfdp->fd_fd.fd_files = (struct fdescenttbl *)&newfdp->fd_dfiles;
newfdp->fd_fd.fd_map = newfdp->fd_dmap;
newfdp->fd_fd.fd_lastfile = -1;
return (&newfdp->fd_fd);
FILEDESC_LOCK_INIT(newfdp);
newfdp->fd_refcnt = 1;
newfdp->fd_holdcnt = 1;
newfdp->fd_cmask = CMASK;
newfdp->fd_map = newfdp0->fd_dmap;
newfdp->fd_lastfile = -1;
newfdp->fd_files = (struct fdescenttbl *)&newfdp0->fd_dfiles;
newfdp->fd_files->fdt_nfiles = NDFILE;
if (fdp == NULL)
return (newfdp);
if (fdp->fd_lastfile >= newfdp->fd_nfiles)
fdgrowtable(newfdp, fdp->fd_lastfile + 1);
FILEDESC_SLOCK(fdp);
newfdp->fd_cdir = fdp->fd_cdir;
if (newfdp->fd_cdir)
VREF(newfdp->fd_cdir);
newfdp->fd_rdir = fdp->fd_rdir;
if (newfdp->fd_rdir)
VREF(newfdp->fd_rdir);
newfdp->fd_jdir = fdp->fd_jdir;
if (newfdp->fd_jdir)
VREF(newfdp->fd_jdir);
while (fdp->fd_lastfile >= newfdp->fd_nfiles) {
FILEDESC_SUNLOCK(fdp);
fdgrowtable(newfdp, fdp->fd_lastfile + 1);
FILEDESC_SLOCK(fdp);
}
return (newfdp);
}
static struct filedesc *
@ -1905,14 +1926,6 @@ fdcopy(struct filedesc *fdp)
return (NULL);
newfdp = fdinit(fdp);
FILEDESC_SLOCK(fdp);
while (fdp->fd_lastfile >= newfdp->fd_nfiles) {
FILEDESC_SUNLOCK(fdp);
FILEDESC_XLOCK(newfdp);
fdgrowtable(newfdp, fdp->fd_lastfile + 1);
FILEDESC_XUNLOCK(newfdp);
FILEDESC_SLOCK(fdp);
}
/* copy all passable descriptors (i.e. not kqueue) */
newfdp->fd_freefile = -1;
for (i = 0; i <= fdp->fd_lastfile; ++i) {