Add a new kind of reference count (fd_holdcnt) to struct filedesc
which holds on to just the data structure and the mutex. (The existing refcount (fd_refcnt) holds onto the open files in the descriptor.) The fd_holdcnt is protected by fdesc_mtx, fd_refcnt by FILEDESC_LOCK. Add fdhold(struct proc *) which gets a hold on the filedescriptors of the specified proc.. Add fddrop(struct filedesc *) which drops the fd_holdcnt and if zero destroys the mutex and frees the memory. Initialize the fd_holdcnt to one in fdinit(). Normal operations on the filedesc structure will not change it. In fdfree() use fddrop() to dispose of the mutex and structure. Hold the FILEDESC_LOCK() until we have cleaned out the contents and carefully set the fields to null values during cleanup. Use fdhold()/fddrop() in mountcheckdirs() and sysctl_kern_file().
This commit is contained in:
parent
7e727eadc4
commit
d986dbb448
@ -1394,6 +1394,7 @@ fdinit(struct filedesc *fdp)
|
||||
|
||||
/* 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_fd.fd_ofiles = newfdp->fd_dfiles;
|
||||
newfdp->fd_fd.fd_ofileflags = newfdp->fd_dfileflags;
|
||||
@ -1402,6 +1403,34 @@ fdinit(struct filedesc *fdp)
|
||||
return (&newfdp->fd_fd);
|
||||
}
|
||||
|
||||
static struct filedesc *
|
||||
fdhold(struct proc *p)
|
||||
{
|
||||
struct filedesc *fdp;
|
||||
|
||||
mtx_lock(&fdesc_mtx);
|
||||
fdp = p->p_fd;
|
||||
if (fdp != NULL)
|
||||
fdp->fd_holdcnt++;
|
||||
mtx_unlock(&fdesc_mtx);
|
||||
return (fdp);
|
||||
}
|
||||
|
||||
static void
|
||||
fddrop(struct filedesc *fdp)
|
||||
{
|
||||
int i;
|
||||
|
||||
mtx_lock(&fdesc_mtx);
|
||||
i = --fdp->fd_holdcnt;
|
||||
mtx_unlock(&fdesc_mtx);
|
||||
if (i > 0)
|
||||
return;
|
||||
|
||||
mtx_destroy(&fdp->fd_mtx);
|
||||
FREE(fdp, M_FILEDESC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Share a filedesc structure.
|
||||
*/
|
||||
@ -1588,7 +1617,6 @@ fdfree(struct thread *td)
|
||||
* We are the last reference to the structure, so we can
|
||||
* safely assume it will not change out from under us.
|
||||
*/
|
||||
FILEDESC_UNLOCK(fdp);
|
||||
fpp = fdp->fd_ofiles;
|
||||
for (i = fdp->fd_lastfile; i-- >= 0; fpp++) {
|
||||
if (*fpp)
|
||||
@ -1604,14 +1632,22 @@ fdfree(struct thread *td)
|
||||
FREE(fdp->fd_ofiles, M_FILEDESC);
|
||||
if (NDSLOTS(fdp->fd_nfiles) > NDSLOTS(NDFILE))
|
||||
FREE(fdp->fd_map, M_FILEDESC);
|
||||
|
||||
fdp->fd_nfiles = 0;
|
||||
|
||||
if (fdp->fd_cdir)
|
||||
vrele(fdp->fd_cdir);
|
||||
fdp->fd_cdir = NULL;
|
||||
if (fdp->fd_rdir)
|
||||
vrele(fdp->fd_rdir);
|
||||
fdp->fd_rdir = NULL;
|
||||
if (fdp->fd_jdir)
|
||||
vrele(fdp->fd_jdir);
|
||||
mtx_destroy(&fdp->fd_mtx);
|
||||
FREE(fdp, M_FILEDESC);
|
||||
fdp->fd_jdir = NULL;
|
||||
|
||||
FILEDESC_UNLOCK(fdp);
|
||||
|
||||
fddrop(fdp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2262,8 +2298,7 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd, int mode,
|
||||
* mount point.
|
||||
*/
|
||||
void
|
||||
mountcheckdirs(olddp, newdp)
|
||||
struct vnode *olddp, *newdp;
|
||||
mountcheckdirs(struct vnode *olddp, struct vnode *newdp)
|
||||
{
|
||||
struct filedesc *fdp;
|
||||
struct proc *p;
|
||||
@ -2273,12 +2308,9 @@ mountcheckdirs(olddp, newdp)
|
||||
return;
|
||||
sx_slock(&allproc_lock);
|
||||
LIST_FOREACH(p, &allproc, p_list) {
|
||||
mtx_lock(&fdesc_mtx);
|
||||
fdp = p->p_fd;
|
||||
if (fdp == NULL) {
|
||||
mtx_unlock(&fdesc_mtx);
|
||||
fdp = fdhold(p);
|
||||
if (fdp == NULL)
|
||||
continue;
|
||||
}
|
||||
nrele = 0;
|
||||
FILEDESC_LOCK_FAST(fdp);
|
||||
if (fdp->fd_cdir == olddp) {
|
||||
@ -2292,7 +2324,6 @@ mountcheckdirs(olddp, newdp)
|
||||
nrele++;
|
||||
}
|
||||
FILEDESC_UNLOCK_FAST(fdp);
|
||||
mtx_unlock(&fdesc_mtx);
|
||||
while (nrele--)
|
||||
vrele(olddp);
|
||||
}
|
||||
@ -2383,11 +2414,9 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS)
|
||||
xf.xf_pid = p->p_pid;
|
||||
xf.xf_uid = p->p_ucred->cr_uid;
|
||||
PROC_UNLOCK(p);
|
||||
mtx_lock(&fdesc_mtx);
|
||||
if ((fdp = p->p_fd) == NULL) {
|
||||
mtx_unlock(&fdesc_mtx);
|
||||
fdp = fdhold(p);
|
||||
if (fdp == NULL)
|
||||
continue;
|
||||
}
|
||||
FILEDESC_LOCK_FAST(fdp);
|
||||
for (n = 0; n < fdp->fd_nfiles; ++n) {
|
||||
if ((fp = fdp->fd_ofiles[n]) == NULL)
|
||||
@ -2406,7 +2435,7 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS)
|
||||
break;
|
||||
}
|
||||
FILEDESC_UNLOCK_FAST(fdp);
|
||||
mtx_unlock(&fdesc_mtx);
|
||||
fddrop(fdp);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ struct filedesc {
|
||||
int fd_lastfile; /* high-water mark of fd_ofiles */
|
||||
int fd_freefile; /* approx. next free file */
|
||||
u_short fd_cmask; /* mask for file creation */
|
||||
u_short fd_refcnt; /* reference count */
|
||||
u_short fd_refcnt; /* thread reference count */
|
||||
u_short fd_holdcnt; /* hold count on structure + mutex */
|
||||
|
||||
struct mtx fd_mtx; /* protects members of this struct */
|
||||
int fd_locked; /* long lock flag */
|
||||
|
Loading…
Reference in New Issue
Block a user