diff options
author | kib <kib@FreeBSD.org> | 2012-09-09 19:11:52 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2012-09-09 19:11:52 +0000 |
commit | 01b848f0eebd0e92a90c06e0708aa3d48942ed79 (patch) | |
tree | 7c0e814abcdde22ad04e0810b32053877bb598f2 /sys/kern/vfs_lookup.c | |
parent | 7ea73aa912244bc9fcb5d57cf684c60efcde6401 (diff) | |
download | FreeBSD-src-01b848f0eebd0e92a90c06e0708aa3d48942ed79.zip FreeBSD-src-01b848f0eebd0e92a90c06e0708aa3d48942ed79.tar.gz |
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
Diffstat (limited to 'sys/kern/vfs_lookup.c')
-rw-r--r-- | sys/kern/vfs_lookup.c | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 29ad019..d53dbd0 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"); |