diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 18ad471..c8b4d97 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -368,7 +368,7 @@ vfs_busy(struct mount *mp, int flags, struct mtx *interlkp) } if (interlkp) mtx_unlock(interlkp); - lkflags = LK_SHARED | LK_INTERLOCK; + lkflags = LK_SHARED | LK_INTERLOCK | LK_NOWAIT; if (lockmgr(&mp->mnt_lock, lkflags, MNT_MTX(mp))) panic("vfs_busy: unexpected lock failure"); return (0); diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 2301a34..c730781 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -873,6 +873,10 @@ _vn_lock(struct vnode *vp, int flags, char *file, int line) VNASSERT((flags & LK_TYPE_MASK) != 0, vp, ("vn_lock called with no locktype.")); do { +#ifdef DEBUG_VFS_LOCKS + KASSERT(vp->v_holdcnt != 0, + ("vn_lock %p: zero hold count", vp)); +#endif error = VOP_LOCK1(vp, flags, file, line); flags &= ~LK_INTERLOCK; /* Interlock is always dropped. */ KASSERT((flags & LK_RETRY) == 0 || error == 0, diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 7b1af28..38dc2b6 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -361,6 +361,10 @@ ffs_lock(ap) vp = ap->a_vp; flags = ap->a_flags; for (;;) { +#ifdef DEBUG_VFS_LOCKS + KASSERT(vp->v_holdcnt != 0, + ("ffs_lock %p: zero hold count", vp)); +#endif lkp = vp->v_vnlock; result = _lockmgr_args(lkp, flags, VI_MTX(vp), LK_WMESG_DEFAULT, LK_PRIO_DEFAULT, LK_TIMO_DEFAULT, diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index 042ecd0..e345048 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -157,6 +157,7 @@ ufs_lookup(ap) int nameiop = cnp->cn_nameiop; ino_t ino; int ltype; + struct mount *mp; bp = NULL; slotoffset = -1; @@ -578,9 +579,27 @@ found: pdp = vdp; if (flags & ISDOTDOT) { ltype = VOP_ISLOCKED(pdp); + mp = pdp->v_mount; + vhold(pdp); + for (;;) { + error = vfs_busy(mp, LK_NOWAIT, NULL); + if (error == 0) + break; + VOP_UNLOCK(pdp, 0); + pause("ufs_dd", 1); + vn_lock(pdp, ltype | LK_RETRY); + VI_LOCK(pdp); + if (pdp->v_iflag & VI_DOOMED) { + vdropl(pdp); + return (ENOENT); + } + VI_UNLOCK(pdp); + } VOP_UNLOCK(pdp, 0); /* race to get the inode */ - error = VFS_VGET(pdp->v_mount, ino, cnp->cn_lkflags, &tdp); + error = VFS_VGET(mp, ino, cnp->cn_lkflags, &tdp); + vfs_unbusy(mp); vn_lock(pdp, ltype | LK_RETRY); + vdrop(pdp); if (error) return (error); *vpp = tdp;