git: 80bd5ef07025 - main - vfs: factor out mount point traversal to a dedicated routine
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 07 Jul 2023 01:15:47 UTC
The branch main has been updated by mjg: URL: https://cgit.FreeBSD.org/src/commit/?id=80bd5ef0702562c546fa1717e8fe221058974eac commit 80bd5ef0702562c546fa1717e8fe221058974eac Author: Mateusz Guzik <mjg@FreeBSD.org> AuthorDate: 2023-07-05 23:01:17 +0000 Commit: Mateusz Guzik <mjg@FreeBSD.org> 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: /*