--- sys/fs/nfs/nfs.h.extpg 2026-05-04 15:32:46.705055000 -0700 +++ sys/fs/nfs/nfs.h 2026-05-09 08:41:43.772876000 -0700 @@ -743,6 +743,7 @@ struct nfsrv_descript { #define ND_EXTLSCERTUSER 0x20000000000 #define ND_ERELOOKUP 0x40000000000 #define ND_MACHCRED 0x80000000000 +#define ND_CANEXTPG 0x100000000000 /* * ND_GSS should be the "or" of all GSS type authentications. --- sys/fs/nfsserver/nfs_nfsdport.c.extpg 2026-05-04 18:20:56.764305000 -0700 +++ sys/fs/nfsserver/nfs_nfsdport.c 2026-05-09 14:26:28.074737000 -0700 @@ -2393,12 +2393,13 @@ again: /* * If cnt > MCLBYTES and the reply will not be saved, use - * ext_pgs mbufs for TLS. + * ext_pgs mbufs for TLS or if enabled via vfs.nfsd.enable_mextpg. * For NFSv4.0, we do not know for sure if the reply will * be saved, so do not use ext_pgs mbufs for NFSv4.0. */ if (cnt > MCLBYTES && siz > MCLBYTES && - (nd->nd_flag & (ND_TLS | ND_EXTPG | ND_SAVEREPLY)) == ND_TLS && + ((nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS || + (nd->nd_flag & (ND_CANEXTPG | ND_SAVEREPLY)) == ND_CANEXTPG) && (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4) nd->nd_flag |= ND_EXTPG; @@ -2738,7 +2739,8 @@ ateof: /* * If the reply is likely to exceed MCLBYTES and the reply will - * not be saved, use ext_pgs mbufs for TLS. + * not be saved, use ext_pgs mbufs for TLS or if enabled via + * vfs.nfsd.enable_mextpg. * It is difficult to predict how large each entry will be and * how many entries have been read, so just assume the directory * entries grow by a factor of 4 when attributes are included. @@ -2746,7 +2748,8 @@ ateof: * be saved, so do not use ext_pgs mbufs for NFSv4.0. */ if (cnt > MCLBYTES && siz > MCLBYTES / 4 && - (nd->nd_flag & (ND_TLS | ND_EXTPG | ND_SAVEREPLY)) == ND_TLS && + ((nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS || + (nd->nd_flag & (ND_CANEXTPG | ND_SAVEREPLY)) == ND_CANEXTPG) && (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4) nd->nd_flag |= ND_EXTPG; @@ -7090,13 +7093,14 @@ nfsvno_getxattr(struct vnode *vp, char *name, uint32_t if (tlen > 0) { /* * If cnt > MCLBYTES and the reply will not be saved, use - * ext_pgs mbufs for TLS. + * ext_pgs mbufs for TLS or enabled via vfs.nfsd.enable_mextpg. * For NFSv4.0, we do not know for sure if the reply will * be saved, so do not use ext_pgs mbufs for NFSv4.0. * Always use ext_pgs mbufs if ND_EXTPG is set. */ if ((flag & ND_EXTPG) != 0 || (tlen > MCLBYTES && - (flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS && + ((flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS || + (flag & (ND_CANEXTPG | ND_SAVEREPLY)) == ND_CANEXTPG) && (flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4)) uiop->uio_iovcnt = nfsrv_createiovec_extpgs(tlen, maxextsiz, &m, &m2, &iv); --- sys/fs/nfsserver/nfs_nfsdkrpc.c.extpg 2026-05-09 08:42:48.920437000 -0700 +++ sys/fs/nfsserver/nfs_nfsdkrpc.c 2026-05-15 14:53:38.933917000 -0700 @@ -96,6 +96,10 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_nfsvers, SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_nfsvers, CTLFLAG_VNET | CTLFLAG_RWTUN, &VNET_NAME(nfs_maxvers), 0, "The highest version of NFS handled by the server"); + +static bool nfsrv_mextpg = true; +SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, enable_mextpg, CTLFLAG_RW, + &nfsrv_mextpg, 0, "Enable use of M_EXTPG mbufs"); static int nfs_proc(struct nfsrv_descript *, u_int32_t, SVCXPRT *xprt, struct nfsrvcache **); @@ -315,7 +319,19 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt) if ((xprt->xp_tls & RPCTLS_FLAGS_CERTUSER) != 0) nd.nd_flag |= ND_TLSCERTUSER; } - nd.nd_maxextsiz = 16384; + nd.nd_maxextsiz = MBUF_PEXT_MAX_PGS * PAGE_SIZE; + /* + * If the NIC can handle M_EXTPG mbufs, they can be used + * only if the reply will not be copied into the DRC. + * This implies NFSv3 over TCP and NFSv4.n, but not NFSv4.0. + * (NFSv4.n will set ND_SAVEREPLY if the reply is going + * to be copied into the session slot.) + * Check for TCP transport (UDP uses the DRC) and a direct + * map. + */ + if (nfsrv_mextpg && xprt->xp_extpg && nd.nd_nam2 == NULL && + PMAP_HAS_DMAP != 0) + nd.nd_flag |= ND_CANEXTPG; #ifdef MAC mac_cred_associate_nfsd(nd.nd_cred); #endif --- sys/fs/nfsserver/nfs_nfsdserv.c.extpg 2026-05-05 17:25:40.956237000 -0700 +++ sys/fs/nfsserver/nfs_nfsdserv.c 2026-05-09 14:27:40.677664000 -0700 @@ -1018,13 +1018,16 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is if (cnt > 0) { /* * If cnt > MCLBYTES and the reply will not be saved, use - * ext_pgs mbufs for TLS. + * ext_pgs mbufs for TLS of if enabled via + * vfs.nfsd.enable_mextpg. * For NFSv4.0, we do not know for sure if the reply will * be saved, so do not use ext_pgs mbufs for NFSv4.0. * Always use ext_pgs mbufs if ND_EXTPG is set. */ if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES && - (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS && + ((nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS || + (nd->nd_flag & (ND_CANEXTPG | ND_SAVEREPLY)) == + ND_CANEXTPG) && (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4)) nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, nd->nd_maxextsiz, p, &m3, &m2);