Index: sys/kern/vfs_lookup.c =================================================================== --- sys/kern/vfs_lookup.c +++ sys/kern/vfs_lookup.c @@ -276,7 +276,6 @@ ndp->ni_pathlen--; } *dpp = ndp->ni_rootdir; - vrefact(*dpp); return (0); } @@ -396,7 +395,6 @@ */ FILEDESC_SLOCK(fdp); ndp->ni_rootdir = fdp->fd_rdir; - vrefact(ndp->ni_rootdir); ndp->ni_topdir = fdp->fd_jdir; /* @@ -413,14 +411,30 @@ if (cnp->cn_pnbuf[0] == '/') { ndp->ni_resflags |= NIRES_ABS; error = namei_handle_root(ndp, &dp); + if (error == 0) { + vrefactn(dp, 2); + } else { + /* + * Simplify error handling, we should almost never be + * here. + */ + vrefact(ndp->ni_rootdir); + } } else { if (ndp->ni_startdir != NULL) { + vrefact(ndp->ni_rootdir); dp = ndp->ni_startdir; startdir_used = 1; } else if (ndp->ni_dirfd == AT_FDCWD) { dp = fdp->fd_cdir; - vrefact(dp); + if (dp == ndp->ni_rootdir) { + vrefactn(dp, 2); + } else { + vrefact(ndp->ni_rootdir); + vrefact(dp); + } } else { + vrefact(ndp->ni_rootdir); rights = ndp->ni_rightsneeded; cap_rights_set(&rights, CAP_LOOKUP); @@ -570,6 +584,7 @@ error = namei_handle_root(ndp, &dp); if (error != 0) goto out; + vrefact(dp); } } vput(ndp->ni_vp); Index: sys/kern/vfs_subr.c =================================================================== --- sys/kern/vfs_subr.c +++ sys/kern/vfs_subr.c @@ -3047,6 +3047,19 @@ #endif } +void +vrefactn(struct vnode *vp, u_int n) +{ + + CTR2(KTR_VFS, "%s: vp %p", __func__, vp); +#ifdef INVARIANTS + int old = atomic_fetchadd_int(&vp->v_usecount, n); + VNASSERT(old > 0, vp, ("%s: wrong use count %d", __func__, old)); +#else + atomic_add_int(&vp->v_usecount, n); +#endif +} + /* * Return reference count of a vnode. * Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -900,6 +900,7 @@ void vref(struct vnode *vp); void vrefl(struct vnode *vp); void vrefact(struct vnode *vp); +void vrefactn(struct vnode *vp, u_int n); int vrefcnt(struct vnode *vp); void v_addpollinfo(struct vnode *vp);