The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=29d1a3248a6da1ed9f1a46d7d525fb779306a90f

commit 29d1a3248a6da1ed9f1a46d7d525fb779306a90f
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-07-12 11:56:13 +0000
Commit:     Konstantin Belousov <[email protected]>
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

Reply via email to