git: f57ce26f2572 - main - vfs_lookup_cross_mount(): fix missing LK_CANRECURSE

From: Jason A. Harmening <jah_at_FreeBSD.org>
Date: Sun, 13 Sep 2026 03:19:33 UTC
The branch main has been updated by jah:

URL: https://cgit.FreeBSD.org/src/commit/?id=f57ce26f2572efb8adc825ad4efc0e0743a9112f

commit f57ce26f2572efb8adc825ad4efc0e0743a9112f
Author:     Jason A. Harmening <jah@FreeBSD.org>
AuthorDate: 2026-09-07 17:36:20 +0000
Commit:     Jason A. Harmening <jah@FreeBSD.org>
CommitDate: 2026-09-13 03:19:03 +0000

    vfs_lookup_cross_mount(): fix missing LK_CANRECURSE
    
    This was a rather dumb miss on my part in commit 42442d7a6e.
    LK_CANRECURSE is clearly needed in any case in which the covered vnode
    is held exclusive across the call to VFS_ROOT(), regardless of whether
    it was initially held exclusive or upgraded.  The commit message for
    that change also noted that unionfs lookup only worked without
    LK_CANRECURSE due to a coincidence of the then-current unionfs
    implementation.  As it happens, said coincidence was recently removed
    in commit b952606b4f ("unionfs_lock(): eliminate LK_CANRECURSE special-
    case").
    
    PR:             298201
    Reported by:    olivier
    Fixes:          42442d7a6e "Generalize the VV_CROSSLOCK logic in
    vfs_lookup"
    Reviewed by:    kib, markj, pho
    Tested by:      pho
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D59494
---
 sys/kern/vfs_lookup.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 71d4d3f75721..34e9bb47b532 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -983,16 +983,20 @@ vfs_lookup_cross_mount(struct nameidata *ndp)
 			 * We are going to be holding the vnode lock, which
 			 * in this case is shared by the root vnode of the
 			 * filesystem mounted at mp, across the call to
-			 * VFS_ROOT().  Make the situation clear to the
+			 * VFS_ROOT().  Make the situation clear to that
 			 * filesystem by passing LK_CANRECURSE if the
-			 * lock is held exclusive, or by clearinng
-			 * LK_NODDLKTREAT to allow recursion on the shared
-			 * lock in the presence of an exclusive waiter.
+			 * lock is held exclusive, upgrading the lock (and
+			 * passing LK_CANRECURSE) if the lock is held shared
+			 * but mp requires an exclusive lock for lookup,
+			 * or clearing LK_NODDLKTREAT to allow recursion on
+			 * the shared lock in the presence of an exclusive
+			 * waiter.
 			 */
 			if (VOP_ISLOCKED(dp) == LK_EXCLUSIVE) {
 				crosslkflags &= ~LK_SHARED;
 				crosslkflags |= LK_EXCLUSIVE | LK_CANRECURSE;
 			} else if ((crosslkflags & LK_EXCLUSIVE) != 0) {
+				crosslkflags |= LK_CANRECURSE;
 				error = vn_lock(dp, LK_UPGRADE);
 				if (error != 0) {
 					MPASS(error == ENOENT);