git: 29d1a3248a6d - main - lookup: do not return vp_crossmp as dvp for mount over the reg file
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 20 Jul 2026 21:55:46 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=29d1a3248a6da1ed9f1a46d7d525fb779306a90f
commit 29d1a3248a6da1ed9f1a46d7d525fb779306a90f
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-07-12 11:56:13 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-07-20 21:55:39 +0000
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
---
sys/kern/vfs_lookup.c | 34 ++++++++++++++++++++++++++++++----
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