git: 7fd37611b92b - main - null_vptocnp(): busy nullfs mp instead of refing it

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 14 Jun 2022 07:33:22 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=7fd37611b92b5f365f33435bb725b335c2f10ba8

commit 7fd37611b92b5f365f33435bb725b335c2f10ba8
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2022-06-10 11:35:45 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-06-14 07:32:45 +0000

    null_vptocnp(): busy nullfs mp instead of refing it
    
    null_nodeget() needs a valid mount point data, otherwise we might
    race and dereference NULL.
    
    Using MBF_NOWAIT makes non-forced unmount non-transparent for
    vn_fullpath() over nullfs, but we make no guarantee that fullpath
    calculation succeeds anyway.
    
    Reported and tested by: pho
    Reviewed by:    jah
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D35477
---
 sys/fs/nullfs/null_vnops.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c
index e3a320a22bfa..bb18bc8ee55f 100644
--- a/sys/fs/nullfs/null_vnops.c
+++ b/sys/fs/nullfs/null_vnops.c
@@ -989,9 +989,11 @@ null_vptocnp(struct vop_vptocnp_args *ap)
 
 	locked = VOP_ISLOCKED(vp);
 	lvp = NULLVPTOLOWERVP(vp);
-	vhold(lvp);
 	mp = vp->v_mount;
-	vfs_ref(mp);
+	error = vfs_busy(mp, MBF_NOWAIT);
+	if (error != 0)
+		return (error);
+	vhold(lvp);
 	VOP_UNLOCK(vp); /* vp is held by vn_vptocnp_locked that called us */
 	ldvp = lvp;
 	vref(lvp);
@@ -999,7 +1001,7 @@ null_vptocnp(struct vop_vptocnp_args *ap)
 	vdrop(lvp);
 	if (error != 0) {
 		vn_lock(vp, locked | LK_RETRY);
-		vfs_rel(mp);
+		vfs_unbusy(mp);
 		return (ENOENT);
 	}
 
@@ -1007,7 +1009,7 @@ null_vptocnp(struct vop_vptocnp_args *ap)
 	if (error != 0) {
 		vrele(ldvp);
 		vn_lock(vp, locked | LK_RETRY);
-		vfs_rel(mp);
+		vfs_unbusy(mp);
 		return (ENOENT);
 	}
 	error = null_nodeget(mp, ldvp, dvp);
@@ -1018,7 +1020,7 @@ null_vptocnp(struct vop_vptocnp_args *ap)
 		VOP_UNLOCK(*dvp); /* keep reference on *dvp */
 	}
 	vn_lock(vp, locked | LK_RETRY);
-	vfs_rel(mp);
+	vfs_unbusy(mp);
 	return (error);
 }