The branch main has been updated by mjg:

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

commit 80bd5ef0702562c546fa1717e8fe221058974eac
Author:     Mateusz Guzik <[email protected]>
AuthorDate: 2023-07-05 23:01:17 +0000
Commit:     Mateusz Guzik <[email protected]>
CommitDate: 2023-07-07 01:15:04 +0000

    vfs: factor out mount point traversal to a dedicated routine
    
    While here tidy up asserts in the area.
    
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D40883
---
 sys/kern/vfs_lookup.c | 142 +++++++++++++++++++++++++++++---------------------
 1 file changed, 82 insertions(+), 60 deletions(-)

diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 5a5560a4c26f..1f62cf3e6652 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -871,6 +871,79 @@ vfs_lookup_failifexists(struct nameidata *ndp)
        return (EEXIST);
 }
 
+static int __noinline
+vfs_lookup_cross_mount(struct nameidata *ndp)
+{
+       struct componentname *cnp;
+       struct mount *mp;
+       struct vnode *dp, *tdp;
+       int error, crosslkflags;
+       bool crosslock;
+
+       cnp = &ndp->ni_cnd;
+       dp = ndp->ni_vp;
+
+       /*
+        * The vnode has been mounted on, find the root of the mounted
+        * filesystem.
+        */
+       for (;;) {
+               mp = dp->v_mountedhere;
+               ASSERT_VOP_LOCKED(dp, __func__);
+               VNPASS((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0 && mp != 
NULL, dp);
+
+               crosslock = (dp->v_vflag & VV_CROSSLOCK) != 0;
+               crosslkflags = enforce_lkflags(mp, cnp->cn_lkflags);
+               if (__predict_false(crosslock)) {
+                       /*
+                        * 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
+                        * 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.
+                        */
+                       if (VOP_ISLOCKED(dp) == LK_EXCLUSIVE) {
+                               crosslkflags &= ~LK_SHARED;
+                               crosslkflags |= LK_EXCLUSIVE | LK_CANRECURSE;
+                       } else if ((crosslkflags & LK_EXCLUSIVE) != 0) {
+                               error = vn_lock(dp, LK_UPGRADE);
+                               if (error != 0)
+                                       break;
+                               if (dp->v_mountedhere != mp) {
+                                       continue;
+                               }
+                       } else
+                               crosslkflags &= ~LK_NODDLKTREAT;
+               }
+               if (vfs_busy(mp, 0) != 0)
+                       continue;
+               if (__predict_true(!crosslock))
+                       vput(dp);
+               if (dp != ndp->ni_dvp)
+                       vput(ndp->ni_dvp);
+               else
+                       vrele(ndp->ni_dvp);
+               vrefact(vp_crossmp);
+               ndp->ni_dvp = vp_crossmp;
+               error = VFS_ROOT(mp, crosslkflags, &tdp);
+               vfs_unbusy(mp);
+               if (__predict_false(crosslock))
+                       vput(dp);
+               if (vn_lock(vp_crossmp, LK_SHARED | LK_NOWAIT))
+                       panic("vp_crossmp exclusively locked or reclaimed");
+               if (error != 0)
+                       break;
+               ndp->ni_vp = dp = tdp;
+               if ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) == 0)
+                       break;
+       }
+
+       return (error);
+}
+
 /*
  * Search a pathname.
  * This is a very central and rather complicated routine.
@@ -919,7 +992,6 @@ vfs_lookup(struct nameidata *ndp)
        char *lastchar;                 /* location of the last character */
        struct vnode *dp = NULL;        /* the directory we are searching */
        struct vnode *tdp;              /* saved dp */
-       struct mount *mp;               /* mount table entry */
        struct prison *pr;
        size_t prev_ni_pathlen;         /* saved ndp->ni_pathlen */
        int docache;                    /* == 0 do not cache last component */
@@ -930,8 +1002,6 @@ vfs_lookup(struct nameidata *ndp)
        struct componentname *cnp = &ndp->ni_cnd;
        int lkflags_save;
        int ni_dvp_unlocked;
-       int crosslkflags;
-       bool crosslock;
 
        /*
         * Setup: break out flag bits into variables.
@@ -1283,66 +1353,18 @@ good:
                        ni_dvp_unlocked = 1;
                }
                goto success;
-       } else if ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0) {
-               if ((cnp->cn_flags & NOCROSSMOUNT) != 0)
-                       goto nextname;
-       } else
-               goto nextname;
+       }
 
-       /*
-        * Check to see if the vnode has been mounted on;
-        * if so find the root of the mounted filesystem.
-        */
-       do {
-               mp = dp->v_mountedhere;
-               KASSERT(mp != NULL,
-                   ("%s: NULL mountpoint for VIRF_MOUNTPOINT vnode", 
__func__));
-               crosslock = (dp->v_vflag & VV_CROSSLOCK) != 0;
-               crosslkflags = enforce_lkflags(mp, cnp->cn_lkflags);
-               if (__predict_false(crosslock)) {
-                       /*
-                        * 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
-                        * 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.
-                        */
-                       if (VOP_ISLOCKED(dp) == LK_EXCLUSIVE) {
-                               crosslkflags &= ~LK_SHARED;
-                               crosslkflags |= LK_EXCLUSIVE | LK_CANRECURSE;
-                       } else if ((crosslkflags & LK_EXCLUSIVE) != 0) {
-                               error = vn_lock(dp, LK_UPGRADE);
-                               if (error != 0)
-                                       goto bad_unlocked;
-                               if (dp->v_mountedhere != mp) {
-                                       continue;
-                               }
-                       } else
-                               crosslkflags &= ~LK_NODDLKTREAT;
-               }
-               if (vfs_busy(mp, 0) != 0)
-                       continue;
-               if (__predict_true(!crosslock))
-                       vput(dp);
-               if (dp != ndp->ni_dvp)
-                       vput(ndp->ni_dvp);
-               else
-                       vrele(ndp->ni_dvp);
-               vrefact(vp_crossmp);
-               ndp->ni_dvp = vp_crossmp;
-               error = VFS_ROOT(mp, crosslkflags, &tdp);
-               vfs_unbusy(mp);
-               if (__predict_false(crosslock))
-                       vput(dp);
-               if (vn_lock(vp_crossmp, LK_SHARED | LK_NOWAIT))
-                       panic("vp_crossmp exclusively locked or reclaimed");
+       if ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0 &&
+           (cnp->cn_flags & NOCROSSMOUNT) == 0) {
+               error = vfs_lookup_cross_mount(ndp);
                if (error != 0)
                        goto bad_unlocked;
-               ndp->ni_vp = dp = tdp;
-       } while ((vn_irflag_read(dp) & VIRF_MOUNTPOINT) != 0);
+               /*
+                * FALLTHROUGH to nextname
+                */
+               dp = ndp->ni_vp;
+       }
 
 nextname:
        /*

Reply via email to