mirror of
https://github.com/opnsense/src.git
synced 2026-06-08 08:12:27 -04:00
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
This commit is contained in:
parent
ebf37c3fed
commit
80bd5ef070
1 changed files with 82 additions and 60 deletions
|
|
@ -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:
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue