vfs: add vrefact, to be used when the vnode has to be already active

This allows blind increment of relevant counters which under contention
is cheaper than inc-not-zero loops at least on amd64.

Use it in some of the places which are guaranteed to see already active
vnodes.

Reviewed by:	kib (previous version)
This commit is contained in:
mjg 2016-12-12 15:37:11 +00:00
parent f24a1f7d0d
commit f03b37f3e8
5 changed files with 51 additions and 28 deletions

View File

@ -318,11 +318,11 @@ pwd_ensure_dirs(void)
FILEDESC_XLOCK(fdp); FILEDESC_XLOCK(fdp);
if (fdp->fd_cdir == NULL) { if (fdp->fd_cdir == NULL) {
fdp->fd_cdir = rootvnode; fdp->fd_cdir = rootvnode;
VREF(rootvnode); vrefact(rootvnode);
} }
if (fdp->fd_rdir == NULL) { if (fdp->fd_rdir == NULL) {
fdp->fd_rdir = rootvnode; fdp->fd_rdir = rootvnode;
VREF(rootvnode); vrefact(rootvnode);
} }
FILEDESC_XUNLOCK(fdp); FILEDESC_XUNLOCK(fdp);
} }
@ -1860,13 +1860,13 @@ fdinit(struct filedesc *fdp, bool prepfiles)
FILEDESC_SLOCK(fdp); FILEDESC_SLOCK(fdp);
newfdp->fd_cdir = fdp->fd_cdir; newfdp->fd_cdir = fdp->fd_cdir;
if (newfdp->fd_cdir) if (newfdp->fd_cdir)
VREF(newfdp->fd_cdir); vrefact(newfdp->fd_cdir);
newfdp->fd_rdir = fdp->fd_rdir; newfdp->fd_rdir = fdp->fd_rdir;
if (newfdp->fd_rdir) if (newfdp->fd_rdir)
VREF(newfdp->fd_rdir); vrefact(newfdp->fd_rdir);
newfdp->fd_jdir = fdp->fd_jdir; newfdp->fd_jdir = fdp->fd_jdir;
if (newfdp->fd_jdir) if (newfdp->fd_jdir)
VREF(newfdp->fd_jdir); vrefact(newfdp->fd_jdir);
if (!prepfiles) { if (!prepfiles) {
FILEDESC_SUNLOCK(fdp); FILEDESC_SUNLOCK(fdp);
@ -2769,7 +2769,7 @@ _fgetvp(struct thread *td, int fd, int flags, cap_rights_t *needrightsp,
error = EINVAL; error = EINVAL;
} else { } else {
*vpp = fp->f_vnode; *vpp = fp->f_vnode;
vref(*vpp); vrefact(*vpp);
} }
fdrop(fp, td); fdrop(fp, td);
@ -2807,7 +2807,7 @@ fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp,
*havecaps = caps; *havecaps = caps;
*vpp = fp->f_vnode; *vpp = fp->f_vnode;
vref(*vpp); vrefact(*vpp);
return (0); return (0);
out: out:
@ -3115,10 +3115,10 @@ pwd_chroot(struct thread *td, struct vnode *vp)
} }
} }
oldvp = fdp->fd_rdir; oldvp = fdp->fd_rdir;
VREF(vp); vrefact(vp);
fdp->fd_rdir = vp; fdp->fd_rdir = vp;
if (fdp->fd_jdir == NULL) { if (fdp->fd_jdir == NULL) {
VREF(vp); vrefact(vp);
fdp->fd_jdir = vp; fdp->fd_jdir = vp;
} }
FILEDESC_XUNLOCK(fdp); FILEDESC_XUNLOCK(fdp);
@ -3166,17 +3166,17 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp)
continue; continue;
FILEDESC_XLOCK(fdp); FILEDESC_XLOCK(fdp);
if (fdp->fd_cdir == olddp) { if (fdp->fd_cdir == olddp) {
vref(newdp); vrefact(newdp);
fdp->fd_cdir = newdp; fdp->fd_cdir = newdp;
nrele++; nrele++;
} }
if (fdp->fd_rdir == olddp) { if (fdp->fd_rdir == olddp) {
vref(newdp); vrefact(newdp);
fdp->fd_rdir = newdp; fdp->fd_rdir = newdp;
nrele++; nrele++;
} }
if (fdp->fd_jdir == olddp) { if (fdp->fd_jdir == olddp) {
vref(newdp); vrefact(newdp);
fdp->fd_jdir = newdp; fdp->fd_jdir = newdp;
nrele++; nrele++;
} }
@ -3185,13 +3185,13 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp)
} }
sx_sunlock(&allproc_lock); sx_sunlock(&allproc_lock);
if (rootvnode == olddp) { if (rootvnode == olddp) {
vref(newdp); vrefact(newdp);
rootvnode = newdp; rootvnode = newdp;
nrele++; nrele++;
} }
mtx_lock(&prison0.pr_mtx); mtx_lock(&prison0.pr_mtx);
if (prison0.pr_root == olddp) { if (prison0.pr_root == olddp) {
vref(newdp); vrefact(newdp);
prison0.pr_root = newdp; prison0.pr_root = newdp;
nrele++; nrele++;
} }
@ -3200,7 +3200,7 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp)
TAILQ_FOREACH(pr, &allprison, pr_list) { TAILQ_FOREACH(pr, &allprison, pr_list) {
mtx_lock(&pr->pr_mtx); mtx_lock(&pr->pr_mtx);
if (pr->pr_root == olddp) { if (pr->pr_root == olddp) {
vref(newdp); vrefact(newdp);
pr->pr_root = newdp; pr->pr_root = newdp;
nrele++; nrele++;
} }
@ -3527,17 +3527,17 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen,
/* ktrace vnode */ /* ktrace vnode */
tracevp = p->p_tracevp; tracevp = p->p_tracevp;
if (tracevp != NULL) if (tracevp != NULL)
vref(tracevp); vrefact(tracevp);
/* text vnode */ /* text vnode */
textvp = p->p_textvp; textvp = p->p_textvp;
if (textvp != NULL) if (textvp != NULL)
vref(textvp); vrefact(textvp);
/* Controlling tty. */ /* Controlling tty. */
cttyvp = NULL; cttyvp = NULL;
if (p->p_pgrp != NULL && p->p_pgrp->pg_session != NULL) { if (p->p_pgrp != NULL && p->p_pgrp->pg_session != NULL) {
cttyvp = p->p_pgrp->pg_session->s_ttyvp; cttyvp = p->p_pgrp->pg_session->s_ttyvp;
if (cttyvp != NULL) if (cttyvp != NULL)
vref(cttyvp); vrefact(cttyvp);
} }
fdp = fdhold(p); fdp = fdhold(p);
PROC_UNLOCK(p); PROC_UNLOCK(p);
@ -3561,17 +3561,17 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen,
FILEDESC_SLOCK(fdp); FILEDESC_SLOCK(fdp);
/* working directory */ /* working directory */
if (fdp->fd_cdir != NULL) { if (fdp->fd_cdir != NULL) {
vref(fdp->fd_cdir); vrefact(fdp->fd_cdir);
export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD, FREAD, efbuf); export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD, FREAD, efbuf);
} }
/* root directory */ /* root directory */
if (fdp->fd_rdir != NULL) { if (fdp->fd_rdir != NULL) {
vref(fdp->fd_rdir); vrefact(fdp->fd_rdir);
export_vnode_to_sb(fdp->fd_rdir, KF_FD_TYPE_ROOT, FREAD, efbuf); export_vnode_to_sb(fdp->fd_rdir, KF_FD_TYPE_ROOT, FREAD, efbuf);
} }
/* jail directory */ /* jail directory */
if (fdp->fd_jdir != NULL) { if (fdp->fd_jdir != NULL) {
vref(fdp->fd_jdir); vrefact(fdp->fd_jdir);
export_vnode_to_sb(fdp->fd_jdir, KF_FD_TYPE_JAIL, FREAD, efbuf); export_vnode_to_sb(fdp->fd_jdir, KF_FD_TYPE_JAIL, FREAD, efbuf);
} }
for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) { for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) {
@ -3661,7 +3661,7 @@ export_vnode_for_osysctl(struct vnode *vp, int type, struct kinfo_file *kif,
{ {
int error; int error;
vref(vp); vrefact(vp);
FILEDESC_SUNLOCK(fdp); FILEDESC_SUNLOCK(fdp);
export_vnode_to_kinfo(vp, type, 0, kif, KERN_FILEDESC_PACK_KINFO); export_vnode_to_kinfo(vp, type, 0, kif, KERN_FILEDESC_PACK_KINFO);
kinfo_to_okinfo(kif, okif); kinfo_to_okinfo(kif, okif);
@ -3788,7 +3788,7 @@ kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen)
if (fdp->fd_cdir == NULL) if (fdp->fd_cdir == NULL)
error = EINVAL; error = EINVAL;
else { else {
vref(fdp->fd_cdir); vrefact(fdp->fd_cdir);
error = export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD, error = export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD,
FREAD, efbuf); FREAD, efbuf);
} }

View File

@ -547,7 +547,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread *
/* Bump references to the text vnode (for procfs). */ /* Bump references to the text vnode (for procfs). */
if (p2->p_textvp) if (p2->p_textvp)
vref(p2->p_textvp); vrefact(p2->p_textvp);
/* /*
* Set up linkage for kernel based threading. * Set up linkage for kernel based threading.

View File

@ -255,7 +255,7 @@ namei_handle_root(struct nameidata *ndp, struct vnode **dpp)
ndp->ni_pathlen--; ndp->ni_pathlen--;
} }
*dpp = ndp->ni_rootdir; *dpp = ndp->ni_rootdir;
VREF(*dpp); vrefact(*dpp);
return (0); return (0);
} }
@ -376,7 +376,7 @@ namei(struct nameidata *ndp)
*/ */
FILEDESC_SLOCK(fdp); FILEDESC_SLOCK(fdp);
ndp->ni_rootdir = fdp->fd_rdir; ndp->ni_rootdir = fdp->fd_rdir;
VREF(ndp->ni_rootdir); vrefact(ndp->ni_rootdir);
ndp->ni_topdir = fdp->fd_jdir; ndp->ni_topdir = fdp->fd_jdir;
/* /*
@ -398,7 +398,7 @@ namei(struct nameidata *ndp)
startdir_used = 1; startdir_used = 1;
} else if (ndp->ni_dirfd == AT_FDCWD) { } else if (ndp->ni_dirfd == AT_FDCWD) {
dp = fdp->fd_cdir; dp = fdp->fd_cdir;
VREF(dp); vrefact(dp);
} else { } else {
rights = ndp->ni_rightsneeded; rights = ndp->ni_rightsneeded;
cap_rights_set(&rights, CAP_LOOKUP); cap_rights_set(&rights, CAP_LOOKUP);
@ -956,7 +956,7 @@ lookup(struct nameidata *ndp)
vput(ndp->ni_dvp); vput(ndp->ni_dvp);
else else
vrele(ndp->ni_dvp); vrele(ndp->ni_dvp);
vref(vp_crossmp); vrefact(vp_crossmp);
ndp->ni_dvp = vp_crossmp; ndp->ni_dvp = vp_crossmp;
error = VFS_ROOT(mp, compute_cn_lkflags(mp, cnp->cn_lkflags, error = VFS_ROOT(mp, compute_cn_lkflags(mp, cnp->cn_lkflags,
cnp->cn_flags), &tdp); cnp->cn_flags), &tdp);

View File

@ -2647,6 +2647,28 @@ vrefl(struct vnode *vp)
v_incr_usecount_locked(vp); v_incr_usecount_locked(vp);
} }
void
vrefact(struct vnode *vp)
{
CTR2(KTR_VFS, "%s: vp %p", __func__, vp);
if (__predict_false(vp->v_type == VCHR)) {
VNASSERT(vp->v_holdcnt > 0 && vp->v_usecount > 0, vp,
("%s: wrong ref counts", __func__));
vref(vp);
return;
}
#ifdef INVARIANTS
int old = atomic_fetchadd_int(&vp->v_holdcnt, 1);
VNASSERT(old > 0, vp, ("%s: wrong hold count", __func__));
old = atomic_fetchadd_int(&vp->v_usecount, 1);
VNASSERT(old > 0, vp, ("%s: wrong use count", __func__));
#else
refcount_acquire(&vp->v_holdcnt);
refcount_acquire(&vp->v_usecount);
#endif
}
/* /*
* Return reference count of a vnode. * Return reference count of a vnode.
* *

View File

@ -828,6 +828,7 @@ void vput(struct vnode *vp);
void vrele(struct vnode *vp); void vrele(struct vnode *vp);
void vref(struct vnode *vp); void vref(struct vnode *vp);
void vrefl(struct vnode *vp); void vrefl(struct vnode *vp);
void vrefact(struct vnode *vp);
int vrefcnt(struct vnode *vp); int vrefcnt(struct vnode *vp);
void v_addpollinfo(struct vnode *vp); void v_addpollinfo(struct vnode *vp);