NFSv4/flexfiles: Add a dataserver_nconnect cap

Data-server clients inherit the MDS nconnect setting.  A striping
mount multiplies that by every distinct data server: at the
anticipated scale of 1024 and nconnect=16 the client opens 16k
sockets plus their sunrpc slot tables, and striping already spreads
I/O across the data servers, so a high per-DS transport count buys
little for that workload.

Add a dataserver_nconnect module parameter to the flexfiles layout
driver alongside its existing dataserver_timeo and dataserver_retrans
knobs, and thread the value through nfs4_pnfs_ds_connect() to both
the v3 and v4 data-server client setup paths.  The default of 0
preserves today's inherit-from-MDS behavior, so the cap is opt-in
and non-regressing.  The files layout passes 0, unchanged.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
This commit is contained in:
Benjamin Coddington 2026-09-15 08:22:26 -04:00 committed by Anna Schumaker
parent bcb2579c9d
commit e0697d5806
7 changed files with 38 additions and 13 deletions

View File

@ -267,7 +267,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
goto out_test_devid;
status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo,
dataserver_retrans, 4,
dataserver_retrans, 0, 4,
s->nfs_client->cl_minorversion, true);
if (status) {
nfs4_mark_deviceid_unavailable(devid);

View File

@ -20,6 +20,7 @@
static unsigned int dataserver_timeo = NFS_DEF_TCP_TIMEO;
static unsigned int dataserver_retrans;
static unsigned int dataserver_nconnect;
static bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg);
@ -418,6 +419,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
*/
status = nfs4_pnfs_ds_connect(s, ds, &mirror_ds->id_node,
dataserver_timeo, dataserver_retrans,
dataserver_nconnect,
mirror_ds->ds_versions[0].version,
mirror_ds->ds_versions[0].minor_version,
mirror_ds->ds_versions[0].tightly_coupled);
@ -676,3 +678,8 @@ module_param(dataserver_timeo, uint, 0644);
MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the "
"NFSv4.1 client waits for a response from a "
" data server before it retries an NFS request.");
module_param(dataserver_nconnect, uint, 0644);
MODULE_PARM_DESC(dataserver_nconnect, "The maximum number of connections "
"the NFSv4.1 client opens to each data server, "
"capping the value inherited from the MDS nconnect "
"mount option. 0 (default) applies no cap.");

View File

@ -251,6 +251,7 @@ extern struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
int ds_addrlen, int ds_proto,
unsigned int ds_timeo,
unsigned int ds_retrans,
unsigned int ds_nconnect,
u32 minor_version,
bool tightly_coupled);
extern struct rpc_clnt *nfs4_find_or_create_ds_client(struct nfs_client *,
@ -260,7 +261,7 @@ extern void nfs4_session_limit_xasize(struct nfs_server *server);
extern struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,
const struct sockaddr_storage *ds_addr, int ds_addrlen,
int ds_proto, unsigned int ds_timeo,
unsigned int ds_retrans);
unsigned int ds_retrans, unsigned int ds_nconnect);
#ifdef CONFIG_PROC_FS
extern int __init nfs_fs_proc_init(void);
extern void nfs_fs_proc_exit(void);

View File

@ -84,7 +84,8 @@ struct nfs_server *nfs3_clone_server(struct nfs_server *source,
*/
struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,
const struct sockaddr_storage *ds_addr, int ds_addrlen,
int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans)
int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans,
unsigned int ds_nconnect)
{
struct rpc_timeout ds_timeout;
unsigned long connect_timeout = ds_timeo * (ds_retrans + 1) * HZ / 10;
@ -124,8 +125,12 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,
fallthrough;
case XPRT_TRANSPORT_RDMA:
case XPRT_TRANSPORT_TCP:
if (mds_clp->cl_nconnect > 1)
if (mds_clp->cl_nconnect > 1) {
cl_init.nconnect = mds_clp->cl_nconnect;
if (ds_nconnect)
cl_init.nconnect = min(cl_init.nconnect,
ds_nconnect);
}
}
if (mds_srv->flags & NFS_MOUNT_NORESVPORT)

