The branch stable/14 has been updated by jah:

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

commit 66b8f5484cfe0e37078b8b56355f2fa18b585f88
Author:     Jason A. Harmening <j...@freebsd.org>
AuthorDate: 2023-11-04 16:56:45 +0000
Commit:     Jason A. Harmening <j...@freebsd.org>
CommitDate: 2023-11-12 02:38:26 +0000

    vfs_lookup_cross_mount(): restore previous do...while loop
    
    When the cross-mount walking logic in vfs_lookup() was factored into
    a separate function, the main cross-mount traversal loop was changed
    from a do...while loop conditional on the current vnode having
    VIRF_MOUNTPOINT set to an unconditional for(;;) loop.  For the
    unionfs 'crosslock' case in which the vnode may be re-locked, this
    meant that continuing the loop upon finding inconsistent
    v_mountedhere state would no longer branch to a check that the vnode
    is in fact still a mountpoint.  This would in turn lead to over-
    iteration and, for INVARIANTS builds, a failed assert on the next
    iteration.
    
    Fix this by restoring the previous loop behavior.
    
    Reported by:    pho
    Tested by:      pho
    Fixes:          80bd5ef0702562c546fa1717e8fe221058974eac
    
    (cherry picked from commit 586fed0b03561558644eccc37f824c7110500182)
---
 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 d75351c34314..922adda33b94 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -882,7 +882,7 @@ vfs_lookup_cross_mount(struct nameidata *ndp)
         * The vnode has been mounted on, find the root of the mounted
         * filesystem.
         */
-       for (;;) {
+       do {
                mp = dp->v_mountedhere;
                ASSERT_VOP_LOCKED(dp, __func__);
                VNPASS((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0 && mp != 
NULL, dp);
@@ -915,6 +915,12 @@ vfs_lookup_cross_mount(struct nameidata *ndp)
                                        break;
                                }
                                if (dp->v_mountedhere != mp) {
+                                       /*
+                                        * Note that we rely on the
+                                        * VIRF_MOUNTPOINT loop condition to
+                                        * ensure we stop iterating if dp is
+                                        * no longer a mountpoint at all.
+                                        */
                                        continue;
                                }
                        } else
@@ -939,9 +945,7 @@ vfs_lookup_cross_mount(struct nameidata *ndp)
                if (error != 0)
                        break;
                ndp->ni_vp = dp = tdp;
-               if ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) == 0)
-                       break;
-       }
+       } while ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0);
 
        return (error);
 }

Reply via email to