nfsd: add controls to set the minimum number of threads per pool

Add a new "min_threads" variable to the nfsd_net, along with the
corresponding netlink interface, to set that value from userland.
Pass that value to svc_set_pool_threads() and svc_set_num_threads().

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
Jeff Layton 2026-01-06 13:59:50 -05:00 committed by Chuck Lever
parent 1c87a0c39a
commit d8316b837c
7 changed files with 42 additions and 4 deletions

View file

@ -78,6 +78,9 @@ attribute-sets:
-
name: scope
type: string
-
name: min-threads
type: u32
-
name: version
attributes:
@ -159,6 +162,7 @@ operations:
- gracetime
- leasetime
- scope
- min-threads
-
name: threads-get
doc: get the number of running threads
@ -170,6 +174,7 @@ operations:
- gracetime
- leasetime
- scope
- min-threads
-
name: version-set
doc: set nfs enabled versions

View file

@ -24,11 +24,12 @@ const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
};
/* NFSD_CMD_THREADS_SET - do */
static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_SCOPE + 1] = {
static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_MIN_THREADS + 1] = {
[NFSD_A_SERVER_THREADS] = { .type = NLA_U32, },
[NFSD_A_SERVER_GRACETIME] = { .type = NLA_U32, },
[NFSD_A_SERVER_LEASETIME] = { .type = NLA_U32, },
[NFSD_A_SERVER_SCOPE] = { .type = NLA_NUL_STRING, },
[NFSD_A_SERVER_MIN_THREADS] = { .type = NLA_U32, },
};
/* NFSD_CMD_VERSION_SET - do */
@ -57,7 +58,7 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
.cmd = NFSD_CMD_THREADS_SET,
.doit = nfsd_nl_threads_set_doit,
.policy = nfsd_threads_set_nl_policy,
.maxattr = NFSD_A_SERVER_SCOPE,
.maxattr = NFSD_A_SERVER_MIN_THREADS,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{

View file

@ -129,6 +129,12 @@ struct nfsd_net {
seqlock_t writeverf_lock;
unsigned char writeverf[8];
/*
* Minimum number of threads to run per pool. If 0 then the
* min == max requested number of threads.
*/
unsigned int min_threads;
u32 clientid_base;
u32 clientid_counter;
u32 clverifier_counter;

View file

@ -1642,6 +1642,10 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
scope = nla_data(attr);
}
attr = info->attrs[NFSD_A_SERVER_MIN_THREADS];
if (attr)
nn->min_threads = nla_get_u32(attr);
ret = nfsd_svc(nrpools, nthreads, net, get_current_cred(), scope);
if (ret > 0)
ret = 0;
@ -1681,6 +1685,8 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
nn->nfsd4_grace) ||
nla_put_u32(skb, NFSD_A_SERVER_LEASETIME,
nn->nfsd4_lease) ||
nla_put_u32(skb, NFSD_A_SERVER_MIN_THREADS,
nn->min_threads) ||
nla_put_string(skb, NFSD_A_SERVER_SCOPE,
nn->nfsd_name);
if (err)

View file

@ -690,7 +690,7 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
/* Special case: When n == 1, distribute threads equally among pools. */
if (n == 1)
return svc_set_num_threads(nn->nfsd_serv, 0, nthreads[0]);
return svc_set_num_threads(nn->nfsd_serv, nn->min_threads, nthreads[0]);
if (n > nn->nfsd_serv->sv_nrpools)
n = nn->nfsd_serv->sv_nrpools;
@ -718,7 +718,7 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
for (i = 0; i < n; i++) {
err = svc_set_pool_threads(nn->nfsd_serv,
&nn->nfsd_serv->sv_pools[i],
0, nthreads[i]);
nn->min_threads, nthreads[i]);
if (err)
goto out;
}

View file

@ -2164,6 +2164,25 @@ TRACE_EVENT(nfsd_ctl_maxblksize,
)
);
TRACE_EVENT(nfsd_ctl_minthreads,
TP_PROTO(
const struct net *net,
int minthreads
),
TP_ARGS(net, minthreads),
TP_STRUCT__entry(
__field(unsigned int, netns_ino)
__field(int, minthreads)
),
TP_fast_assign(
__entry->netns_ino = net->ns.inum;
__entry->minthreads = minthreads
),
TP_printk("minthreads=%d",
__entry->minthreads
)
);
TRACE_EVENT(nfsd_ctl_time,
TP_PROTO(
const struct net *net,

View file

@ -35,6 +35,7 @@ enum {
NFSD_A_SERVER_GRACETIME,
NFSD_A_SERVER_LEASETIME,
NFSD_A_SERVER_SCOPE,
NFSD_A_SERVER_MIN_THREADS,
__NFSD_A_SERVER_MAX,
NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1)