View File

@ -794,7 +794,8 @@ static int nfs4_set_client(struct nfs_server *server,
struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
const struct sockaddr_storage *ds_addr, int ds_addrlen,
int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans,
u32 minor_version, bool tightly_coupled)
unsigned int ds_nconnect, u32 minor_version,
bool tightly_coupled)
{
struct rpc_timeout ds_timeout;
struct nfs_client *mds_clp = mds_srv->nfs_client;
@ -832,6 +833,9 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
case XPRT_TRANSPORT_TCP:
if (mds_clp->cl_nconnect > 1) {
cl_init.nconnect = mds_clp->cl_nconnect;
if (ds_nconnect)
cl_init.nconnect = min(cl_init.nconnect,
ds_nconnect);
cl_init.max_connect = NFS_MAX_TRANSPORTS;
}
}

View File

@ -504,7 +504,8 @@ struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(const struct net *net,
void nfs4_pnfs_v3_ds_connect_unload(void);
int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
struct nfs4_deviceid_node *devid, unsigned int timeo,
unsigned int retrans, u32 version, u32 minor_version,
unsigned int retrans, unsigned int nconnect,
u32 version, u32 minor_version,
bool tightly_coupled);
struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net,
struct xdr_stream *xdr,

View File

@ -844,7 +844,8 @@ static struct nfs_client *(*get_v3_ds_connect)(
int ds_addrlen,
int ds_proto,
unsigned int ds_timeo,
unsigned int ds_retrans);
unsigned int ds_retrans,
unsigned int ds_nconnect);
static bool load_v3_ds_connect(void)
{
@ -867,7 +868,8 @@ void nfs4_pnfs_v3_ds_connect_unload(void)
static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
struct nfs4_pnfs_ds *ds,
unsigned int timeo,
unsigned int retrans)
unsigned int retrans,
unsigned int nconnect)
{
struct nfs_client *clp = ERR_PTR(-EIO);
struct nfs_client *mds_clp = mds_srv->nfs_client;
@ -919,7 +921,7 @@ static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
ds_proto = XPRT_TRANSPORT_TCP_TLS;
clp = get_v3_ds_connect(mds_srv, &da->da_addr, da->da_addrlen,
ds_proto, timeo, retrans);
ds_proto, timeo, retrans, nconnect);
if (IS_ERR(clp))
continue;
clp->cl_rpcclient->cl_softerr = 0;
@ -942,6 +944,7 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
struct nfs4_pnfs_ds *ds,
unsigned int timeo,
unsigned int retrans,
unsigned int nconnect,
u32 minor_version,
bool tightly_coupled)
{
@ -1033,7 +1036,8 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
clp = nfs4_set_ds_client(mds_srv, &da->da_addr,
da->da_addrlen, ds_proto,
timeo, retrans, minor_version,
timeo, retrans, nconnect,
minor_version,
tightly_coupled);
if (IS_ERR(clp))
continue;
@ -1068,7 +1072,8 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
*/
int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
struct nfs4_deviceid_node *devid, unsigned int timeo,
unsigned int retrans, u32 version, u32 minor_version,
unsigned int retrans, unsigned int nconnect,
u32 version, u32 minor_version,
bool tightly_coupled)
{
int err;
@ -1088,11 +1093,13 @@ int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
switch (version) {
case 3:
err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo, retrans);
err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo, retrans,
nconnect);
break;
case 4:
err = _nfs4_pnfs_v4_ds_connect(mds_srv, ds, timeo, retrans,
minor_version, tightly_coupled);
nconnect, minor_version,
tightly_coupled);
break;
default:
dprintk("%s: unsupported DS version %d\n", __func__, version);