diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2026-07-12 11:56:13 +0000 |
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2026-07-20 21:55:39 +0000 |
| commit | 29d1a3248a6da1ed9f1a46d7d525fb779306a90f (patch) | |
| tree | b7e51f102f8f02c6d79cf5b72053c85ee31a1db9 | |
| parent | 6ee5895f88ed7ba6b16aae9ad5833df6df6864bc (diff) | |
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
| -rw-r--r-- | sys/kern/vfs_lookup.c | 34 | ||||
| -rw-r--r-- | sys/kern/vfs_syscalls.c | 9 |
2 files changed, 38 insertions, 5 deletions
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 5d66070ca142..57b536eab6ea 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -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) diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 29d503bbb3fa..eeee67418877 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -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 |
