aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2026-07-12 11:56:13 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2026-07-20 21:55:39 +0000
commit29d1a3248a6da1ed9f1a46d7d525fb779306a90f (patch)
treeb7e51f102f8f02c6d79cf5b72053c85ee31a1db9
parent6ee5895f88ed7ba6b16aae9ad5833df6df6864bc (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.c34
-rw-r--r--sys/kern/vfs_syscalls.c9
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