aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_lookup.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2012-09-09 19:11:52 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2012-09-09 19:11:52 +0000
commit84c3cd4f19940eb09fd22554349e3786958c68f9 (patch)
tree7c0e814abcdde22ad04e0810b32053877bb598f2 /sys/kern/vfs_lookup.c
parent58ecbe49f55d18b7aa6adf3a0932aa4313187164 (diff)
downloadsrc-84c3cd4f19940eb09fd22554349e3786958c68f9.tar.gz
src-84c3cd4f19940eb09fd22554349e3786958c68f9.zip
Add MNTK_LOOKUP_EXCL_DOTDOT struct mount flag, which specifies to the
lookup code that dotdot lookups shall override any shared lock requests with the exclusive one. The flag is useful for filesystems which sometimes need to upgrade shared lock to exclusive inside the VOP_LOOKUP or later, which cannot be done safely for dotdot, due to dvp also locked and causing LOR. In collaboration with: pho MFC after: 3 weeks
Notes
Notes: svn path=/head/; revision=240283
Diffstat (limited to 'sys/kern/vfs_lookup.c')
-rw-r--r--sys/kern/vfs_lookup.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 29ad01943789..d53dbd0bb84c 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -406,11 +406,13 @@ namei(struct nameidata *ndp)
}
static int
-compute_cn_lkflags(struct mount *mp, int lkflags)
+compute_cn_lkflags(struct mount *mp, int lkflags, int cnflags)
{
- if (mp == NULL ||
- ((lkflags & LK_SHARED) && !(mp->mnt_kern_flag & MNTK_LOOKUP_SHARED))) {
+ if (mp == NULL || ((lkflags & LK_SHARED) &&
+ (!(mp->mnt_kern_flag & MNTK_LOOKUP_SHARED) ||
+ ((cnflags & ISDOTDOT) &&
+ (mp->mnt_kern_flag & MNTK_LOOKUP_EXCL_DOTDOT))))) {
lkflags &= ~LK_SHARED;
lkflags |= LK_EXCLUSIVE;
}
@@ -539,7 +541,8 @@ lookup(struct nameidata *ndp)
dp = ndp->ni_startdir;
ndp->ni_startdir = NULLVP;
vn_lock(dp,
- compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY));
+ compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY,
+ cnp->cn_flags));
dirloop:
/*
@@ -700,7 +703,7 @@ dirloop:
VFS_UNLOCK_GIANT(tvfslocked);
vn_lock(dp,
compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags |
- LK_RETRY));
+ LK_RETRY, ISDOTDOT));
}
}
@@ -738,7 +741,8 @@ unionlookup:
vprint("lookup in", dp);
#endif
lkflags_save = cnp->cn_lkflags;
- cnp->cn_lkflags = compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags);
+ cnp->cn_lkflags = compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags,
+ cnp->cn_flags);
if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
cnp->cn_lkflags = lkflags_save;
KASSERT(ndp->ni_vp == NULL, ("leaf should be empty"));
@@ -757,7 +761,7 @@ unionlookup:
VFS_UNLOCK_GIANT(tvfslocked);
vn_lock(dp,
compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags |
- LK_RETRY));
+ LK_RETRY, cnp->cn_flags));
goto unionlookup;
}
@@ -829,8 +833,8 @@ unionlookup:
dvfslocked = 0;
vref(vp_crossmp);
ndp->ni_dvp = vp_crossmp;
- error = VFS_ROOT(mp, compute_cn_lkflags(mp, cnp->cn_lkflags),
- &tdp);
+ error = VFS_ROOT(mp, compute_cn_lkflags(mp, cnp->cn_lkflags,
+ cnp->cn_flags), &tdp);
vfs_unbusy(mp);
if (vn_lock(vp_crossmp, LK_SHARED | LK_NOWAIT))
panic("vp_crossmp exclusively locked or reclaimed");