lookup: do not return vp_crossmp as dvp for mount over the reg file

Return the covered vnode instead.

Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D58191
This commit is contained in:
Konstantin Belousov committed 2026-07-21 00:55:39 +03:00
1 parent 6ee5895f88
commit 29d1a3248a
2 files changed
+38 -5

No files matched your search

+30 -4
View File
@@ -1487,15 +1487,41 @@ nextname:
error = EROFS;
goto bad2;
}
if (!wantparent) {
if (wantparent) {
/*
* Do not return vp_crossmp for the case of mount
* over the regular file. Substitute ni_dvp with the
* covered vnode.
*/
if (ndp->ni_dvp == vp_crossmp &&
(dp->v_vflag & VV_ROOT) != 0 && dp->v_type != VDIR) {
struct vnode *mvp;
vput(ndp->ni_dvp);
mvp = dp->v_mount->mnt_vnodecovered;
vref(mvp);
ndp->ni_dvp = mvp;
if ((cnp->cn_flags & LOCKPARENT) != 0) {
vn_lock_pair(dp, true, VOP_ISLOCKED(dp), mvp,
false, LK_EXCLUSIVE);
if (VN_IS_DOOMED(dp) || VN_IS_DOOMED(mvp)) {
error = ENOENT;
goto bad2;
}
} else {
ni_dvp_unlocked = 1;
}
} else if ((cnp->cn_flags & LOCKPARENT) == 0 &&
ndp->ni_dvp != dp) {
VOP_UNLOCK(ndp->ni_dvp);
ni_dvp_unlocked = 1;
}
} else {
ni_dvp_unlocked = 2;
if (ndp->ni_dvp != dp)
vput(ndp->ni_dvp);
else
vrele(ndp->ni_dvp);
} else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp) {
VOP_UNLOCK(ndp->ni_dvp);
ni_dvp_unlocked = 1;
}
if (cnp->cn_flags & AUDITVNODE1)
+8 -1
View File
@@ -3819,6 +3819,13 @@ again:
}
#endif
fvp = fromnd.ni_vp;
if (fromnd.ni_dvp->v_type != VDIR) {
NDFREE_PNBUF(&fromnd);
vrele(fromnd.ni_dvp);
if (fvp != NULL)
vrele(fromnd.ni_vp);
return (EBUSY);
}
if (exchange && fvp == NULL) {
NDFREE_PNBUF(&fromnd);
vrele(fromnd.ni_dvp);
@@ -3840,7 +3847,7 @@ again:
}
tdvp = tond.ni_dvp;
tvp = tond.ni_vp;
if (tdvp == vp_crossmp) {
if (tdvp->v_type != VDIR) {
/*
* Rename of the root vnode of the mounted
* filesystem. It is possible to get there with the