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:
Boris Popov 2000-09-17 07:26:42 +00:00
parent b5a1cc3a5c
commit 3ff1a2f43e
4 changed files with 56 additions and 22 deletions

View File

@ -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));
}

View File

@ -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:

View File

@ -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.

View File

@ -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;
}