git: 2e6615b26bb5 - main - netexport: Move struct netexport in a .h file and refcnt it

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Tue, 16 Jun 2026 15:37:10 UTC
The branch main has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=2e6615b26bb51ceadc99121f16856aad9345a3cf

commit 2e6615b26bb51ceadc99121f16856aad9345a3cf
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2026-06-16 15:35:30 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2026-06-16 15:35:30 +0000

    netexport: Move struct netexport in a .h file and refcnt it
    
    This patch moves "struct netexport" into a separate
    netexport.h file and refcounts the structure, plus adds
    a few fields that will be used in a future NFS server
    commit.
    
    The patch also includes some helper functions for
    handling the netextport structure:
    vfs_netexport_alloc(), vfs_netexport_acquire(),
    vfs_netexport_release() and vfs_netexport_reset().
    
    Reviewed by:    kib, markj
    Differential Revision:  https://reviews.freebsd.org/D57553
---
 sys/kern/vfs_export.c | 79 ++++++++++++++++++++++++++++----------------
 sys/kern/vfs_mount.c  |  2 +-
 sys/sys/mount.h       |  2 ++
 sys/sys/netexport.h   | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 145 insertions(+), 29 deletions(-)

diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c
index 566dd3d8770d..6dc4eafc4c60 100644
--- a/sys/kern/vfs_export.c
+++ b/sys/kern/vfs_export.c
@@ -58,6 +58,7 @@
 
 #include <netinet/in.h>
 #include <net/radix.h>
+#include <sys/netexport.h>
 
 #include <rpc/types.h>
 #include <rpc/auth.h>
@@ -72,31 +73,13 @@ static struct radix_node_head *vfs_create_addrlist_af(
 		    struct radix_node_head **prnh, int off);
 #endif
 static int	vfs_free_netcred(struct radix_node *rn, void *w);
+static struct netexport *vfs_netexport_alloc(void);
+static void	vfs_netexport_reset(struct netexport *nep);
 static void	vfs_free_addrlist_af(struct radix_node_head **prnh);
 static int	vfs_hang_addrlist(struct mount *mp, struct netexport *nep,
 		    struct export_args *argp);
 static struct netcred *vfs_export_lookup(struct mount *, struct sockaddr *);
 
-/*
- * Network address lookup element
- */
-struct netcred {
-	struct	radix_node netc_rnodes[2];
-	uint64_t netc_exflags;
-	struct	ucred *netc_anon;
-	int	netc_numsecflavors;
-	int	netc_secflavors[MAXSECFLAVORS];
-};
-
-/*
- * Network export information
- */
-struct netexport {
-	struct	netcred ne_defexported;		      /* Default export */
-	struct 	radix_node_head	*ne4;
-	struct 	radix_node_head	*ne6;
-};
-
 /*
  * Build hash lists of net addresses and hang them off the mount point.
  * Called by vfs_export() to set up the lists of export addresses.
@@ -350,7 +333,7 @@ vfs_export(struct mount *mp, struct export_args *argp, bool do_exjail)
 		}
 		vfs_free_addrlist(nep);
 		mp->mnt_export = NULL;
-		free(nep, M_MOUNT);
+		vfs_netexport_release(nep);
 		nep = NULL;
 		MNT_ILOCK(mp);
 		cr = mp->mnt_exjail;
@@ -369,7 +352,7 @@ vfs_export(struct mount *mp, struct export_args *argp, bool do_exjail)
 			MNT_IUNLOCK(mp);
 			if (do_exjail && nep != NULL) {
 				vfs_free_addrlist(nep);
-				memset(nep, 0, sizeof(*nep));
+				vfs_netexport_reset(nep);
 				new_nep = true;
 			}
 		} else if (mp->mnt_exjail->cr_prison != pr) {
@@ -379,16 +362,14 @@ vfs_export(struct mount *mp, struct export_args *argp, bool do_exjail)
 		} else
 			MNT_IUNLOCK(mp);
 		if (nep == NULL) {
-			nep = malloc(sizeof(struct netexport), M_MOUNT,
-			    M_WAITOK | M_ZERO);
-			mp->mnt_export = nep;
+			nep = mp->mnt_export = vfs_netexport_alloc();
 			new_nep = true;
 		}
 		if (argp->ex_flags & MNT_EXPUBLIC) {
 			if ((error = vfs_setpublicfs(mp, nep, argp)) != 0) {
 				if (new_nep) {
 					mp->mnt_export = NULL;
-					free(nep, M_MOUNT);
+					vfs_netexport_release(nep);
 				}
 				goto out;
 			}
@@ -408,7 +389,7 @@ vfs_export(struct mount *mp, struct export_args *argp, bool do_exjail)
 		if ((error = vfs_hang_addrlist(mp, nep, argp))) {
 			if (new_nep) {
 				mp->mnt_export = NULL;
-				free(nep, M_MOUNT);
+				vfs_netexport_release(nep);
 			}
 			goto out;
 		}
@@ -507,7 +488,7 @@ tryagain:
 				mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED);
 				MNT_IUNLOCK(mp);
 				vfs_free_addrlist(mp->mnt_export);
-				free(mp->mnt_export, M_MOUNT);
+				vfs_netexport_release(mp->mnt_export);
 				mp->mnt_export = NULL;
 			} else
 				MNT_IUNLOCK(mp);
@@ -698,3 +679,45 @@ vfs_stdcheckexp(struct mount *mp, struct sockaddr *nam, uint64_t *extflagsp,
 	lockmgr(&mp->mnt_explock, LK_RELEASE, NULL);
 	return (0);
 }
+
+static struct netexport *
+vfs_netexport_alloc(void)
+{
+	struct netexport *nep;
+
+	nep = malloc(sizeof(struct netexport), M_MOUNT, M_WAITOK | M_ZERO);
+	refcount_init(&nep->ne_ref, 1);
+	mtx_init(&nep->ne_mtx, "mntexplock", NULL, MTX_DEF);
+	return (nep);
+}
+
+static void
+vfs_netexport_reset(struct netexport *nep)
+{
+
+	KASSERT(refcount_load(&nep->ne_ref) > 0,
+	    ("vfs_netexport_reset: invalid refcount"));
+	memset(&nep->ne_startzero, 0, __rangeof(struct netexport, ne_startzero,
+	    ne_endzero));
+}
+
+u_int
+vfs_netexport_acquire(struct netexport *nep)
+{
+
+	KASSERT(refcount_load(&nep->ne_ref) > 0,
+	    ("vfs_netexport_acquire: invalid refcount"));
+	return (refcount_acquire(&nep->ne_ref));
+}
+
+void
+vfs_netexport_release(struct netexport *nep)
+{
+
+	KASSERT(refcount_load(&nep->ne_ref) > 0,
+	    ("vfs_netexport_release: invalid refcount"));
+	if (!refcount_release(&nep->ne_ref))
+		return;
+	mtx_destroy(&nep->ne_mtx);
+	free(nep, M_MOUNT);
+}
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index d7e6683e0446..4d724a0f1c38 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -765,7 +765,7 @@ vfs_mount_destroy(struct mount *mp)
 	}
 	if (mp->mnt_export != NULL) {
 		vfs_free_addrlist(mp->mnt_export);
-		free(mp->mnt_export, M_MOUNT);
+		vfs_netexport_release(mp->mnt_export);
 	}
 	vfsconf_lock();
 	mp->mnt_vfc->vfc_refcount--;
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index fa4c98d93bf8..dc4a49828bbe 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -1061,6 +1061,8 @@ void	vfs_exjail_delete(struct prison *);
 int	vfs_export			 /* process mount export info */
 	    (struct mount *, struct export_args *, bool);
 void	vfs_free_addrlist(struct netexport *);
