diff options
| -rw-r--r-- | sys/kern/vfs_cache.c | 25 | ||||
| -rw-r--r-- | sys/kern/vfs_lookup.c | 9 | ||||
| -rw-r--r-- | sys/sys/namei.h | 1 | ||||
| -rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 43 |
4 files changed, 56 insertions, 22 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 5cc4f1cabefc..976f85e2badf 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -458,18 +458,24 @@ vfs_cache_lookup(ap) vp = *vpp; vpid = vp->v_id; + cnp->cn_flags &= ~PDIRUNLOCK; if (dvp == vp) { /* lookup on "." */ VREF(vp); error = 0; } else if (flags & ISDOTDOT) { VOP_UNLOCK(dvp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; error = vget(vp, LK_EXCLUSIVE, p); - if (!error && lockparent && (flags & ISLASTCN)) - error = vn_lock(dvp, LK_EXCLUSIVE, p); + if (!error && lockparent && (flags & ISLASTCN)) { + if ((error = vn_lock(dvp, LK_EXCLUSIVE, p)) == 0) + cnp->cn_flags &= ~PDIRUNLOCK; + } } else { error = vget(vp, LK_EXCLUSIVE, p); - if (!lockparent || error || !(flags & ISLASTCN)) + if (!lockparent || error || !(flags & ISLASTCN)) { VOP_UNLOCK(dvp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } } /* * Check that the capability number did not change @@ -479,12 +485,17 @@ vfs_cache_lookup(ap) if (vpid == vp->v_id) return (0); vput(vp); - if (lockparent && dvp != vp && (flags & ISLASTCN)) + if (lockparent && dvp != vp && (flags & ISLASTCN)) { VOP_UNLOCK(dvp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } + } + if (cnp->cn_flags & PDIRUNLOCK) { + error = vn_lock(dvp, LK_EXCLUSIVE, p); + if (error) + return (error); + cnp->cn_flags &= ~PDIRUNLOCK; } - error = vn_lock(dvp, LK_EXCLUSIVE, p); - if (error) - return (error); return (VOP_CACHEDLOOKUP(dvp, vpp, cnp)); } diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index c9f43d4873dd..4cd4b013d67a 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -418,6 +418,7 @@ dirloop: unionlookup: ndp->ni_dvp = dp; ndp->ni_vp = NULL; + cnp->cn_flags &= ~PDIRUNLOCK; ASSERT_VOP_LOCKED(dp, "lookup"); if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); @@ -429,7 +430,10 @@ unionlookup: (dp->v_mount->mnt_flag & MNT_UNION)) { tdp = dp; dp = dp->v_mount->mnt_vnodecovered; - vput(tdp); + if (cnp->cn_flags & PDIRUNLOCK) + vrele(tdp); + else + vput(tdp); VREF(dp); vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p); goto unionlookup; @@ -557,7 +561,8 @@ nextname: return (0); bad2: - if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') + if ((cnp->cn_flags & (LOCKPARENT | PDIRUNLOCK)) == LOCKPARENT && + *ndp->ni_next == '\0') VOP_UNLOCK(ndp->ni_dvp, 0, p); vrele(ndp->ni_dvp); bad: diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 84cd2da13abe..22065988ab41 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -140,6 +140,7 @@ struct nameidata { #define DOWHITEOUT 0x040000 /* do whiteouts */ #define WILLBEDIR 0x080000 /* new files will be dirs; allow trailing / */ #define ISUNICODE 0x100000 /* current component name is unicode*/ +#define PDIRUNLOCK 0x200000 /* file system lookup() unlocked parent dir */ #define PARAMASK 0x1fff00 /* mask of parameter descriptors */ /* * Initialization of an nameidata structure. diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index ee28d48dc156..cddd025f5579 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -154,6 +154,7 @@ ufs_lookup(ap) bp = NULL; slotoffset = -1; + cnp->cn_flags &= ~PDIRUNLOCK; /* * XXX there was a soft-update diff about this I couldn't merge. * I think this was the equiv. @@ -395,8 +396,10 @@ notfound: * information cannot be used. */ cnp->cn_flags |= SAVENAME; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (EJUSTRETURN); } /* @@ -460,8 +463,10 @@ found: if (flags & ISDOTDOT) VOP_UNLOCK(vdp, 0, p); /* race to get the inode */ error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); - if (flags & ISDOTDOT) - vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p); + if (flags & ISDOTDOT) { + if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p) != 0) + cnp->cn_flags |= PDIRUNLOCK; + } if (error) return (error); /* @@ -478,8 +483,10 @@ found: return (EPERM); } *vpp = tdp; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (0); } @@ -501,14 +508,18 @@ found: if (flags & ISDOTDOT) VOP_UNLOCK(vdp, 0, p); /* race to get the inode */ error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); - if (flags & ISDOTDOT) - vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p); + if (flags & ISDOTDOT) { + if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p) != 0) + cnp->cn_flags |= PDIRUNLOCK; + } if (error) return (error); *vpp = tdp; cnp->cn_flags |= SAVENAME; - if (!lockparent) + if (!lockparent) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } return (0); } @@ -534,14 +545,18 @@ found: pdp = vdp; if (flags & ISDOTDOT) { VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ + cnp->cn_flags |= PDIRUNLOCK; if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) { - vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p); + if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) + cnp->cn_flags &= ~PDIRUNLOCK; return (error); } - if (lockparent && (flags & ISLASTCN) && - (error = vn_lock(pdp, LK_EXCLUSIVE, p))) { - vput(tdp); - return (error); + if (lockparent && (flags & ISLASTCN)) { + if ((error = vn_lock(pdp, LK_EXCLUSIVE, p)) != 0) { + vput(tdp); + return (error); + } + cnp->cn_flags &= ~PDIRUNLOCK; } *vpp = tdp; } else if (dp->i_number == dp->i_ino) { @@ -551,8 +566,10 @@ found: error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); if (error) return (error); - if (!lockparent || !(flags & ISLASTCN)) + if (!lockparent || !(flags & ISLASTCN)) { VOP_UNLOCK(pdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } *vpp = tdp; } |
