--- //depot/projects/smpng/sys/kern/vfs_cache.c 2008/08/25 16:33:41 +++ //depot/user/jhb/lock/kern/vfs_cache.c 2008/09/15 22:13:44 @@ -304,7 +309,9 @@ * succeeds, the vnode is returned in *vpp, and a status of -1 is * returned. If the lookup determines that the name does not exist * (negative cacheing), a status of ENOENT is returned. If the lookup - * fails, a status of zero is returned. + * fails, a status of zero is returned. If the directory vnode is + * recycled out from under us due to a forced unmount, a status of + * EBADF is returned. * * vpp is locked and ref'd on return. If we're looking up DOTDOT, dvp is * unlocked. If we're looking up . an extra ref is taken, but the lock is @@ -422,16 +447,24 @@ */ if (dvp == *vpp) { /* lookup on "." */ VREF(*vpp); CACHE_UNLOCK(); /* * When we lookup "." we still can be asked to lock it * differently... */ ltype = cnp->cn_lkflags & LK_TYPE_MASK; - if (ltype == VOP_ISLOCKED(*vpp)) - return (-1); - else if (ltype == LK_EXCLUSIVE) - vn_lock(*vpp, LK_UPGRADE | LK_RETRY); + if (ltype != VOP_ISLOCKED(*vpp)) { + if (ltype == LK_EXCLUSIVE) { + vn_lock(*vpp, LK_UPGRADE | LK_RETRY); + if ((*vpp)->v_iflag & VI_DOOMED) { + /* forced unmount */ + vrele(*vpp); + *vpp = NULL; + return (EBADF); + } + } else + vn_lock(*vpp, LK_DOWNGRADE | LK_RETRY); + } return (-1); } ltype = 0; /* silence gcc warning */ @@ -671,9 +720,9 @@ error = cache_lookup(dvp, vpp, cnp); if (error == 0) return (VOP_CACHEDLOOKUP(dvp, vpp, cnp)); - if (error == ENOENT) - return (error); - return (0); + if (error == -1) + return (0); + return (error); } --- //depot/projects/smpng/sys/kern/vfs_lookup.c 2008/09/17 20:27:47 +++ //depot/user/jhb/lock/kern/vfs_lookup.c 2008/09/18 17:18:53 @@ -430,6 +430,10 @@ ndp->ni_startdir = NULLVP; vn_lock(dp, compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY)); + if (dp->v_iflag & VI_DOOMED) { /* forced unmount */ + error = EBADF; + goto bad; + } dirloop: /* @@ -556,10 +560,6 @@ } if ((dp->v_vflag & VV_ROOT) == 0) break; - if (dp->v_iflag & VI_DOOMED) { /* forced unmount */ - error = EBADF; - goto bad; - } tdp = dp; dp = dp->v_mount->mnt_vnodecovered; tvfslocked = dvfslocked; @@ -570,6 +570,10 @@ vn_lock(dp, compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY)); + if (dp->v_iflag & VI_DOOMED) { /* forced unmount */ + error = EBADF; + goto bad; + } } } @@ -594,8 +598,13 @@ */ if (dp != vp_crossmp && VOP_ISLOCKED(dp) == LK_SHARED && - (cnp->cn_flags & ISLASTCN) && (cnp->cn_flags & LOCKPARENT)) + (cnp->cn_flags & ISLASTCN) && (cnp->cn_flags & LOCKPARENT)) { vn_lock(dp, LK_UPGRADE|LK_RETRY); + if (dp->v_iflag & VI_DOOMED) { /* forced unmount */ + error = EBADF; + goto bad; + } + } /* * If we're looking up the last component and we need an exclusive * lock, adjust our lkflags. @@ -627,6 +636,10 @@ vn_lock(dp, compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY)); + if (dp->v_iflag & VI_DOOMED) { /* forced unmount */ + error = EBADF; + goto bad; + } goto unionlookup; } @@ -804,6 +817,18 @@ if ((cnp->cn_flags & (ISLASTCN | LOCKSHARED | LOCKLEAF)) == (ISLASTCN | LOCKLEAF) && VOP_ISLOCKED(dp) != LK_EXCLUSIVE) { vn_lock(dp, LK_UPGRADE | LK_RETRY); + if (dp->v_iflag & VI_DOOMED) { /* forced unmount */ + error = EBADF; + /* + * XXX: Always bad2? The !wantparent case + * above could have already dropped the + * reference. Perhaps better would be to set + * a flag to indicate if a reference is held + * on the parent dir and to use that at bad2 + * and merge the bad and bad2 labels. + */ + goto bad2; + } } if (vfslocked && dvfslocked) VFS_UNLOCK_GIANT(dvfslocked); /* Only need one */ @@ -850,6 +875,10 @@ dp = dvp; cnp->cn_lkflags = LK_EXCLUSIVE; vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); + if (dp->v_iflag & VI_DOOMED) { /* forced unmount */ + error = EBADF; + goto bad; + } /* * Search a new directory. --- //depot/projects/smpng/sys/nfsclient/nfs_vnops.c 2008/09/17 20:27:47 +++ //depot/user/jhb/lock/nfsclient/nfs_vnops.c 2008/09/18 17:18:53 @@ -868,7 +868,10 @@ *vpp = NULLVP; return (error); } - if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) { + error = cache_lookup(dvp, vpp, cnp); + if (error > 0 && error != ENOENT) + return (error); + if (error == -1) { struct vattr vattr; newvp = *vpp;