+u_int	vfs_netexport_acquire(struct netexport *);
+void	vfs_netexport_release(struct netexport *);
 void	vfs_allocate_syncvnode(struct mount *);
 void	vfs_deallocate_syncvnode(struct mount *);
 int	vfs_donmount(struct thread *td, uint64_t fsflags,
diff --git a/sys/sys/netexport.h b/sys/sys/netexport.h
new file mode 100644
index 000000000000..4d0e7f987f93
--- /dev/null
+++ b/sys/sys/netexport.h
@@ -0,0 +1,91 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SYS_NETEXPORT_H_
+#define _SYS_NETEXPORT_H_
+
+/*
+ * This file must be included after net/radix.h so that "struct radix_node"
+ * is defined.
+ */
+#ifdef _KERNEL
+/*
+ * Network address lookup element
+ */
+struct netcred {
+	struct	radix_node netc_rnodes[2];
+	uint64_t netc_exflags;
+	struct	ucred *netc_anon;
+	int	netc_numsecflavors;
+	int	netc_secflavors[MAXSECFLAVORS];
+};
+
+/*
+ * Network export information
+ * ne_defexported - Protected by mnt_explock.
+ * ne4 - Protected by mnt_explock.
+ * ne6 - Protected by mnt_explock.
+ * The following fields are used by the pNFS server's replenisher process.
+ * ne_pnfsnumfile - Protected by the ne_mtx mutex.
+ * ne_pnfsnextfile - Protected by the vnode lock for the numfiles directory.
+ * ne_pnfsnumcnt - Handled as an atomic.
+ *                 (Although this value doesn't need to be exact, so using
+ *                  an atomic is not really necessary.)
+ */
+struct netexport {
+#define	ne_startzero	ne_defexported
+	struct	netcred ne_defexported;		/* Default export */
+	struct 	radix_node_head	*ne4;
+	struct 	radix_node_head	*ne6;
+#define	ne_endzero	ne_mtx
+	struct	mtx ne_mtx;			/* For ne_pnfsnumfile. */
+	struct	vnode *ne_pnfsnumfile;
+	uint64_t ne_pnfsnextfile;
+	u_int	ne_ref;				/* Refcount for structure */
+	u_int	ne_pnfsnumcnt;			/* For stats, not protected. */
+};
+
+#define	MNTEXP_LOCK(n)		mtx_lock(&(n)->ne_mtx)
+#define	MNTEXP_UNLOCK(n)	mtx_unlock(&(n)->ne_mtx)
+#define	MNTEXP_MTX(n)		(&(n)->ne_mtx)
+
+#define	PNFSD_START		((struct vnode *)-1)
+#define	PNFSD_STOP		((struct vnode *)-2)
+#define	PNFSD_STOPPED		((struct vnode *)-3)
+
+#endif	/* _KERNEL */
+
+#endif /* !_SYS_NETEXPORT_H_ */