diff options
Diffstat (limited to 'sys/kern/vfs_lookup.c')
-rw-r--r-- | sys/kern/vfs_lookup.c | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index c4840ce..a21af4f 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -353,6 +353,41 @@ compute_cn_lkflags(struct mount *mp, int lkflags) return (lkflags); } +static __inline int +needs_exclusive_leaf(struct mount *mp, int flags) +{ + + /* + * Intermediate nodes can use shared locks, we only need to + * force an exclusive lock for leaf nodes. + */ + if ((flags & (ISLASTCN | LOCKLEAF)) != (ISLASTCN | LOCKLEAF)) + return (0); + + /* Always use exclusive locks if LOCKSHARED isn't set. */ + if (!(flags & LOCKSHARED)) + return (1); + + /* + * For lookups during open(), if the mount point supports + * extended shared operations, then use a shared lock for the + * leaf node, otherwise use an exclusive lock. + */ + if (flags & ISOPEN) { + if (mp != NULL && + (mp->mnt_kern_flag & MNTK_EXTENDED_SHARED)) + return (0); + else + return (1); + } + + /* + * Lookup requests outside of open() that specify LOCKSHARED + * only need a shared lock on the leaf vnode. + */ + return (1); +} + /* * Search a pathname. * This is a very central and rather complicated routine. @@ -610,8 +645,7 @@ unionlookup: * If we're looking up the last component and we need an exclusive * lock, adjust our lkflags. */ - if ((cnp->cn_flags & (ISLASTCN|LOCKSHARED|LOCKLEAF)) == - (ISLASTCN|LOCKLEAF)) + if (needs_exclusive_leaf(dp->v_mount, cnp->cn_flags)) cnp->cn_lkflags = LK_EXCLUSIVE; #ifdef NAMEI_DIAGNOSTIC vprint("lookup in", dp); @@ -811,8 +845,8 @@ success: * Because of lookup_shared we may have the vnode shared locked, but * the caller may want it to be exclusively locked. */ - if ((cnp->cn_flags & (ISLASTCN | LOCKSHARED | LOCKLEAF)) == - (ISLASTCN | LOCKLEAF) && VOP_ISLOCKED(dp) != LK_EXCLUSIVE) { + if (needs_exclusive_leaf(dp->v_mount, cnp->cn_flags) && + VOP_ISLOCKED(dp) != LK_EXCLUSIVE) { vn_lock(dp, LK_UPGRADE | LK_RETRY); if (dp->v_iflag & VI_DOOMED) { error = ENOENT; |