git: cb1ee0c32144 - stable/14 - vfs_lookup_cross_mount(): fix missing LK_CANRECURSE

From: Jason A. Harmening <jah_at_FreeBSD.org>
Date: Mon, 21 Sep 2026 05:11:15 UTC
The branch stable/14 has been updated by jah:

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

commit cb1ee0c3214405331bb8085d3be910d4f560edbc
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-21 05:10:47 +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
    Differential Revision:  https://reviews.freebsd.org/D59494
    
    (cherry picked from commit f57ce26f2572efb8adc825ad4efc0e0743a9112f)
---
 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 1d303fecf493..c0322d59693e 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -941,16 +941,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);