summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/vfs_cache.c25
-rw-r--r--sys/kern/vfs_lookup.c9
-rw-r--r--sys/sys/namei.h1
-rw-r--r--sys/ufs/ufs/ufs_lookup.c43
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;
}