NFSD: convert write_threads to netlink command

Introduce write_threads netlink command similar to the one available
through the procfs.

Tested-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Co-developed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
Lorenzo Bianconi 2024-04-23 15:25:40 +02:00 committed by Chuck Lever
parent 9077d59847
commit 924f4fb003
5 changed files with 216 additions and 0 deletions

View file

@ -62,6 +62,22 @@ attribute-sets:
name: compound-ops
type: u32
multi-attr: true
-
name: server
attributes:
-
name: threads
type: u32
multi-attr: true
-
name: gracetime
type: u32
-
name: leasetime
type: u32
-
name: scope
type: string
operations:
list:
@ -87,3 +103,26 @@ operations:
- sport
- dport
- compound-ops
-
name: threads-set
doc: set the number of running threads
attribute-set: server
flags: [ admin-perm ]
do:
request:
attributes:
- threads
- gracetime
- leasetime
- scope
-
name: threads-get
doc: get the number of running threads
attribute-set: server
do:
reply:
attributes:
- threads
- gracetime
- leasetime
- scope

View file

@ -10,6 +10,14 @@
#include <uapi/linux/nfsd_netlink.h>
/* NFSD_CMD_THREADS_SET - do */
static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_SCOPE + 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, },
};
/* Ops table for nfsd */
static const struct genl_split_ops nfsd_nl_ops[] = {
{
@ -19,6 +27,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
.done = nfsd_nl_rpc_status_get_done,
.flags = GENL_CMD_CAP_DUMP,
},
{
.cmd = NFSD_CMD_THREADS_SET,
.doit = nfsd_nl_threads_set_doit,
.policy = nfsd_threads_set_nl_policy,
.maxattr = NFSD_A_SERVER_SCOPE,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
.cmd = NFSD_CMD_THREADS_GET,
.doit = nfsd_nl_threads_get_doit,
.flags = GENL_CMD_CAP_DO,
},
};
struct genl_family nfsd_nl_family __ro_after_init = {

View file

@ -16,6 +16,8 @@ int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb);
int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
struct netlink_callback *cb);
int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info);
extern struct genl_family nfsd_nl_family;

View file

@ -15,6 +15,7 @@
#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/gss_api.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
#include <linux/sunrpc/svc.h>
#include <linux/module.h>
#include <linux/fsnotify.h>
@ -1653,6 +1654,148 @@ int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb)
return 0;
}
/**
* nfsd_nl_threads_set_doit - set the number of running threads
* @skb: reply buffer
* @info: netlink metadata and command arguments
*
* Return 0 on success or a negative errno.
*/
int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
{
int nthreads = 0, count = 0, nrpools, ret = -EOPNOTSUPP, rem;
struct net *net = genl_info_net(info);
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
const struct nlattr *attr;
const char *scope = NULL;
if (GENL_REQ_ATTR_CHECK(info, NFSD_A_SERVER_THREADS))
return -EINVAL;
/* count number of SERVER_THREADS values */
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
if (nla_type(attr) == NFSD_A_SERVER_THREADS)
count++;
}
mutex_lock(&nfsd_mutex);
nrpools = nfsd_nrpools(net);
if (nrpools && count > nrpools)
count = nrpools;
/* XXX: make this handle non-global pool-modes */
if (count > 1)
goto out_unlock;
nthreads = nla_get_u32(info->attrs[NFSD_A_SERVER_THREADS]);
if (info->attrs[NFSD_A_SERVER_GRACETIME] ||
info->attrs[NFSD_A_SERVER_LEASETIME] ||
info->attrs[NFSD_A_SERVER_SCOPE]) {
ret = -EBUSY;
if (nn->nfsd_serv && nn->nfsd_serv->sv_nrthreads)
goto out_unlock;
ret = -EINVAL;
attr = info->attrs[NFSD_A_SERVER_GRACETIME];
if (attr) {
u32 gracetime = nla_get_u32(attr);
if (gracetime < 10 || gracetime > 3600)
goto out_unlock;
nn->nfsd4_grace = gracetime;
}
attr = info->attrs[NFSD_A_SERVER_LEASETIME];
if (attr) {
u32 leasetime = nla_get_u32(attr);
if (leasetime < 10 || leasetime > 3600)
goto out_unlock;
nn->nfsd4_lease = leasetime;
}
attr = info->attrs[NFSD_A_SERVER_SCOPE];
if (attr)
scope = nla_data(attr);
}
ret = nfsd_svc(nthreads, net, get_current_cred(), scope);
out_unlock:
mutex_unlock(&nfsd_mutex);
return ret == nthreads ? 0 : ret;
}
/**
* nfsd_nl_threads_get_doit - get the number of running threads
* @skb: reply buffer
* @info: netlink metadata and command arguments
*
* Return 0 on success or a negative errno.
*/
int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = genl_info_net(info);
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
void *hdr;
int err;
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb)
return -ENOMEM;
hdr = genlmsg_iput(skb, info);
if (!hdr) {
err = -EMSGSIZE;
goto err_free_msg;
}
mutex_lock(&nfsd_mutex);
err = nla_put_u32(skb, NFSD_A_SERVER_GRACETIME,
nn->nfsd4_grace) ||
nla_put_u32(skb, NFSD_A_SERVER_LEASETIME,
nn->nfsd4_lease) ||
nla_put_string(skb, NFSD_A_SERVER_SCOPE,
nn->nfsd_name);
if (err)
goto err_unlock;
if (nn->nfsd_serv) {
int i;
for (i = 0; i < nfsd_nrpools(net); ++i) {
struct svc_pool *sp = &nn->nfsd_serv->sv_pools[i];
err = nla_put_u32(skb, NFSD_A_SERVER_THREADS,
atomic_read(&sp->sp_nrthreads));
if (err)
goto err_unlock;
}
} else {
err = nla_put_u32(skb, NFSD_A_SERVER_THREADS, 0);
if (err)
goto err_unlock;
}
mutex_unlock(&nfsd_mutex);
genlmsg_end(skb, hdr);
return genlmsg_reply(skb, info);
err_unlock:
mutex_unlock(&nfsd_mutex);
err_free_msg:
nlmsg_free(skb);
return err;
}
/**
* nfsd_net_init - Prepare the nfsd_net portion of a new net namespace
* @net: a freshly-created network namespace

View file

@ -29,8 +29,20 @@ enum {
NFSD_A_RPC_STATUS_MAX = (__NFSD_A_RPC_STATUS_MAX - 1)
};
enum {
NFSD_A_SERVER_THREADS = 1,
NFSD_A_SERVER_GRACETIME,
NFSD_A_SERVER_LEASETIME,
NFSD_A_SERVER_SCOPE,
__NFSD_A_SERVER_MAX,
NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1)
};
enum {
NFSD_CMD_RPC_STATUS_GET = 1,
NFSD_CMD_THREADS_SET,
NFSD_CMD_THREADS_GET,
__NFSD_CMD_MAX,
NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)