summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormjg <mjg@FreeBSD.org>2016-12-31 12:06:27 +0000
committermjg <mjg@FreeBSD.org>2016-12-31 12:06:27 +0000
commit1af6bcb527e97aaddea67934bd4fcbd6cb8a1d01 (patch)
tree6bcdec0ca237f2d33a315bfad1b0af77fdadd516
parentf83e24b3d82a425ec8bd4bb259f6c75ce6786280 (diff)
downloadFreeBSD-src-1af6bcb527e97aaddea67934bd4fcbd6cb8a1d01.zip
FreeBSD-src-1af6bcb527e97aaddea67934bd4fcbd6cb8a1d01.tar.gz
MFC r309893,r309929:
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. == vfs: use vrefact in getcwd and fchdir
-rw-r--r--sys/kern/kern_descrip.c46
-rw-r--r--sys/kern/kern_fork.c2
-rw-r--r--sys/kern/vfs_cache.c4
-rw-r--r--sys/kern/vfs_lookup.c8
-rw-r--r--sys/kern/vfs_subr.c22
-rw-r--r--sys/kern/vfs_syscalls.c2
-rw-r--r--sys/sys/vnode.h1
7 files changed, 54 insertions, 31 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index c4edfc9..45e6e97 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -318,11 +318,11 @@ pwd_ensure_dirs(void)
FILEDESC_XLOCK(fdp);
if (fdp->fd_cdir == NULL) {
fdp->fd_cdir = rootvnode;
- VREF(rootvnode);
+ vrefact(rootvnode);
}
if (fdp->fd_rdir == NULL) {
fdp->fd_rdir = rootvnode;
- VREF(rootvnode);
+ vrefact(rootvnode);
}
FILEDESC_XUNLOCK(fdp);
}
@@ -1855,13 +1855,13 @@ fdinit(struct filedesc *fdp, bool prepfiles)
FILEDESC_SLOCK(fdp);
newfdp->fd_cdir = fdp->fd_cdir;
if (newfdp->fd_cdir)
- VREF(newfdp->fd_cdir);
+ vrefact(newfdp->fd_cdir);
newfdp->fd_rdir = fdp->fd_rdir;
if (newfdp->fd_rdir)
- VREF(newfdp->fd_rdir);
+ vrefact(newfdp->fd_rdir);
newfdp->fd_jdir = fdp->fd_jdir;
if (newfdp->fd_jdir)
- VREF(newfdp->fd_jdir);
+ vrefact(newfdp->fd_jdir);
if (!prepfiles) {
FILEDESC_SUNLOCK(fdp);
@@ -2688,7 +2688,7 @@ _fgetvp(struct thread *td, int fd, int flags, cap_rights_t *needrightsp,
error = EINVAL;
} else {
*vpp = fp->f_vnode;
- vref(*vpp);
+ vrefact(*vpp);
}
fdrop(fp, td);
@@ -2727,7 +2727,7 @@ fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp,
return (EINVAL);
*vpp = fp->f_vnode;
- vref(*vpp);
+ vrefact(*vpp);
filecaps_copy(&fdp->fd_ofiles[fd].fde_caps, havecaps, true);
return (0);
@@ -3033,10 +3033,10 @@ pwd_chroot(struct thread *td, struct vnode *vp)
}
}
oldvp = fdp->fd_rdir;
- VREF(vp);
+ vrefact(vp);
fdp->fd_rdir = vp;
if (fdp->fd_jdir == NULL) {
- VREF(vp);
+ vrefact(vp);
fdp->fd_jdir = vp;
}
FILEDESC_XUNLOCK(fdp);
@@ -3084,17 +3084,17 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp)
continue;
FILEDESC_XLOCK(fdp);
if (fdp->fd_cdir == olddp) {
- vref(newdp);
+ vrefact(newdp);
fdp->fd_cdir = newdp;
nrele++;
}
if (fdp->fd_rdir == olddp) {
- vref(newdp);
+ vrefact(newdp);
fdp->fd_rdir = newdp;
nrele++;
}
if (fdp->fd_jdir == olddp) {
- vref(newdp);
+ vrefact(newdp);
fdp->fd_jdir = newdp;
nrele++;
}
@@ -3103,13 +3103,13 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp)
}
sx_sunlock(&allproc_lock);
if (rootvnode == olddp) {
- vref(newdp);
+ vrefact(newdp);
rootvnode = newdp;
nrele++;
}
mtx_lock(&prison0.pr_mtx);
if (prison0.pr_root == olddp) {
- vref(newdp);
+ vrefact(newdp);
prison0.pr_root = newdp;
nrele++;
}
@@ -3118,7 +3118,7 @@ mountcheckdirs(struct vnode *olddp, struct vnode *newdp)
TAILQ_FOREACH(pr, &allprison, pr_list) {
mtx_lock(&pr->pr_mtx);
if (pr->pr_root == olddp) {
- vref(newdp);
+ vrefact(newdp);
pr->pr_root = newdp;
nrele++;
}
@@ -3445,17 +3445,17 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen,
/* ktrace vnode */
tracevp = p->p_tracevp;
if (tracevp != NULL)
- vref(tracevp);
+ vrefact(tracevp);
/* text vnode */
textvp = p->p_textvp;
if (textvp != NULL)
- vref(textvp);
+ vrefact(textvp);
/* Controlling tty. */
cttyvp = NULL;
if (p->p_pgrp != NULL && p->p_pgrp->pg_session != NULL) {
cttyvp = p->p_pgrp->pg_session->s_ttyvp;
if (cttyvp != NULL)
- vref(cttyvp);
+ vrefact(cttyvp);
}
fdp = fdhold(p);
PROC_UNLOCK(p);
@@ -3479,17 +3479,17 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen,
FILEDESC_SLOCK(fdp);
/* working directory */
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);
}
/* root directory */
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);
}
/* jail directory */
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);
}
for (i = 0; fdp->fd_refcnt > 0 && i <= fdp->fd_lastfile; i++) {
@@ -3579,7 +3579,7 @@ export_vnode_for_osysctl(struct vnode *vp, int type, struct kinfo_file *kif,
{
int error;
- vref(vp);
+ vrefact(vp);
FILEDESC_SUNLOCK(fdp);
export_vnode_to_kinfo(vp, type, 0, kif, KERN_FILEDESC_PACK_KINFO);
kinfo_to_okinfo(kif, okif);
@@ -3706,7 +3706,7 @@ kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen)
if (fdp->fd_cdir == NULL)
error = EINVAL;
else {
- vref(fdp->fd_cdir);
+ vrefact(fdp->fd_cdir);
error = export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD,
FREAD, efbuf);
}
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index b288314..ff1c0a0 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -549,7 +549,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread *
/* Bump references to the text vnode (for procfs). */
if (p2->p_textvp)
- vref(p2->p_textvp);
+ vrefact(p2->p_textvp);
/*
* Set up linkage for kernel based threading.
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index ac46856..efcecaf 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -1122,9 +1122,9 @@ kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, u_int buflen,
fdp = td->td_proc->p_fd;
FILEDESC_SLOCK(fdp);
cdir = fdp->fd_cdir;
- VREF(cdir);
+ vrefact(cdir);
rdir = fdp->fd_rdir;
- VREF(rdir);
+ vrefact(rdir);
FILEDESC_SUNLOCK(fdp);
error = vn_fullpath1(td, cdir, rdir, tmpbuf, &bp, buflen);
vrele(rdir);
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 85c625f..c1ad31e 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -200,7 +200,7 @@ namei_handle_root(struct nameidata *ndp, struct vnode **dpp)
ndp->ni_pathlen--;
}
*dpp = ndp->ni_rootdir;
- VREF(*dpp);
+ vrefact(*dpp);
return (0);
}
@@ -321,7 +321,7 @@ namei(struct nameidata *ndp)
*/
FILEDESC_SLOCK(fdp);
ndp->ni_rootdir = fdp->fd_rdir;
- VREF(ndp->ni_rootdir);
+ vrefact(ndp->ni_rootdir);
ndp->ni_topdir = fdp->fd_jdir;
/*
@@ -343,7 +343,7 @@ namei(struct nameidata *ndp)
startdir_used = 1;
} else if (ndp->ni_dirfd == AT_FDCWD) {
dp = fdp->fd_cdir;
- VREF(dp);
+ vrefact(dp);
} else {
rights = ndp->ni_rightsneeded;
cap_rights_set(&rights, CAP_LOOKUP);
@@ -910,7 +910,7 @@ good:
vput(ndp->ni_dvp);
else
vrele(ndp->ni_dvp);
- vref(vp_crossmp);
+ vrefact(vp_crossmp);
ndp->ni_dvp = vp_crossmp;
error = VFS_ROOT(mp, compute_cn_lkflags(mp, cnp->cn_lkflags,
cnp->cn_flags), &tdp);
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index cf701c6..9ea3318 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -2576,6 +2576,28 @@ vrefl(struct vnode *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.
*
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 0968486..80b93a1 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -754,7 +754,7 @@ sys_fchdir(td, uap)
if (error != 0)
return (error);
vp = fp->f_vnode;
- VREF(vp);
+ vrefact(vp);
fdrop(fp, td);
vn_lock(vp, LK_SHARED | LK_RETRY);
AUDIT_ARG_VNODE1(vp);
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 1f6e384..096806b 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -841,6 +841,7 @@ void vput(struct vnode *vp);
void vrele(struct vnode *vp);
void vref(struct vnode *vp);
void vrefl(struct vnode *vp);
+void vrefact(struct vnode *vp);
int vrefcnt(struct vnode *vp);
void v_addpollinfo(struct vnode *vp);
OpenPOWER on IntegriCloud