summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_lookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/vfs_lookup.c')
-rw-r--r--sys/kern/vfs_lookup.c42
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;
OpenPOWER on IntegriCloud