Add new flag PDIRUNLOCK to the component.cn_flags which should be set by
filesystem lookup() routine if it unlocks parent directory. This flag should be carefully tracked by filesystems if they want to work properly with nullfs and other stacked filesystems. VFS takes advantage of this flag to perform symantically correct usage of vrele() instead of vput() if parent directory already unlocked. If filesystem fails to track this flag then previous codepath in VFS left unchanged. Convert UFS code to set PDIRUNLOCK flag if necessary. Other filesystmes will be changed after some period of testing. Reviewed in general by: mckusick, dillon, adrian Obtained from: NetBSD
This commit is contained in:
parent
b5a1cc3a5c
commit
3ff1a2f43e
@ -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));
|
||||
}
|
||||
|
||||
|
@ -418,6 +418,7 @@ lookup(ndp)
|
||||
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 @@ lookup(ndp)
|
||||
(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 @@ lookup(ndp)
|
||||
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:
|
||||
|
@ -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.
|
||||
|
@ -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 @@ ufs_lookup(ap)
|
||||
* 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 @@ ufs_lookup(ap)
|
||||
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 @@ ufs_lookup(ap)
|
||||
return (EPERM);
|
||||
}
|
||||
*vpp = tdp;
|
||||
if (!lockparent)
|
||||
if (!lockparent) {
|
||||
VOP_UNLOCK(vdp, 0, p);
|
||||
cnp->cn_flags |= PDIRUNLOCK;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -501,14 +508,18 @@ ufs_lookup(ap)
|
||||
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 @@ ufs_lookup(ap)
|
||||
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 @@ ufs_lookup(ap)
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user