Commit 924f4fb0 authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Chuck Lever
Browse files

NFSD: convert write_threads to netlink command



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

Tested-by: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Co-developed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 9077d598
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -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
+20 −0
Original line number Diff line number Diff line
@@ -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 = {
+2 −0
Original line number Diff line number Diff line
@@ -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;

+143 −0
Original line number Diff line number Diff line
@@ -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
+12 −0
Original line number Diff line number Diff line
@@ -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)