git: 02b4a95522c9 - stable/15 - lookup: do not return vp_crossmp as dvp for mount over the reg file

Konstantin Belousov <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a66a5d2.25fde.773837f4__37590.4332775221$1785112111$gmane$org@gitrepo.freebsd.org>
The branch stable/15 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=02b4a95522c9028a47dbe3571563cda72e115875

commit 02b4a95522c9028a47dbe3571563cda72e115875
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-07-12 11:56:13 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2026-07-27 00:26:15 +0000

    lookup: do not return vp_crossmp as dvp for mount over the reg file
    
    (cherry picked from commit 29d1a3248a6da1ed9f1a46d7d525fb779306a90f)
---
 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 addabb45e271..8d1d9cfff8aa 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -1483,15 +1483,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 769ebbcd18dc..a6f513b719ba 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -3821,6 +3821,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);
@@ -3842,7 +3849,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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.