filedesc: factor out some code out of fdescfree

Previously it had a huge self-contained chunk dedicated to dealing with shared
tables.

No functional changes.
This commit is contained in:
Mateusz Guzik 2014-11-02 13:43:04 +00:00
parent ca109b01cf
commit 3dc85312b2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=273968

View File

@ -1945,6 +1945,87 @@ fdcopy(struct filedesc *fdp)
return (newfdp);
}
/*
* Clear POSIX style locks. This is only used when fdp looses a reference (i.e.
* one of processes using it exits) and the table used to be shared.
*/
static void
fdclearlocks(struct thread *td)
{
struct filedesc *fdp;
struct filedesc_to_leader *fdtol;
struct flock lf;
struct file *fp;
struct proc *p;
struct vnode *vp;
int i;
p = td->td_proc;
fdp = p->p_fd;
fdtol = p->p_fdtol;
MPASS(fdtol != NULL);
FILEDESC_XLOCK(fdp);
KASSERT(fdtol->fdl_refcount > 0,
("filedesc_to_refcount botch: fdl_refcount=%d",
fdtol->fdl_refcount));
if (fdtol->fdl_refcount == 1 &&
(p->p_leader->p_flag & P_ADVLOCK) != 0) {
for (i = 0; i <= fdp->fd_lastfile; i++) {
fp = fdp->fd_ofiles[i].fde_file;
if (fp == NULL || fp->f_type != DTYPE_VNODE)
continue;
fhold(fp);
FILEDESC_XUNLOCK(fdp);
lf.l_whence = SEEK_SET;
lf.l_start = 0;
lf.l_len = 0;
lf.l_type = F_UNLCK;
vp = fp->f_vnode;
(void) VOP_ADVLOCK(vp,
(caddr_t)p->p_leader, F_UNLCK,
&lf, F_POSIX);
FILEDESC_XLOCK(fdp);
fdrop(fp, td);
}
}
retry:
if (fdtol->fdl_refcount == 1) {
if (fdp->fd_holdleaderscount > 0 &&
(p->p_leader->p_flag & P_ADVLOCK) != 0) {
/*
* close() or do_dup() has cleared a reference
* in a shared file descriptor table.
*/
fdp->fd_holdleaderswakeup = 1;
sx_sleep(&fdp->fd_holdleaderscount,
FILEDESC_LOCK(fdp), PLOCK, "fdlhold", 0);
goto retry;
}
if (fdtol->fdl_holdcount > 0) {
/*
* Ensure that fdtol->fdl_leader remains
* valid in closef().
*/
fdtol->fdl_wakeup = 1;
sx_sleep(fdtol, FILEDESC_LOCK(fdp), PLOCK,
"fdlhold", 0);
goto retry;
}
}
fdtol->fdl_refcount--;
if (fdtol->fdl_refcount == 0 &&
fdtol->fdl_holdcount == 0) {
fdtol->fdl_next->fdl_prev = fdtol->fdl_prev;
fdtol->fdl_prev->fdl_next = fdtol->fdl_next;
} else
fdtol = NULL;
p->p_fdtol = NULL;
FILEDESC_XUNLOCK(fdp);
if (fdtol != NULL)
free(fdtol, M_FILEDESC_TO_LEADER);
}
/*
* Release a filedesc structure.
*/
@ -1952,12 +2033,10 @@ void
fdescfree(struct thread *td)
{
struct filedesc *fdp;
int i;
struct filedesc_to_leader *fdtol;
struct filedescent *fde;
struct file *fp;
struct vnode *cdir, *jdir, *rdir, *vp;
struct flock lf;
struct vnode *cdir, *jdir, *rdir;
int i;
/* Certain daemons might not have file descriptors. */
fdp = td->td_proc->p_fd;
@ -1970,69 +2049,8 @@ fdescfree(struct thread *td)
PROC_UNLOCK(td->td_proc);
#endif
/* Check for special need to clear POSIX style locks */
fdtol = td->td_proc->p_fdtol;
if (fdtol != NULL) {
FILEDESC_XLOCK(fdp);
KASSERT(fdtol->fdl_refcount > 0,
("filedesc_to_refcount botch: fdl_refcount=%d",
fdtol->fdl_refcount));
if (fdtol->fdl_refcount == 1 &&
(td->td_proc->p_leader->p_flag & P_ADVLOCK) != 0) {
for (i = 0; i <= fdp->fd_lastfile; i++) {
fp = fdp->fd_ofiles[i].fde_file;
if (fp == NULL || fp->f_type != DTYPE_VNODE)
continue;
fhold(fp);
FILEDESC_XUNLOCK(fdp);
lf.l_whence = SEEK_SET;
lf.l_start = 0;
lf.l_len = 0;
lf.l_type = F_UNLCK;
vp = fp->f_vnode;
(void) VOP_ADVLOCK(vp,
(caddr_t)td->td_proc->p_leader, F_UNLCK,
&lf, F_POSIX);
FILEDESC_XLOCK(fdp);
fdrop(fp, td);
}
}
retry:
if (fdtol->fdl_refcount == 1) {
if (fdp->fd_holdleaderscount > 0 &&
(td->td_proc->p_leader->p_flag & P_ADVLOCK) != 0) {
/*
* close() or do_dup() has cleared a reference
* in a shared file descriptor table.
*/
fdp->fd_holdleaderswakeup = 1;
sx_sleep(&fdp->fd_holdleaderscount,
FILEDESC_LOCK(fdp), PLOCK, "fdlhold", 0);
goto retry;
}
if (fdtol->fdl_holdcount > 0) {
/*
* Ensure that fdtol->fdl_leader remains
* valid in closef().
*/
fdtol->fdl_wakeup = 1;
sx_sleep(fdtol, FILEDESC_LOCK(fdp), PLOCK,
"fdlhold", 0);
goto retry;
}
}
fdtol->fdl_refcount--;
if (fdtol->fdl_refcount == 0 &&
fdtol->fdl_holdcount == 0) {
fdtol->fdl_next->fdl_prev = fdtol->fdl_prev;
fdtol->fdl_prev->fdl_next = fdtol->fdl_next;
} else
fdtol = NULL;
td->td_proc->p_fdtol = NULL;
FILEDESC_XUNLOCK(fdp);
if (fdtol != NULL)
free(fdtol, M_FILEDESC_TO_LEADER);
}
if (td->td_proc->p_fdtol != NULL)
fdclearlocks(td);
mtx_lock(&fdesc_mtx);
td->td_proc->p_fd = NULL;