convert write_threads, write_version and write_ports to netlink commands
Subsystems (5)
v5 cover convert write_threads, write_version and write_ports to netlink commands
Introduce write_threads, write_version and write_ports netlink commands similar to the ones available through the procfs.
Changes since v4:
- rebase on top of nfsd-next tree
Changes since v3:
- drop write_maxconn and write_maxblksize for the moment
- add write_version and write_ports commands Changes since v2:
- use u32 to store nthreads in nfsd_nl_threads_set_doit
- rename server-attr in control-plane in nfsd.yaml specs Changes since v1:
- remove write_v4_end_grace command
- add write_maxblksize and write_maxconn netlink commands
This patch can be tested with user-space tool reported below:
https://github.com/LorenzoBianconi/nfsd-netlink.git
Lorenzo Bianconi (3):
NFSD: convert write_threads to netlink command
NFSD: convert write_version to netlink command
NFSD: convert write_ports to netlink command
Documentation/netlink/specs/nfsd.yaml | 83 ++++++++ fs/nfsd/netlink.c | 54 ++++++ fs/nfsd/netlink.h | 8 + fs/nfsd/nfsctl.c | 267 +++++++++++++++++++++++++- include/uapi/linux/nfsd_netlink.h | 30 +++ tools/net/ynl/generated/nfsd-user.c | 254 ++++++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 156 +++++++++++++++ 7 files changed, 845 insertions(+), 7 deletions(-)
Signature · 1 line
2.43.0
PATCH v5 1/3 NFSD: convert write_threads to netlink command
Introduce write_threads netlink command similar to the ones available through the procfs.
--- Documentation/netlink/specs/nfsd.yaml | 23 +++++++ fs/nfsd/netlink.c | 17 +++++ fs/nfsd/netlink.h | 2 + fs/nfsd/nfsctl.c | 58 +++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 9 +++ tools/net/ynl/generated/nfsd-user.c | 92 +++++++++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 47 ++++++++++++++ 7 files changed, 248 insertions(+)
Documentation/netlink/specs/nfsd.yaml +23 -0
@@ -62,6 +62,12 @@ attribute-sets: name: compound-ops type: u32 multi-attr: true + - + name: server-worker + attributes: + - + name: threads + type: u32 operations: list:
@@ -87,3 +93,20 @@ operations: - sport - dport - compound-ops + - + name: threads-set + doc: set the number of running threads + attribute-set: server-worker + flags: [ admin-perm ] + do: + request: + attributes: + - threads + - + name: threads-get + doc: get the number of running threads + attribute-set: server-worker + do: + reply: + attributes: + - threads
fs/nfsd/netlink.c +17 -0
@@ -10,6 +10,11 @@#include <uapi/linux/nfsd_netlink.h> +/* NFSD_CMD_THREADS_SET - do */ +static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_THREADS +1 ] = { + [NFSD_A_SERVER_WORKER_THREADS ] = { .type =NLA_U32 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {
@@ -19,6 +24,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_WORKER_THREADS, + .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 = {
fs/nfsd/netlink.h +2 -0
@@ -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;
fs/nfsd/nfsctl.c +58 -0
64 lines not on this page · raw message
include/uapi/linux/nfsd_netlink.h +9 -0
@@ -29,8 +29,17 @@ enum {NFSD_A_RPC_STATUS_MAX = (__NFSD_A_RPC_STATUS_MAX -1 ) }; +enum { +NFSD_A_SERVER_WORKER_THREADS =1 , + + __NFSD_A_SERVER_WORKER_MAX, +NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_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 )
tools/net/ynl/generated/nfsd-user.c +92 -0
110 lines not on this page · raw message
tools/net/ynl/generated/nfsd-user.h +47 -0
51 lines not on this page · raw message
Signature · 1 line
2.43.0
Re: [PATCH v5 1/3] NFSD: convert write_threads to netlink command
Quoted 354 lines · Lorenzo Bianconi
Introduce
write_threadsnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 23 +++++++ fs/nfsd/netlink.c | 17 +++++ fs/nfsd/netlink.h | 2 + fs/nfsd/nfsctl.c | 58 +++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 9 +++ tools/net/ynl/generated/nfsd-user.c | 92 +++++++++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 47 ++++++++++++++ 7 files changed, 248 insertions(+)Documentation/netlink/specs/nfsd.yaml +23
-0@@ -62,6 +62,12 @@ attribute-sets: name: compound-ops type: u32 multi-attr: true + - + name: server-worker + attributes: + - + name: threads + type: u32 operations: list:@@ -87,3 +93,20 @@ operations: - sport - dport - compound-ops + - + name: threads-set + doc: set the number of running threads + attribute-set: server-worker + flags: [ admin-perm ] + do: + request: + attributes: + - threads + - + name: threads-get + doc: get the number of running threads + attribute-set: server-worker + do: + reply: + attributes: + - threadsfs/nfsd/netlink.c +17
-0@@ -10,6 +10,11 @@#include <uapi/linux/nfsd_netlink.h> +/* NFSD_CMD_THREADS_SET - do */ +static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_THREADS +1 ] = { + [NFSD_A_SERVER_WORKER_THREADS ] = { .type =NLA_U32 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -19,6 +24,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_WORKER_THREADS, + .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 = {fs/nfsd/netlink.h +2
-0@@ -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;fs/nfsd/nfsctl.c +58
-0@@ -1699,6 +1699,64 @@ 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) +{ +u32 nthreads; +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_WORKER_THREADS )) +return -EINVAL ; + + nthreads =nla_get_u32 (info->attrs[NFSD_A_SERVER_WORKER_THREADS ]); + ret =nfsd_svc (nthreads,genl_info_net (info),get_current_cred ()); + +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) +{ +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; + } + +if (nla_put_u32 (skb,NFSD_A_SERVER_WORKER_THREADS , +nfsd_nrthreads (genl_info_net (info)))) { + err = -EINVAL ; + goto err_free_msg; + } + +genlmsg_end (skb, hdr); + +return genlmsg_reply (skb, info); + +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 include/uapi/linux/nfsd_netlink.h +9
-0@@ -29,8 +29,17 @@ enum {NFSD_A_RPC_STATUS_MAX = (__NFSD_A_RPC_STATUS_MAX -1 ) }; +enum { +NFSD_A_SERVER_WORKER_THREADS =1 , + + __NFSD_A_SERVER_WORKER_MAX, +NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_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 )tools/net/ynl/generated/nfsd-user.c +92
-0@@ -15,6 +15,8 @@/* Enums */ static const char *const nfsd_op_strmap[] = { [NFSD_CMD_RPC_STATUS_GET ] ="rpc-status-get" , + [NFSD_CMD_THREADS_SET ] ="threads-set" , + [NFSD_CMD_THREADS_GET ] ="threads-get" , };const char *nfsd_op_str (int op)@@ -47,6 +49,15 @@ struct ynl_policy_nest nfsd_rpc_status_nest = { .table = nfsd_rpc_status_policy, }; +struct ynl_policy_attr nfsd_server_worker_policy[NFSD_A_SERVER_WORKER_MAX +1 ] = { + [NFSD_A_SERVER_WORKER_THREADS ] = { .name ="threads" , .type =YNL_PT_U32 , }, +}; + +struct ynl_policy_nest nfsd_server_worker_nest = { + .max_attr =NFSD_A_SERVER_WORKER_MAX , + .table = nfsd_server_worker_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -198,6 +209,87 @@ nfsd_rpc_status_get_dump(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_THREADS_SET ============== */ +/* NFSD_CMD_THREADS_SET - do */ +void nfsd_threads_set_req_free (struct nfsd_threads_set_req *req) +{ +free (req); +} + +int nfsd_threads_set (struct ynl_sock *ys,struct nfsd_threads_set_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_THREADS_SET ,1 ); + ys->req_policy = &nfsd_server_worker_nest; + +if (req->_present.threads) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_WORKER_THREADS , req->threads); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_THREADS_GET ============== */ +/* NFSD_CMD_THREADS_GET - do */ +void nfsd_threads_get_rsp_free (struct nfsd_threads_get_rsp *rsp) +{ +free (rsp); +} + +int nfsd_threads_get_rsp_parse (const struct nlmsghdr *nlh,void *data) +{ +struct ynl_parse_arg *yarg = data; +struct nfsd_threads_get_rsp *dst; +const struct nlattr *attr; + + dst = yarg->data; + +mnl_attr_for_each (attr, nlh,sizeof (struct genlmsghdr )) { +unsigned int type =mnl_attr_get_type (attr); + +if (type ==NFSD_A_SERVER_WORKER_THREADS ) { +if (ynl_attr_validate (yarg, attr)) +return MNL_CB_ERROR ; + dst->_present.threads =1 ; + dst->threads =mnl_attr_get_u32 (attr); + } + } + +return MNL_CB_OK ; +} + +struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys) +{ +struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; +struct nfsd_threads_get_rsp *rsp; +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_THREADS_GET ,1 ); + ys->req_policy = &nfsd_server_worker_nest; + yrs.yarg.rsp_policy = &nfsd_server_worker_nest; + + rsp =calloc (1 ,sizeof (*rsp)); + yrs.yarg.data = rsp; + yrs.cb = nfsd_threads_get_rsp_parse; + yrs.rsp_cmd =NFSD_CMD_THREADS_GET ; + + err =ynl_exec (ys, nlh, &yrs); +if (err <0 ) + goto err_free; + +return rsp; + +err_free: +nfsd_threads_get_rsp_free (rsp); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +38
-0@@ -64,4 +64,51 @@ nfsd_rpc_status_get_rsp_list_free(struct nfsd_rpc_status_get_rsp_list *rsp);struct nfsd_rpc_status_get_rsp_list *nfsd_rpc_status_get_dump (struct ynl_sock *ys); +/* ============== NFSD_CMD_THREADS_SET ============== */ +/* NFSD_CMD_THREADS_SET - do */ +struct nfsd_threads_set_req { +struct { +__u32 threads:1 ; + } _present; + +__u32 threads; +}; + +static inline struct nfsd_threads_set_req *nfsd_threads_set_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_threads_set_req )); +} +void nfsd_threads_set_req_free (struct nfsd_threads_set_req *req); + +static inline void +nfsd_threads_set_req_set_threads (struct nfsd_threads_set_req *req, +__u32 threads) +{ + req->_present.threads =1 ; + req->threads = threads; +} + +/* +* set the number of running threads +*/ +int nfsd_threads_set (struct ynl_sock *ys,struct nfsd_threads_set_req *req); + +/* ============== NFSD_CMD_THREADS_GET ============== */ +/* NFSD_CMD_THREADS_GET - do */ + +struct nfsd_threads_get_rsp { +struct { +__u32 threads:1 ; + } _present; + +__u32 threads;
tools/net/ynl/generated/nfsd-user.h nfsd_rpc_status_get_rsp_list_free(struct nfsd_rpc_status_get_rsp_list *rsp); · line 114
Quoted 10 lines
tools/net/ynl/generated/nfsd-user.h +9
-0+}; + +void nfsd_threads_get_rsp_free (struct nfsd_threads_get_rsp *rsp); + +/* +* get the number of running threads +*/ +struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */
Ok, Uncle! I'll relent on the quest for a single netlink command to start the server. This patch looks reasonable to me.
Re: [PATCH v5 1/3] NFSD: convert write_threads to netlink command
Quoted 360 lines · Jeff Layton
Quoted 359 lines · Lorenzo Bianconi
Introduce
write_threadsnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 23 +++++++ fs/nfsd/netlink.c | 17 +++++ fs/nfsd/netlink.h | 2 + fs/nfsd/nfsctl.c | 58 +++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 9 +++ tools/net/ynl/generated/nfsd-user.c | 92 +++++++++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 47 ++++++++++++++ 7 files changed, 248 insertions(+)Documentation/netlink/specs/nfsd.yaml +23
-0@@ -62,6 +62,12 @@ attribute-sets: name: compound-ops type: u32 multi-attr: true + - + name: server-worker + attributes: + - + name: threads + type: u32 operations: list:@@ -87,3 +93,20 @@ operations: - sport - dport - compound-ops + - + name: threads-set + doc: set the number of running threads + attribute-set: server-worker + flags: [ admin-perm ] + do: + request: + attributes: + - threads + - + name: threads-get + doc: get the number of running threads + attribute-set: server-worker + do: + reply: + attributes: + - threadsfs/nfsd/netlink.c +17
-0@@ -10,6 +10,11 @@#include <uapi/linux/nfsd_netlink.h> +/* NFSD_CMD_THREADS_SET - do */ +static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_THREADS +1 ] = { + [NFSD_A_SERVER_WORKER_THREADS ] = { .type =NLA_U32 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -19,6 +24,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_WORKER_THREADS, + .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 = {fs/nfsd/netlink.h +2
-0@@ -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;fs/nfsd/nfsctl.c +58
-0@@ -1699,6 +1699,64 @@ 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) +{ +u32 nthreads; +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_WORKER_THREADS )) +return -EINVAL ; + + nthreads =nla_get_u32 (info->attrs[NFSD_A_SERVER_WORKER_THREADS ]); + ret =nfsd_svc (nthreads,genl_info_net (info),get_current_cred ()); + +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) +{ +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; + } + +if (nla_put_u32 (skb,NFSD_A_SERVER_WORKER_THREADS , +nfsd_nrthreads (genl_info_net (info)))) { + err = -EINVAL ; + goto err_free_msg; + } + +genlmsg_end (skb, hdr); + +return genlmsg_reply (skb, info); + +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 include/uapi/linux/nfsd_netlink.h +9
-0@@ -29,8 +29,17 @@ enum {NFSD_A_RPC_STATUS_MAX = (__NFSD_A_RPC_STATUS_MAX -1 ) }; +enum { +NFSD_A_SERVER_WORKER_THREADS =1 , + + __NFSD_A_SERVER_WORKER_MAX, +NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_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 )tools/net/ynl/generated/nfsd-user.c +92
-0@@ -15,6 +15,8 @@/* Enums */ static const char *const nfsd_op_strmap[] = { [NFSD_CMD_RPC_STATUS_GET ] ="rpc-status-get" , + [NFSD_CMD_THREADS_SET ] ="threads-set" , + [NFSD_CMD_THREADS_GET ] ="threads-get" , };const char *nfsd_op_str (int op)@@ -47,6 +49,15 @@ struct ynl_policy_nest nfsd_rpc_status_nest = { .table = nfsd_rpc_status_policy, }; +struct ynl_policy_attr nfsd_server_worker_policy[NFSD_A_SERVER_WORKER_MAX +1 ] = { + [NFSD_A_SERVER_WORKER_THREADS ] = { .name ="threads" , .type =YNL_PT_U32 , }, +}; + +struct ynl_policy_nest nfsd_server_worker_nest = { + .max_attr =NFSD_A_SERVER_WORKER_MAX , + .table = nfsd_server_worker_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -198,6 +209,87 @@ nfsd_rpc_status_get_dump(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_THREADS_SET ============== */ +/* NFSD_CMD_THREADS_SET - do */ +void nfsd_threads_set_req_free (struct nfsd_threads_set_req *req) +{ +free (req); +} + +int nfsd_threads_set (struct ynl_sock *ys,struct nfsd_threads_set_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_THREADS_SET ,1 ); + ys->req_policy = &nfsd_server_worker_nest; + +if (req->_present.threads) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_WORKER_THREADS , req->threads); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_THREADS_GET ============== */ +/* NFSD_CMD_THREADS_GET - do */ +void nfsd_threads_get_rsp_free (struct nfsd_threads_get_rsp *rsp) +{ +free (rsp); +} + +int nfsd_threads_get_rsp_parse (const struct nlmsghdr *nlh,void *data) +{ +struct ynl_parse_arg *yarg = data; +struct nfsd_threads_get_rsp *dst; +const struct nlattr *attr; + + dst = yarg->data; + +mnl_attr_for_each (attr, nlh,sizeof (struct genlmsghdr )) { +unsigned int type =mnl_attr_get_type (attr); + +if (type ==NFSD_A_SERVER_WORKER_THREADS ) { +if (ynl_attr_validate (yarg, attr)) +return MNL_CB_ERROR ; + dst->_present.threads =1 ; + dst->threads =mnl_attr_get_u32 (attr); + } + } + +return MNL_CB_OK ; +} + +struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys) +{ +struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; +struct nfsd_threads_get_rsp *rsp; +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_THREADS_GET ,1 ); + ys->req_policy = &nfsd_server_worker_nest; + yrs.yarg.rsp_policy = &nfsd_server_worker_nest; + + rsp =calloc (1 ,sizeof (*rsp)); + yrs.yarg.data = rsp; + yrs.cb = nfsd_threads_get_rsp_parse; + yrs.rsp_cmd =NFSD_CMD_THREADS_GET ; + + err =ynl_exec (ys, nlh, &yrs); +if (err <0 ) + goto err_free; + +return rsp; + +err_free: +nfsd_threads_get_rsp_free (rsp); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +43
-0@@ -64,4 +64,51 @@ nfsd_rpc_status_get_rsp_list_free(struct nfsd_rpc_status_get_rsp_list *rsp);struct nfsd_rpc_status_get_rsp_list *nfsd_rpc_status_get_dump (struct ynl_sock *ys); +/* ============== NFSD_CMD_THREADS_SET ============== */ +/* NFSD_CMD_THREADS_SET - do */ +struct nfsd_threads_set_req { +struct { +__u32 threads:1 ; + } _present; + +__u32 threads; +}; + +static inline struct nfsd_threads_set_req *nfsd_threads_set_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_threads_set_req )); +} +void nfsd_threads_set_req_free (struct nfsd_threads_set_req *req); + +static inline void +nfsd_threads_set_req_set_threads (struct nfsd_threads_set_req *req, +__u32 threads) +{ + req->_present.threads =1 ; + req->threads = threads; +} + +/* +* set the number of running threads +*/ +int nfsd_threads_set (struct ynl_sock *ys,struct nfsd_threads_set_req *req); + +/* ============== NFSD_CMD_THREADS_GET ============== */ +/* NFSD_CMD_THREADS_GET - do */ + +struct nfsd_threads_get_rsp { +struct { +__u32 threads:1 ; + } _present; + +__u32 threads; +}; + +void nfsd_threads_get_rsp_free (struct nfsd_threads_get_rsp *rsp); + +/*
Quoted 8 lines
tools/net/ynl/generated/nfsd-user.h nfsd_rpc_status_get_rsp_list_free(struct nfsd_rpc_status_get_rsp_list *rsp); · line 114
Quoted 5 lines
tools/net/ynl/generated/nfsd-user.h +4
-0+* get the number of running threads +*/ +struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */ Ok, Uncle! I'll relent on the quest for a single netlink command to start the server.
I think we can consider a single config/start-up command, but I don't feel it has to happen as part of this series, unless I'm missing something critical. It seems like a declarative mechanism would need some deeper changes in NFSD.
Quoted 3 lines
This patch looks reasonable to me.
Reviewed-by Jeff Layton <[email protected]>
Thanks, Jeff!
Before applying these, I'd like an Acked-by from Jakub for the tools/net/ynl modifications, and at least a fresh sanity check from Jakub on the changes to the nfsd netlink protocol (though I don't anything problematic so far).
Signature · 1 line
Chuck Lever
Jakub Kicinski
maintainerRe: [PATCH v5 1/3] NFSD: convert write_threads to netlink command
Quoted 4 lines · On Wed, 29 Nov 2023 13:31:17 -0500 Chuck Lever wrote:
Before applying these, I'd like an Acked-by from Jakub for the
tools/net/ynlmodifications, and at least a fresh sanity check from Jakub on the changes to the nfsd netlink protocol (though I don't anything problematic so far).
I left a couple of suggestions, looks good overall.
PATCH v5 2/3 NFSD: convert write_version to netlink command
In reply to Lorenzo BianconiIntroduce write_version netlink command similar to the ones available through the procfs.
--- Documentation/netlink/specs/nfsd.yaml | 32 ++++++++ fs/nfsd/netlink.c | 19 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 105 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 11 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 55 ++++++++++++++ 7 files changed, 306 insertions(+)
Documentation/netlink/specs/nfsd.yaml +32 -0
@@ -68,6 +68,18 @@ attribute-sets: - name: threads type: u32 + - + name: server-version + attributes: + - + name: major + type: u32 + - + name: minor + type: u32 + - + name: status + type: u8 operations: list:
@@ -110,3 +122,23 @@ operations: reply: attributes: - threads + - + name: version-set + doc: enable/disable server version + attribute-set: server-version + flags: [ admin-perm ] + do: + request: + attributes: + - major + - minor + - status + - + name: version-get + doc: dump server versions + attribute-set: server-version + dump: + reply: + attributes: + - major + - minor
fs/nfsd/netlink.c +19 -0
@@ -15,6 +15,13 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_T [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, }; +/* NFSD_CMD_VERSION_SET - do */ +static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_STATUS +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .type =NLA_U8 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {
@@ -36,6 +43,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_threads_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_VERSION_SET, + .doit = nfsd_nl_version_set_doit, + .policy = nfsd_version_set_nl_policy, + .maxattr = NFSD_A_SERVER_VERSION_STATUS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_VERSION_GET, + .dumpit = nfsd_nl_version_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {
fs/nfsd/netlink.h +3 -0
@@ -18,6 +18,9 @@ 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); +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;
fs/nfsd/nfsctl.c +105 -0
111 lines not on this page · raw message
include/uapi/linux/nfsd_netlink.h +11 -0
@@ -36,10 +36,21 @@ enum {NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX -1 ) }; +enum { +NFSD_A_SERVER_VERSION_MAJOR =1 , +NFSD_A_SERVER_VERSION_MINOR , +NFSD_A_SERVER_VERSION_STATUS , + + __NFSD_A_SERVER_VERSION_MAX, +NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET , +NFSD_CMD_VERSION_SET , +NFSD_CMD_VERSION_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )
tools/net/ynl/generated/nfsd-user.c +81 -0
99 lines not on this page · raw message
tools/net/ynl/generated/nfsd-user.h +55 -0
59 lines not on this page · raw message
Signature · 1 line
2.43.0
Jeff Layton
maintainerRe: [PATCH v5 2/3] NFSD: convert write_version to netlink command
Quoted 372 lines · Lorenzo Bianconi
Introduce
write_versionnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 32 ++++++++ fs/nfsd/netlink.c | 19 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 105 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 11 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 55 ++++++++++++++ 7 files changed, 306 insertions(+)Documentation/netlink/specs/nfsd.yaml +32
-0@@ -68,6 +68,18 @@ attribute-sets: - name: threads type: u32 + - + name: server-version + attributes: + - + name: major + type: u32 + - + name: minor + type: u32 + - + name: status + type: u8 operations: list:@@ -110,3 +122,23 @@ operations: reply: attributes: - threads + - + name: version-set + doc: enable/disable server version + attribute-set: server-version + flags: [ admin-perm ] + do: + request: + attributes: + - major + - minor + - status + - + name: version-get + doc: dump server versions + attribute-set: server-version + dump: + reply: + attributes: + - major + - minorfs/nfsd/netlink.c +19
-0@@ -15,6 +15,13 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_T [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, }; +/* NFSD_CMD_VERSION_SET - do */ +static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_STATUS +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .type =NLA_U8 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -36,6 +43,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_threads_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_VERSION_SET, + .doit = nfsd_nl_version_set_doit, + .policy = nfsd_version_set_nl_policy, + .maxattr = NFSD_A_SERVER_VERSION_STATUS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_VERSION_GET, + .dumpit = nfsd_nl_version_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {fs/nfsd/netlink.h +3
-0@@ -18,6 +18,9 @@ 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); +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;fs/nfsd/nfsctl.c +105
-0@@ -1757,6 +1757,111 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)return err; } +/** +* nfsd_nl_version_set_doit - enable/disable the provided nfs server version +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info) +{ +struct nfsd_net *nn =net_generic (genl_info_net (info), nfsd_net_id); +enum vers_op cmd; +u32 major, minor; +u8 status; +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MAJOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MINOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_STATUS )) +return -EINVAL ; + + major =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MAJOR ]); + minor =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MINOR ]); + + status =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_STATUS ]); + cmd = !!status ?NFSD_SET :NFSD_CLEAR ; + +mutex_lock (&nfsd_mutex); +switch (major) { +case 4 : + ret =nfsd_minorversion (nn, minor, cmd); +break ; +case 2 : +case 3 : +if (!minor) { + ret =nfsd_vers (nn, major, cmd); +break ; + } + fallthrough; +default : + ret = -EINVAL ; +break ; + } +mutex_unlock (&nfsd_mutex); + +return ret; +} + +/** +* nfsd_nl_version_get_doit - Handle verion_get dumpit +* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb) +{ +struct nfsd_net *nn =net_generic (sock_net (skb->sk), nfsd_net_id); +int i, ret = -ENOMEM ; + +mutex_lock (&nfsd_mutex); + +for (i =2 ; i <=4 ; i++) { +int j; + +if (i < cb->args[0 ])/* already consumed */ +continue ; + +if (!nfsd_vers (nn, i,NFSD_AVAIL )) +continue ; + +for (j =0 ; j <=NFSD_SUPPORTED_MINOR_VERSION ; j++) { +void *hdr; + +if (!nfsd_vers (nn, i,NFSD_TEST )) +continue ; + +/* NFSv{2,3} does not support minor numbers */ +if (i <4 && j) +continue ; + +if (i ==4 && !nfsd_minorversion (nn, j,NFSD_TEST )) +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_VERSION_GET ); +if (!hdr) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MAJOR , i) || +nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MINOR , j)) + goto out; + +genlmsg_end (skb, hdr); + } + } + cb->args[0 ] = i; + ret = skb->len; +out: +mutex_unlock (&nfsd_mutex); + +return ret; +} +/** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace include/uapi/linux/nfsd_netlink.h +11
-0@@ -36,10 +36,21 @@ enum {NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX -1 ) }; +enum { +NFSD_A_SERVER_VERSION_MAJOR =1 , +NFSD_A_SERVER_VERSION_MINOR , +NFSD_A_SERVER_VERSION_STATUS , + + __NFSD_A_SERVER_VERSION_MAX, +NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET , +NFSD_CMD_VERSION_SET , +NFSD_CMD_VERSION_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )tools/net/ynl/generated/nfsd-user.c +81
-0@@ -17,6 +17,8 @@ static const char * const nfsd_op_strmap[] = { [NFSD_CMD_RPC_STATUS_GET] = "rpc-status-get", [NFSD_CMD_THREADS_SET] = "threads-set", [NFSD_CMD_THREADS_GET] = "threads-get", + [NFSD_CMD_VERSION_SET] = "version-set", + [NFSD_CMD_VERSION_GET] = "version-get", };const char *nfsd_op_str (int op)@@ -58,6 +60,17 @@ struct ynl_policy_nest nfsd_server_worker_nest = { .table = nfsd_server_worker_policy, }; +struct ynl_policy_attr nfsd_server_version_policy[NFSD_A_SERVER_VERSION_MAX +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .name ="major" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .name ="minor" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .name ="status" , .type =YNL_PT_U8 , }, +}; + +struct ynl_policy_nest nfsd_server_version_nest = { + .max_attr =NFSD_A_SERVER_VERSION_MAX , + .table = nfsd_server_version_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -290,6 +303,74 @@ struct nfsd_threads_get_rsp *nfsd_threads_get(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +void nfsd_version_set_req_free (struct nfsd_version_set_req *req) +{ +free (req); +} + +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_VERSION_SET ,1 ); + ys->req_policy = &nfsd_server_version_nest; + +if (req->_present.major) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MAJOR , req->major); +if (req->_present.minor) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MINOR , req->minor); +if (req->_present.status) +mnl_attr_put_u8 (nlh,NFSD_A_SERVER_VERSION_STATUS , req->status); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp) +{ +struct nfsd_version_get_list *next = rsp; + +while ((void *)next !=YNL_LIST_END ) { + rsp = next; + next = rsp->next; + +free (rsp); + } +} + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys) +{ +struct ynl_dump_state yds = {}; +struct nlmsghdr *nlh; +int err; + + yds.ys = ys; + yds.alloc_sz =sizeof (struct nfsd_version_get_list ); + yds.cb = nfsd_version_get_rsp_parse; + yds.rsp_cmd =NFSD_CMD_VERSION_GET ; + yds.rsp_policy = &nfsd_server_version_nest; + + nlh =ynl_gemsg_start_dump (ys, ys->family_id,NFSD_CMD_VERSION_GET ,1 ); + + err =ynl_exec_dump (ys, nlh, &yds); +if (err <0 ) + goto free_list; + +return yds.first; + +free_list: +nfsd_version_get_list_free (yds.first); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +4
-0@@ -111,4 +111,59 @@ void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp);*/ struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys); +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +struct nfsd_version_set_req { + struct {
tools/net/ynl/generated/nfsd-user.h void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp); · line 127
Quoted 10 lines
tools/net/ynl/generated/nfsd-user.h +10
-0+ __u32 major:1; + __u32 minor:1; + __u32 status:1; + } _present; + +__u32 major; +__u32 minor; +__u8 status; +}; +
This more or less mirrors how the "versions" file works today, but that interface is quite klunky. We don't have a use case that requires that we do this piecemeal like this. I think we'd be better served with a more declarative interface that reconfigures the supported versions in one shot:
Instead of having "major,minor,status" and potentially having to call this command several times from userland, it seems like it would be nicer to just have userland send down a list "major,minor" that should be enabled, and then just let the kernel figure out whether to enable or disable each. An empty list could mean "disable everything".
That's simpler to reason out as an interface from userland too. Trying to keep track of the enabled and disabled versions and twiddle it is really tricky in rpc.nfsd today.
Quoted 42 lines
tools/net/ynl/generated/nfsd-user.h +41
-0+static inline struct nfsd_version_set_req *nfsd_version_set_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_version_set_req )); +} +void nfsd_version_set_req_free (struct nfsd_version_set_req *req); + +static inline void +nfsd_version_set_req_set_major (struct nfsd_version_set_req *req,__u32 major) +{ + req->_present.major =1 ; + req->major = major; +} +static inline void +nfsd_version_set_req_set_minor (struct nfsd_version_set_req *req,__u32 minor) +{ + req->_present.minor =1 ; + req->minor = minor; +} +static inline void +nfsd_version_set_req_set_status (struct nfsd_version_set_req *req,__u8 status) +{ + req->_present.status =1 ; + req->status = status; +} + +/* +* enable/disable server version +*/ +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req); + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +struct nfsd_version_get_list { +struct nfsd_version_get_list *next; +struct nfsd_version_get_rsp obj __attribute__ ((aligned (8 ))); +}; + +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp); + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v5 2/3] NFSD: convert write_version to netlink command
Quoted 396 lines · Lorenzo Bianconi
Quoted 372 lines
Introduce
write_versionnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 32 ++++++++ fs/nfsd/netlink.c | 19 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 105 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 11 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 55 ++++++++++++++ 7 files changed, 306 insertions(+)Documentation/netlink/specs/nfsd.yaml +32
-0@@ -68,6 +68,18 @@ attribute-sets: - name: threads type: u32 + - + name: server-version + attributes: + - + name: major + type: u32 + - + name: minor + type: u32 + - + name: status + type: u8 operations: list:@@ -110,3 +122,23 @@ operations: reply: attributes: - threads + - + name: version-set + doc: enable/disable server version + attribute-set: server-version + flags: [ admin-perm ] + do: + request: + attributes: + - major + - minor + - status + - + name: version-get + doc: dump server versions + attribute-set: server-version + dump: + reply: + attributes: + - major + - minorfs/nfsd/netlink.c +19
-0@@ -15,6 +15,13 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_T [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, }; +/* NFSD_CMD_VERSION_SET - do */ +static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_STATUS +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .type =NLA_U8 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -36,6 +43,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_threads_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_VERSION_SET, + .doit = nfsd_nl_version_set_doit, + .policy = nfsd_version_set_nl_policy, + .maxattr = NFSD_A_SERVER_VERSION_STATUS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_VERSION_GET, + .dumpit = nfsd_nl_version_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {fs/nfsd/netlink.h +3
-0@@ -18,6 +18,9 @@ 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); +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;fs/nfsd/nfsctl.c +105
-0@@ -1757,6 +1757,111 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)return err; } +/** +* nfsd_nl_version_set_doit - enable/disable the provided nfs server version +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info) +{ +struct nfsd_net *nn =net_generic (genl_info_net (info), nfsd_net_id); +enum vers_op cmd; +u32 major, minor; +u8 status; +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MAJOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MINOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_STATUS )) +return -EINVAL ; + + major =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MAJOR ]); + minor =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MINOR ]); + + status =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_STATUS ]); + cmd = !!status ?NFSD_SET :NFSD_CLEAR ; + +mutex_lock (&nfsd_mutex); +switch (major) { +case 4 : + ret =nfsd_minorversion (nn, minor, cmd); +break ; +case 2 : +case 3 : +if (!minor) { + ret =nfsd_vers (nn, major, cmd); +break ; + } + fallthrough; +default : + ret = -EINVAL ; +break ; + } +mutex_unlock (&nfsd_mutex); + +return ret; +} + +/** +* nfsd_nl_version_get_doit - Handle verion_get dumpit +* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb) +{ +struct nfsd_net *nn =net_generic (sock_net (skb->sk), nfsd_net_id); +int i, ret = -ENOMEM ; + +mutex_lock (&nfsd_mutex); + +for (i =2 ; i <=4 ; i++) { +int j; + +if (i < cb->args[0 ])/* already consumed */ +continue ; + +if (!nfsd_vers (nn, i,NFSD_AVAIL )) +continue ; + +for (j =0 ; j <=NFSD_SUPPORTED_MINOR_VERSION ; j++) { +void *hdr; + +if (!nfsd_vers (nn, i,NFSD_TEST )) +continue ; + +/* NFSv{2,3} does not support minor numbers */ +if (i <4 && j) +continue ; + +if (i ==4 && !nfsd_minorversion (nn, j,NFSD_TEST )) +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_VERSION_GET ); +if (!hdr) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MAJOR , i) || +nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MINOR , j)) + goto out; + +genlmsg_end (skb, hdr); + } + } + cb->args[0 ] = i; + ret = skb->len; +out: +mutex_unlock (&nfsd_mutex); + +return ret; +} +/** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace include/uapi/linux/nfsd_netlink.h +11
-0@@ -36,10 +36,21 @@ enum {NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX -1 ) }; +enum { +NFSD_A_SERVER_VERSION_MAJOR =1 , +NFSD_A_SERVER_VERSION_MINOR , +NFSD_A_SERVER_VERSION_STATUS , + + __NFSD_A_SERVER_VERSION_MAX, +NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET , +NFSD_CMD_VERSION_SET , +NFSD_CMD_VERSION_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )tools/net/ynl/generated/nfsd-user.c +81
-0@@ -17,6 +17,8 @@ static const char * const nfsd_op_strmap[] = { [NFSD_CMD_RPC_STATUS_GET] = "rpc-status-get", [NFSD_CMD_THREADS_SET] = "threads-set", [NFSD_CMD_THREADS_GET] = "threads-get", + [NFSD_CMD_VERSION_SET] = "version-set", + [NFSD_CMD_VERSION_GET] = "version-get", };const char *nfsd_op_str (int op)@@ -58,6 +60,17 @@ struct ynl_policy_nest nfsd_server_worker_nest = { .table = nfsd_server_worker_policy, }; +struct ynl_policy_attr nfsd_server_version_policy[NFSD_A_SERVER_VERSION_MAX +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .name ="major" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .name ="minor" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .name ="status" , .type =YNL_PT_U8 , }, +}; + +struct ynl_policy_nest nfsd_server_version_nest = { + .max_attr =NFSD_A_SERVER_VERSION_MAX , + .table = nfsd_server_version_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -290,6 +303,74 @@ struct nfsd_threads_get_rsp *nfsd_threads_get(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +void nfsd_version_set_req_free (struct nfsd_version_set_req *req) +{ +free (req); +} + +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_VERSION_SET ,1 ); + ys->req_policy = &nfsd_server_version_nest; + +if (req->_present.major) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MAJOR , req->major); +if (req->_present.minor) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MINOR , req->minor); +if (req->_present.status) +mnl_attr_put_u8 (nlh,NFSD_A_SERVER_VERSION_STATUS , req->status); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp) +{ +struct nfsd_version_get_list *next = rsp; + +while ((void *)next !=YNL_LIST_END ) { + rsp = next; + next = rsp->next; + +free (rsp); + } +} + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys) +{ +struct ynl_dump_state yds = {}; +struct nlmsghdr *nlh; +int err; + + yds.ys = ys; + yds.alloc_sz =sizeof (struct nfsd_version_get_list ); + yds.cb = nfsd_version_get_rsp_parse; + yds.rsp_cmd =NFSD_CMD_VERSION_GET ; + yds.rsp_policy = &nfsd_server_version_nest; + + nlh =ynl_gemsg_start_dump (ys, ys->family_id,NFSD_CMD_VERSION_GET ,1 ); + + err =ynl_exec_dump (ys, nlh, &yds); +if (err <0 ) + goto free_list; + +return yds.first; + +free_list: +nfsd_version_get_list_free (yds.first); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +4
-0@@ -111,4 +111,59 @@ void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp);*/ struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys); +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +struct nfsd_version_set_req { + struct {tools/net/ynl/generated/nfsd-user.h void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp); · line 127
Quoted 10 lines
tools/net/ynl/generated/nfsd-user.h +10
-0+ __u32 major:1; + __u32 minor:1; + __u32 status:1; + } _present; + +__u32 major; +__u32 minor; +__u8 status; +}; +This more or less mirrors how the "versions" file works today, but that interface is quite klunky. We don't have a use case that requires that we do this piecemeal like this. I think we'd be better served with a more declarative interface that reconfigures the supported versions in one shot:
Instead of having "major,minor,status" and potentially having to call this command several times from userland, it seems like it would be nicer to just have userland send down a list "major,minor" that should be enabled, and then just let the kernel figure out whether to enable or disable each. An empty list could mean "disable everything".
Quoted 3 lines
That's simpler to reason out as an interface from userland too. Trying to keep track of the enabled and disabled versions and twiddle it is really tricky in rpc.nfsd today.
Ack. So far I have just converted the current implementation to netlink and I have not changed any logic. Anyway I am fine to change the current logic. Should we have 2 rpc.nfsd version in this case?
Regards,
Lorenzo
Quoted 46 lines
Quoted 43 lines
tools/net/ynl/generated/nfsd-user.h +41
-0+static inline struct nfsd_version_set_req *nfsd_version_set_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_version_set_req )); +} +void nfsd_version_set_req_free (struct nfsd_version_set_req *req); + +static inline void +nfsd_version_set_req_set_major (struct nfsd_version_set_req *req,__u32 major) +{ + req->_present.major =1 ; + req->major = major; +} +static inline void +nfsd_version_set_req_set_minor (struct nfsd_version_set_req *req,__u32 minor) +{ + req->_present.minor =1 ; + req->minor = minor; +} +static inline void +nfsd_version_set_req_set_status (struct nfsd_version_set_req *req,__u8 status) +{ + req->_present.status =1 ; + req->status = status; +} + +/* +* enable/disable server version +*/ +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req); + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +struct nfsd_version_get_list { +struct nfsd_version_get_list *next; +struct nfsd_version_get_rsp obj __attribute__ ((aligned (8 ))); +}; + +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp); + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */ Signature · 1 line
Jeff Layton <[email protected]>
Jeff Layton
maintainerRe: [PATCH v5 2/3] NFSD: convert write_version to netlink command
Quoted 432 lines · Lorenzo Bianconi
Quoted 432 lines · Lorenzo Bianconi
Quoted 408 lines
Introduce
write_versionnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>---
Documentation/netlink/specs/nfsd.yaml | 32 ++++++++ fs/nfsd/netlink.c | 19 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 105 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 11 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 55 ++++++++++++++ 7 files changed, 306 insertions(+)Documentation/netlink/specs/nfsd.yaml +0
-0@@ -68,6 +68,18 @@ attribute-sets:-
name: threads
type: u32Documentation/netlink/specs/nfsd.yaml +12
-0+ - + name: server-version + attributes: + - + name: major + type: u32 + - + name: minor + type: u32 + - + name: status + type: u8operations:
list:Documentation/netlink/specs/nfsd.yaml +0
-0@@ -110,3 +122,23 @@ operations:reply:
attributes:
- threadsDocumentation/netlink/specs/nfsd.yaml +20
-0+ - + name: version-set + doc: enable/disable server version + attribute-set: server-version + flags: [ admin-perm ] + do: + request: + attributes: + - major + - minor + - status + - + name: version-get + doc: dump server versions + attribute-set: server-version + dump: + reply: + attributes: + - major + - minorfs/nfsd/netlink.c +0
-0@@ -15,6 +15,13 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_T [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, };fs/nfsd/netlink.c +7
-0+/* NFSD_CMD_VERSION_SET - do */ +static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_STATUS +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .type =NLA_U8 , }, +}; +/* Ops table for nfsd */
static const structgenl_split_opsnfsd_nl_ops[] = { {fs/nfsd/netlink.c +12
-0@@ -36,6 +43,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_threads_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_VERSION_SET, + .doit = nfsd_nl_version_set_doit, + .policy = nfsd_version_set_nl_policy, + .maxattr = NFSD_A_SERVER_VERSION_STATUS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_VERSION_GET, + .dumpit = nfsd_nl_version_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, };struct
genl_familynfsd_nl_family__ro_after_init= {fs/nfsd/netlink.h +3
-0@@ -18,6 +18,9 @@ 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); +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct
genl_familynfsd_nl_family;fs/nfsd/nfsctl.c +0
-0@@ -1757,6 +1757,111 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info) return err; }fs/nfsd/nfsctl.c +105
-0+/** +* nfsd_nl_version_set_doit - enable/disable the provided nfs server version +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info) +{ +struct nfsd_net *nn =net_generic (genl_info_net (info), nfsd_net_id); +enum vers_op cmd; +u32 major, minor; +u8 status; +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MAJOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MINOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_STATUS )) +return -EINVAL ; + + major =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MAJOR ]); + minor =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MINOR ]); + + status =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_STATUS ]); + cmd = !!status ?NFSD_SET :NFSD_CLEAR ; + +mutex_lock (&nfsd_mutex); +switch (major) { +case 4 : + ret =nfsd_minorversion (nn, minor, cmd); +break ; +case 2 : +case 3 : +if (!minor) { + ret =nfsd_vers (nn, major, cmd); +break ; + } + fallthrough; +default : + ret = -EINVAL ; +break ; + } +mutex_unlock (&nfsd_mutex); + +return ret; +} + +/** +* nfsd_nl_version_get_doit - Handle verion_get dumpit +* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb) +{ +struct nfsd_net *nn =net_generic (sock_net (skb->sk), nfsd_net_id); +int i, ret = -ENOMEM ; + +mutex_lock (&nfsd_mutex); + +for (i =2 ; i <=4 ; i++) { +int j; + +if (i < cb->args[0 ])/* already consumed */ +continue ; + +if (!nfsd_vers (nn, i,NFSD_AVAIL )) +continue ; + +for (j =0 ; j <=NFSD_SUPPORTED_MINOR_VERSION ; j++) { +void *hdr; + +if (!nfsd_vers (nn, i,NFSD_TEST )) +continue ; + +/* NFSv{2,3} does not support minor numbers */ +if (i <4 && j) +continue ; + +if (i ==4 && !nfsd_minorversion (nn, j,NFSD_TEST )) +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_VERSION_GET ); +if (!hdr) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MAJOR , i) || +nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MINOR , j)) + goto out; + +genlmsg_end (skb, hdr); + } + } + cb->args[0 ] = i; + ret = skb->len; +out: +mutex_unlock (&nfsd_mutex); + +return ret; +} +/**
*nfsd_net_init- Prepare thenfsd_netportion of a new net namespace
* @net: a freshly-created network namespaceinclude/uapi/linux/nfsd_netlink.h +0
-0@@ -36,10 +36,21 @@ enum { NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX - 1) };include/uapi/linux/nfsd_netlink.h +9
-0+enum { +NFSD_A_SERVER_VERSION_MAJOR =1 , +NFSD_A_SERVER_VERSION_MINOR , +NFSD_A_SERVER_VERSION_STATUS , + + __NFSD_A_SERVER_VERSION_MAX, +NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) +}; +enum {
NFSD_CMD_RPC_STATUS_GET= 1,
NFSD_CMD_THREADS_SET,
NFSD_CMD_THREADS_GET,include/uapi/linux/nfsd_netlink.h +2
-0+NFSD_CMD_VERSION_SET , + NFSD_CMD_VERSION_GET,
__NFSD_CMD_MAX,
NFSD_CMD_MAX= (__NFSD_CMD_MAX- 1)tools/net/ynl/generated/nfsd-user.c +2
-0@@ -17,6 +17,8 @@ static const char * const nfsd_op_strmap[] = { [NFSD_CMD_RPC_STATUS_GET] = "rpc-status-get", [NFSD_CMD_THREADS_SET] = "threads-set", [NFSD_CMD_THREADS_GET] = "threads-get", + [NFSD_CMD_VERSION_SET] = "version-set", + [NFSD_CMD_VERSION_GET] = "version-get", };const char *nfsd_op_str(int op)
tools/net/ynl/generated/nfsd-user.c +0
-0@@ -58,6 +60,17 @@ struct ynl_policy_nest nfsd_server_worker_nest = { .table = nfsd_server_worker_policy, };tools/net/ynl/generated/nfsd-user.c +11
-0+struct ynl_policy_attr nfsd_server_version_policy[NFSD_A_SERVER_VERSION_MAX +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .name ="major" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .name ="minor" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .name ="status" , .type =YNL_PT_U8 , }, +}; + +struct ynl_policy_nest nfsd_server_version_nest = { + .max_attr =NFSD_A_SERVER_VERSION_MAX , + .table = nfsd_server_version_policy, +}; +/* Common nested types */
/* ==============NFSD_CMD_RPC_STATUS_GET============== */ /*NFSD_CMD_RPC_STATUS_GET- dump */tools/net/ynl/generated/nfsd-user.c +0
-0@@ -290,6 +303,74 @@ struct nfsd_threads_get_rsp *nfsd_threads_get(struct ynl_sock *ys) return NULL; }tools/net/ynl/generated/nfsd-user.c +68
-0+/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +void nfsd_version_set_req_free (struct nfsd_version_set_req *req) +{ +free (req); +} + +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_VERSION_SET ,1 ); + ys->req_policy = &nfsd_server_version_nest; + +if (req->_present.major) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MAJOR , req->major); +if (req->_present.minor) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MINOR , req->minor); +if (req->_present.status) +mnl_attr_put_u8 (nlh,NFSD_A_SERVER_VERSION_STATUS , req->status); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp) +{ +struct nfsd_version_get_list *next = rsp; + +while ((void *)next !=YNL_LIST_END ) { + rsp = next; + next = rsp->next; + +free (rsp); + } +} + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys) +{ +struct ynl_dump_state yds = {}; +struct nlmsghdr *nlh; +int err; + + yds.ys = ys; + yds.alloc_sz =sizeof (struct nfsd_version_get_list ); + yds.cb = nfsd_version_get_rsp_parse; + yds.rsp_cmd =NFSD_CMD_VERSION_GET ; + yds.rsp_policy = &nfsd_server_version_nest; + + nlh =ynl_gemsg_start_dump (ys, ys->family_id,NFSD_CMD_VERSION_GET ,1 ); + + err =ynl_exec_dump (ys, nlh, &yds); +if (err <0 ) + goto free_list; + +return yds.first; + +free_list: +nfsd_version_get_list_free (yds.first); +return NULL ; +} +const struct
ynl_familyynl_nfsd_family= {
.name = "nfsd",
};tools/net/ynl/generated/nfsd-user.h +0
-0@@ -111,4 +111,59 @@ void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp);*/ struct nfsd_threads_get_rsp *nfsd_threads_get(struct ynl_sock *ys);tools/net/ynl/generated/nfsd-user.h +4
-0+/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +struct nfsd_version_set_req { + struct {tools/net/ynl/generated/nfsd-user.h void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp); · line 127
Quoted 10 lines
tools/net/ynl/generated/nfsd-user.h +10
-0+ __u32 major:1; + __u32 minor:1; + __u32 status:1; + } _present; + +__u32 major; +__u32 minor; +__u8 status; +}; +This more or less mirrors how the "versions" file works today, but that interface is quite klunky. We don't have a use case that requires that we do this piecemeal like this. I think we'd be better served with a more declarative interface that reconfigures the supported versions in one shot:
Instead of having "major,minor,status" and potentially having to call this command several times from userland, it seems like it would be nicer to just have userland send down a list "major,minor" that should be enabled, and then just let the kernel figure out whether to enable or disable each. An empty list could mean "disable everything".
Quoted 8 lines
Quoted 3 lines
That's simpler to reason out as an interface from userland too. Trying to keep track of the enabled and disabled versions and twiddle it is really tricky in rpc.nfsd today.
Ack. So far I have just converted the current implementation to netlink and I have not changed any logic. Anyway I am fine to change the current logic. Should we have 2 rpc.nfsd version in this case?
No. The goal is to make this a seamless change for systems administrators who are already familiar with the userland tools.
I think what we want to aim for is to teach the existing rpc.nfsd to speak netlink if it's available. If it's not, then it can fall back to using the nfsdfs interfaces instead. Eventually (years from now) we can remove the old interface support, once most everything in the field has netlink support.
Quoted 48 lines
Quoted 48 lines
Quoted 42 lines
tools/net/ynl/generated/nfsd-user.h +41
-0+static inline struct nfsd_version_set_req *nfsd_version_set_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_version_set_req )); +} +void nfsd_version_set_req_free (struct nfsd_version_set_req *req); + +static inline void +nfsd_version_set_req_set_major (struct nfsd_version_set_req *req,__u32 major) +{ + req->_present.major =1 ; + req->major = major; +} +static inline void +nfsd_version_set_req_set_minor (struct nfsd_version_set_req *req,__u32 minor) +{ + req->_present.minor =1 ; + req->minor = minor; +} +static inline void +nfsd_version_set_req_set_status (struct nfsd_version_set_req *req,__u8 status) +{ + req->_present.status =1 ; + req->status = status; +} + +/* +* enable/disable server version +*/ +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req); + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +struct nfsd_version_get_list { +struct nfsd_version_get_list *next; +struct nfsd_version_get_rsp obj __attribute__ ((aligned (8 ))); +}; + +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp); + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys); +#endif /*
_LINUX_NFSD_GEN_H*/Signature · 1 line
Jeff Layton <[email protected]>
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v5 2/3] NFSD: convert write_version to netlink command
In reply to Jeff LaytonQuoted 396 lines · Jeff Layton
Quoted 372 lines · Lorenzo Bianconi
Introduce
write_versionnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 32 ++++++++ fs/nfsd/netlink.c | 19 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 105 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 11 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 55 ++++++++++++++ 7 files changed, 306 insertions(+)Documentation/netlink/specs/nfsd.yaml +32
-0@@ -68,6 +68,18 @@ attribute-sets: - name: threads type: u32 + - + name: server-version + attributes: + - + name: major + type: u32 + - + name: minor + type: u32 + - + name: status + type: u8 operations: list:@@ -110,3 +122,23 @@ operations: reply: attributes: - threads + - + name: version-set + doc: enable/disable server version + attribute-set: server-version + flags: [ admin-perm ] + do: + request: + attributes: + - major + - minor + - status + - + name: version-get + doc: dump server versions + attribute-set: server-version + dump: + reply: + attributes: + - major + - minorfs/nfsd/netlink.c +19
-0@@ -15,6 +15,13 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_T [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, }; +/* NFSD_CMD_VERSION_SET - do */ +static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_STATUS +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .type =NLA_U8 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -36,6 +43,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_threads_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_VERSION_SET, + .doit = nfsd_nl_version_set_doit, + .policy = nfsd_version_set_nl_policy, + .maxattr = NFSD_A_SERVER_VERSION_STATUS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_VERSION_GET, + .dumpit = nfsd_nl_version_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {fs/nfsd/netlink.h +3
-0@@ -18,6 +18,9 @@ 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); +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;fs/nfsd/nfsctl.c +105
-0@@ -1757,6 +1757,111 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)return err; } +/** +* nfsd_nl_version_set_doit - enable/disable the provided nfs server version +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info) +{ +struct nfsd_net *nn =net_generic (genl_info_net (info), nfsd_net_id); +enum vers_op cmd; +u32 major, minor; +u8 status; +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MAJOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MINOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_STATUS )) +return -EINVAL ; + + major =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MAJOR ]); + minor =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MINOR ]); + + status =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_STATUS ]); + cmd = !!status ?NFSD_SET :NFSD_CLEAR ; + +mutex_lock (&nfsd_mutex); +switch (major) { +case 4 : + ret =nfsd_minorversion (nn, minor, cmd); +break ; +case 2 : +case 3 : +if (!minor) { + ret =nfsd_vers (nn, major, cmd); +break ; + } + fallthrough; +default : + ret = -EINVAL ; +break ; + } +mutex_unlock (&nfsd_mutex); + +return ret; +} + +/** +* nfsd_nl_version_get_doit - Handle verion_get dumpit +* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb) +{ +struct nfsd_net *nn =net_generic (sock_net (skb->sk), nfsd_net_id); +int i, ret = -ENOMEM ; + +mutex_lock (&nfsd_mutex); + +for (i =2 ; i <=4 ; i++) { +int j; + +if (i < cb->args[0 ])/* already consumed */ +continue ; + +if (!nfsd_vers (nn, i,NFSD_AVAIL )) +continue ; + +for (j =0 ; j <=NFSD_SUPPORTED_MINOR_VERSION ; j++) { +void *hdr; + +if (!nfsd_vers (nn, i,NFSD_TEST )) +continue ; + +/* NFSv{2,3} does not support minor numbers */ +if (i <4 && j) +continue ; + +if (i ==4 && !nfsd_minorversion (nn, j,NFSD_TEST )) +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_VERSION_GET ); +if (!hdr) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MAJOR , i) || +nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MINOR , j)) + goto out; + +genlmsg_end (skb, hdr); + } + } + cb->args[0 ] = i; + ret = skb->len; +out: +mutex_unlock (&nfsd_mutex); + +return ret; +} +/** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace include/uapi/linux/nfsd_netlink.h +11
-0@@ -36,10 +36,21 @@ enum {NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX -1 ) }; +enum { +NFSD_A_SERVER_VERSION_MAJOR =1 , +NFSD_A_SERVER_VERSION_MINOR , +NFSD_A_SERVER_VERSION_STATUS , + + __NFSD_A_SERVER_VERSION_MAX, +NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET , +NFSD_CMD_VERSION_SET , +NFSD_CMD_VERSION_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )tools/net/ynl/generated/nfsd-user.c +81
-0@@ -17,6 +17,8 @@ static const char * const nfsd_op_strmap[] = { [NFSD_CMD_RPC_STATUS_GET] = "rpc-status-get", [NFSD_CMD_THREADS_SET] = "threads-set", [NFSD_CMD_THREADS_GET] = "threads-get", + [NFSD_CMD_VERSION_SET] = "version-set", + [NFSD_CMD_VERSION_GET] = "version-get", };const char *nfsd_op_str (int op)@@ -58,6 +60,17 @@ struct ynl_policy_nest nfsd_server_worker_nest = { .table = nfsd_server_worker_policy, }; +struct ynl_policy_attr nfsd_server_version_policy[NFSD_A_SERVER_VERSION_MAX +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .name ="major" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .name ="minor" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .name ="status" , .type =YNL_PT_U8 , }, +}; + +struct ynl_policy_nest nfsd_server_version_nest = { + .max_attr =NFSD_A_SERVER_VERSION_MAX , + .table = nfsd_server_version_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -290,6 +303,74 @@ struct nfsd_threads_get_rsp *nfsd_threads_get(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +void nfsd_version_set_req_free (struct nfsd_version_set_req *req) +{ +free (req); +} + +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_VERSION_SET ,1 ); + ys->req_policy = &nfsd_server_version_nest; + +if (req->_present.major) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MAJOR , req->major); +if (req->_present.minor) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MINOR , req->minor); +if (req->_present.status) +mnl_attr_put_u8 (nlh,NFSD_A_SERVER_VERSION_STATUS , req->status); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp) +{ +struct nfsd_version_get_list *next = rsp; + +while ((void *)next !=YNL_LIST_END ) { + rsp = next; + next = rsp->next; + +free (rsp); + } +} + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys) +{ +struct ynl_dump_state yds = {}; +struct nlmsghdr *nlh; +int err; + + yds.ys = ys; + yds.alloc_sz =sizeof (struct nfsd_version_get_list ); + yds.cb = nfsd_version_get_rsp_parse; + yds.rsp_cmd =NFSD_CMD_VERSION_GET ; + yds.rsp_policy = &nfsd_server_version_nest; + + nlh =ynl_gemsg_start_dump (ys, ys->family_id,NFSD_CMD_VERSION_GET ,1 ); + + err =ynl_exec_dump (ys, nlh, &yds); +if (err <0 ) + goto free_list; + +return yds.first; + +free_list: +nfsd_version_get_list_free (yds.first); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +4
-0@@ -111,4 +111,59 @@ void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp);*/ struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys); +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +struct nfsd_version_set_req { + struct {tools/net/ynl/generated/nfsd-user.h void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp); · line 127
Quoted 10 lines
tools/net/ynl/generated/nfsd-user.h +10
-0+ __u32 major:1; + __u32 minor:1; + __u32 status:1; + } _present; + +__u32 major; +__u32 minor; +__u8 status; +}; +This more or less mirrors how the "versions" file works today, but that interface is quite klunky. We don't have a use case that requires that we do this piecemeal like this. I think we'd be better served with a more declarative interface that reconfigures the supported versions in one shot:
Instead of having "major,minor,status" and potentially having to call this command several times from userland, it seems like it would be nicer to just have userland send down a list "major,minor" that should be enabled, and then just let the kernel figure out whether to enable or disable each. An empty list could mean "disable everything".
Quoted 3 lines
That's simpler to reason out as an interface from userland too. Trying to keep track of the enabled and disabled versions and twiddle it is really tricky in rpc.nfsd today.
Jeff and Lorenzo, this sounds to me like a useful and narrow improvement to this interface, one that should be implemented as part of this patch series.
Ditto for Jeff's review comment on 3/3.
Quoted 46 lines
Quoted 42 lines
tools/net/ynl/generated/nfsd-user.h +41
-0+static inline struct nfsd_version_set_req *nfsd_version_set_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_version_set_req )); +} +void nfsd_version_set_req_free (struct nfsd_version_set_req *req); + +static inline void +nfsd_version_set_req_set_major (struct nfsd_version_set_req *req,__u32 major) +{ + req->_present.major =1 ; + req->major = major; +} +static inline void +nfsd_version_set_req_set_minor (struct nfsd_version_set_req *req,__u32 minor) +{ + req->_present.minor =1 ; + req->minor = minor; +} +static inline void +nfsd_version_set_req_set_status (struct nfsd_version_set_req *req,__u8 status) +{ + req->_present.status =1 ; + req->status = status; +} + +/* +* enable/disable server version +*/ +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req); + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +struct nfsd_version_get_list { +struct nfsd_version_get_list *next; +struct nfsd_version_get_rsp obj __attribute__ ((aligned (8 ))); +}; + +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp); + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */ Signature · 1 line
Jeff Layton <[email protected]>
Signature · 1 line
Chuck Lever
Re: [PATCH v5 2/3] NFSD: convert write_version to netlink command
Quoted 397 lines · Jeff Layton
Quoted 396 lines · Lorenzo Bianconi
Quoted 372 lines
Introduce
write_versionnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 32 ++++++++ fs/nfsd/netlink.c | 19 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 105 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 11 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 55 ++++++++++++++ 7 files changed, 306 insertions(+)Documentation/netlink/specs/nfsd.yaml +32
-0@@ -68,6 +68,18 @@ attribute-sets: - name: threads type: u32 + - + name: server-version + attributes: + - + name: major + type: u32 + - + name: minor + type: u32 + - + name: status + type: u8 operations: list:@@ -110,3 +122,23 @@ operations: reply: attributes: - threads + - + name: version-set + doc: enable/disable server version + attribute-set: server-version + flags: [ admin-perm ] + do: + request: + attributes: + - major + - minor + - status + - + name: version-get + doc: dump server versions + attribute-set: server-version + dump: + reply: + attributes: + - major + - minorfs/nfsd/netlink.c +19
-0@@ -15,6 +15,13 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_T [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, }; +/* NFSD_CMD_VERSION_SET - do */ +static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_STATUS +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .type =NLA_U8 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -36,6 +43,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_threads_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_VERSION_SET, + .doit = nfsd_nl_version_set_doit, + .policy = nfsd_version_set_nl_policy, + .maxattr = NFSD_A_SERVER_VERSION_STATUS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_VERSION_GET, + .dumpit = nfsd_nl_version_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {fs/nfsd/netlink.h +3
-0@@ -18,6 +18,9 @@ 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); +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;fs/nfsd/nfsctl.c +105
-0@@ -1757,6 +1757,111 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)return err; } +/** +* nfsd_nl_version_set_doit - enable/disable the provided nfs server version +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info) +{ +struct nfsd_net *nn =net_generic (genl_info_net (info), nfsd_net_id); +enum vers_op cmd; +u32 major, minor; +u8 status; +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MAJOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MINOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_STATUS )) +return -EINVAL ; + + major =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MAJOR ]); + minor =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MINOR ]); + + status =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_STATUS ]); + cmd = !!status ?NFSD_SET :NFSD_CLEAR ; + +mutex_lock (&nfsd_mutex); +switch (major) { +case 4 : + ret =nfsd_minorversion (nn, minor, cmd); +break ; +case 2 : +case 3 : +if (!minor) { + ret =nfsd_vers (nn, major, cmd); +break ; + } + fallthrough; +default : + ret = -EINVAL ; +break ; + } +mutex_unlock (&nfsd_mutex); + +return ret; +} + +/** +* nfsd_nl_version_get_doit - Handle verion_get dumpit +* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb) +{ +struct nfsd_net *nn =net_generic (sock_net (skb->sk), nfsd_net_id); +int i, ret = -ENOMEM ; + +mutex_lock (&nfsd_mutex); + +for (i =2 ; i <=4 ; i++) { +int j; + +if (i < cb->args[0 ])/* already consumed */ +continue ; + +if (!nfsd_vers (nn, i,NFSD_AVAIL )) +continue ; + +for (j =0 ; j <=NFSD_SUPPORTED_MINOR_VERSION ; j++) { +void *hdr; + +if (!nfsd_vers (nn, i,NFSD_TEST )) +continue ; + +/* NFSv{2,3} does not support minor numbers */ +if (i <4 && j) +continue ; + +if (i ==4 && !nfsd_minorversion (nn, j,NFSD_TEST )) +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_VERSION_GET ); +if (!hdr) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MAJOR , i) || +nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MINOR , j)) + goto out; + +genlmsg_end (skb, hdr); + } + } + cb->args[0 ] = i; + ret = skb->len; +out: +mutex_unlock (&nfsd_mutex); + +return ret; +} +/** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace include/uapi/linux/nfsd_netlink.h +11
-0@@ -36,10 +36,21 @@ enum {NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX -1 ) }; +enum { +NFSD_A_SERVER_VERSION_MAJOR =1 , +NFSD_A_SERVER_VERSION_MINOR , +NFSD_A_SERVER_VERSION_STATUS , + + __NFSD_A_SERVER_VERSION_MAX, +NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET , +NFSD_CMD_VERSION_SET , +NFSD_CMD_VERSION_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )tools/net/ynl/generated/nfsd-user.c +81
-0@@ -17,6 +17,8 @@ static const char * const nfsd_op_strmap[] = { [NFSD_CMD_RPC_STATUS_GET] = "rpc-status-get", [NFSD_CMD_THREADS_SET] = "threads-set", [NFSD_CMD_THREADS_GET] = "threads-get", + [NFSD_CMD_VERSION_SET] = "version-set", + [NFSD_CMD_VERSION_GET] = "version-get", };const char *nfsd_op_str (int op)@@ -58,6 +60,17 @@ struct ynl_policy_nest nfsd_server_worker_nest = { .table = nfsd_server_worker_policy, }; +struct ynl_policy_attr nfsd_server_version_policy[NFSD_A_SERVER_VERSION_MAX +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .name ="major" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .name ="minor" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .name ="status" , .type =YNL_PT_U8 , }, +}; + +struct ynl_policy_nest nfsd_server_version_nest = { + .max_attr =NFSD_A_SERVER_VERSION_MAX , + .table = nfsd_server_version_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -290,6 +303,74 @@ struct nfsd_threads_get_rsp *nfsd_threads_get(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +void nfsd_version_set_req_free (struct nfsd_version_set_req *req) +{ +free (req); +} + +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_VERSION_SET ,1 ); + ys->req_policy = &nfsd_server_version_nest; + +if (req->_present.major) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MAJOR , req->major); +if (req->_present.minor) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MINOR , req->minor); +if (req->_present.status) +mnl_attr_put_u8 (nlh,NFSD_A_SERVER_VERSION_STATUS , req->status); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp) +{ +struct nfsd_version_get_list *next = rsp; + +while ((void *)next !=YNL_LIST_END ) { + rsp = next; + next = rsp->next; + +free (rsp); + } +} + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys) +{ +struct ynl_dump_state yds = {}; +struct nlmsghdr *nlh; +int err; + + yds.ys = ys; + yds.alloc_sz =sizeof (struct nfsd_version_get_list ); + yds.cb = nfsd_version_get_rsp_parse; + yds.rsp_cmd =NFSD_CMD_VERSION_GET ; + yds.rsp_policy = &nfsd_server_version_nest; + + nlh =ynl_gemsg_start_dump (ys, ys->family_id,NFSD_CMD_VERSION_GET ,1 ); + + err =ynl_exec_dump (ys, nlh, &yds); +if (err <0 ) + goto free_list; + +return yds.first; + +free_list: +nfsd_version_get_list_free (yds.first); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +4
-0@@ -111,4 +111,59 @@ void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp);*/ struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys); +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +struct nfsd_version_set_req { + struct {tools/net/ynl/generated/nfsd-user.h void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp); · line 127
Quoted 10 lines
tools/net/ynl/generated/nfsd-user.h +10
-0+ __u32 major:1; + __u32 minor:1; + __u32 status:1; + } _present; + +__u32 major; +__u32 minor; +__u8 status; +}; +This more or less mirrors how the "versions" file works today, but that interface is quite klunky. We don't have a use case that requires that we do this piecemeal like this. I think we'd be better served with a more declarative interface that reconfigures the supported versions in one shot:
Instead of having "major,minor,status" and potentially having to call this command several times from userland, it seems like it would be nicer to just have userland send down a list "major,minor" that should be enabled, and then just let the kernel figure out whether to enable or disable each. An empty list could mean "disable everything".
Quoted 7 lines
Quoted 3 lines
That's simpler to reason out as an interface from userland too. Trying to keep track of the enabled and disabled versions and twiddle it is really tricky in rpc.nfsd today.
Jeff and Lorenzo, this sounds to me like a useful and narrow improvement to this interface, one that should be implemented as part of this patch series.
ack, I am fine with it, I will work on patch 2/3 and 3/3. @Chuck: am I suppose to respin patch 1/3 too?
Regards,
Lorenzo
Quoted 53 lines
Ditto for Jeff's review comment on 3/3.
Quoted 46 lines
Quoted 42 lines
tools/net/ynl/generated/nfsd-user.h +41
-0+static inline struct nfsd_version_set_req *nfsd_version_set_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_version_set_req )); +} +void nfsd_version_set_req_free (struct nfsd_version_set_req *req); + +static inline void +nfsd_version_set_req_set_major (struct nfsd_version_set_req *req,__u32 major) +{ + req->_present.major =1 ; + req->major = major; +} +static inline void +nfsd_version_set_req_set_minor (struct nfsd_version_set_req *req,__u32 minor) +{ + req->_present.minor =1 ; + req->minor = minor; +} +static inline void +nfsd_version_set_req_set_status (struct nfsd_version_set_req *req,__u8 status) +{ + req->_present.status =1 ; + req->status = status; +} + +/* +* enable/disable server version +*/ +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req); + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +struct nfsd_version_get_list { +struct nfsd_version_get_list *next; +struct nfsd_version_get_rsp obj __attribute__ ((aligned (8 ))); +}; + +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp); + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */ Signature · 1 line
Jeff Layton <[email protected]>Signature · 1 line
Chuck Lever
Re: [PATCH v5 2/3] NFSD: convert write_version to netlink command
Quoted 401 lines · Lorenzo Bianconi
Quoted 401 lines · Jeff Layton
Quoted 399 lines · Lorenzo Bianconi
Quoted 372 lines
Introduce
write_versionnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 32 ++++++++ fs/nfsd/netlink.c | 19 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 105 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 11 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 55 ++++++++++++++ 7 files changed, 306 insertions(+)Documentation/netlink/specs/nfsd.yaml +32
-0@@ -68,6 +68,18 @@ attribute-sets: - name: threads type: u32 + - + name: server-version + attributes: + - + name: major + type: u32 + - + name: minor + type: u32 + - + name: status + type: u8 operations: list:@@ -110,3 +122,23 @@ operations: reply: attributes: - threads + - + name: version-set + doc: enable/disable server version + attribute-set: server-version + flags: [ admin-perm ] + do: + request: + attributes: + - major + - minor + - status + - + name: version-get + doc: dump server versions + attribute-set: server-version + dump: + reply: + attributes: + - major + - minorfs/nfsd/netlink.c +19
-0@@ -15,6 +15,13 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_T [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, }; +/* NFSD_CMD_VERSION_SET - do */ +static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_STATUS +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .type =NLA_U8 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -36,6 +43,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_threads_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_VERSION_SET, + .doit = nfsd_nl_version_set_doit, + .policy = nfsd_version_set_nl_policy, + .maxattr = NFSD_A_SERVER_VERSION_STATUS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_VERSION_GET, + .dumpit = nfsd_nl_version_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {fs/nfsd/netlink.h +3
-0@@ -18,6 +18,9 @@ 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); +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;fs/nfsd/nfsctl.c +105
-0@@ -1757,6 +1757,111 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)return err; } +/** +* nfsd_nl_version_set_doit - enable/disable the provided nfs server version +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info) +{ +struct nfsd_net *nn =net_generic (genl_info_net (info), nfsd_net_id); +enum vers_op cmd; +u32 major, minor; +u8 status; +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MAJOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MINOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_STATUS )) +return -EINVAL ; + + major =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MAJOR ]); + minor =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MINOR ]); + + status =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_STATUS ]); + cmd = !!status ?NFSD_SET :NFSD_CLEAR ; + +mutex_lock (&nfsd_mutex); +switch (major) { +case 4 : + ret =nfsd_minorversion (nn, minor, cmd); +break ; +case 2 : +case 3 : +if (!minor) { + ret =nfsd_vers (nn, major, cmd); +break ; + } + fallthrough; +default : + ret = -EINVAL ; +break ; + } +mutex_unlock (&nfsd_mutex); + +return ret; +} + +/** +* nfsd_nl_version_get_doit - Handle verion_get dumpit +* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb) +{ +struct nfsd_net *nn =net_generic (sock_net (skb->sk), nfsd_net_id); +int i, ret = -ENOMEM ; + +mutex_lock (&nfsd_mutex); + +for (i =2 ; i <=4 ; i++) { +int j; + +if (i < cb->args[0 ])/* already consumed */ +continue ; + +if (!nfsd_vers (nn, i,NFSD_AVAIL )) +continue ; + +for (j =0 ; j <=NFSD_SUPPORTED_MINOR_VERSION ; j++) { +void *hdr; + +if (!nfsd_vers (nn, i,NFSD_TEST )) +continue ; + +/* NFSv{2,3} does not support minor numbers */ +if (i <4 && j) +continue ; + +if (i ==4 && !nfsd_minorversion (nn, j,NFSD_TEST )) +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_VERSION_GET ); +if (!hdr) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MAJOR , i) || +nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MINOR , j)) + goto out; + +genlmsg_end (skb, hdr); + } + } + cb->args[0 ] = i; + ret = skb->len; +out: +mutex_unlock (&nfsd_mutex); + +return ret; +} +/** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace include/uapi/linux/nfsd_netlink.h +11
-0@@ -36,10 +36,21 @@ enum {NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX -1 ) }; +enum { +NFSD_A_SERVER_VERSION_MAJOR =1 , +NFSD_A_SERVER_VERSION_MINOR , +NFSD_A_SERVER_VERSION_STATUS , + + __NFSD_A_SERVER_VERSION_MAX, +NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET , +NFSD_CMD_VERSION_SET , +NFSD_CMD_VERSION_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )tools/net/ynl/generated/nfsd-user.c +81
-0@@ -17,6 +17,8 @@ static const char * const nfsd_op_strmap[] = { [NFSD_CMD_RPC_STATUS_GET] = "rpc-status-get", [NFSD_CMD_THREADS_SET] = "threads-set", [NFSD_CMD_THREADS_GET] = "threads-get", + [NFSD_CMD_VERSION_SET] = "version-set", + [NFSD_CMD_VERSION_GET] = "version-get", };const char *nfsd_op_str (int op)@@ -58,6 +60,17 @@ struct ynl_policy_nest nfsd_server_worker_nest = { .table = nfsd_server_worker_policy, }; +struct ynl_policy_attr nfsd_server_version_policy[NFSD_A_SERVER_VERSION_MAX +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .name ="major" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .name ="minor" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .name ="status" , .type =YNL_PT_U8 , }, +}; + +struct ynl_policy_nest nfsd_server_version_nest = { + .max_attr =NFSD_A_SERVER_VERSION_MAX , + .table = nfsd_server_version_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -290,6 +303,74 @@ struct nfsd_threads_get_rsp *nfsd_threads_get(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +void nfsd_version_set_req_free (struct nfsd_version_set_req *req) +{ +free (req); +} + +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_VERSION_SET ,1 ); + ys->req_policy = &nfsd_server_version_nest; + +if (req->_present.major) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MAJOR , req->major); +if (req->_present.minor) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MINOR , req->minor); +if (req->_present.status) +mnl_attr_put_u8 (nlh,NFSD_A_SERVER_VERSION_STATUS , req->status); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp) +{ +struct nfsd_version_get_list *next = rsp; + +while ((void *)next !=YNL_LIST_END ) { + rsp = next; + next = rsp->next; + +free (rsp); + } +} + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys) +{ +struct ynl_dump_state yds = {}; +struct nlmsghdr *nlh; +int err; + + yds.ys = ys; + yds.alloc_sz =sizeof (struct nfsd_version_get_list ); + yds.cb = nfsd_version_get_rsp_parse; + yds.rsp_cmd =NFSD_CMD_VERSION_GET ; + yds.rsp_policy = &nfsd_server_version_nest; + + nlh =ynl_gemsg_start_dump (ys, ys->family_id,NFSD_CMD_VERSION_GET ,1 ); + + err =ynl_exec_dump (ys, nlh, &yds); +if (err <0 ) + goto free_list; + +return yds.first; + +free_list: +nfsd_version_get_list_free (yds.first); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +4
-0@@ -111,4 +111,59 @@ void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp);*/ struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys); +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +struct nfsd_version_set_req { + struct {tools/net/ynl/generated/nfsd-user.h void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp); · line 127
Quoted 10 lines
tools/net/ynl/generated/nfsd-user.h +10
-0+ __u32 major:1; + __u32 minor:1; + __u32 status:1; + } _present; + +__u32 major; +__u32 minor; +__u8 status; +}; +This more or less mirrors how the "versions" file works today, but that interface is quite klunky. We don't have a use case that requires that we do this piecemeal like this. I think we'd be better served with a more declarative interface that reconfigures the supported versions in one shot:
Instead of having "major,minor,status" and potentially having to call this command several times from userland, it seems like it would be nicer to just have userland send down a list "major,minor" that should be enabled, and then just let the kernel figure out whether to enable or disable each. An empty list could mean "disable everything".
That's simpler to reason out as an interface from userland too. Trying to keep track of the enabled and disabled versions and twiddle it is really tricky in rpc.nfsd today.
Quoted 6 lines
Quoted 3 lines
Jeff and Lorenzo, this sounds to me like a useful and narrow improvement to this interface, one that should be implemented as part of this patch series.
ack, I am fine with it, I will work on patch 2/3 and 3/3. @Chuck: am I suppose to respin patch 1/3 too?
I assumed there might be minor changes to 1/3 after Jakub's second review, so I have not applied it yet. You can resend all three to me.
Quoted 56 lines
Regards,
LorenzoQuoted 53 lines
Ditto for Jeff's review comment on 3/3.
Quoted 46 lines
Quoted 42 lines
tools/net/ynl/generated/nfsd-user.h +41
-0+static inline struct nfsd_version_set_req *nfsd_version_set_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_version_set_req )); +} +void nfsd_version_set_req_free (struct nfsd_version_set_req *req); + +static inline void +nfsd_version_set_req_set_major (struct nfsd_version_set_req *req,__u32 major) +{ + req->_present.major =1 ; + req->major = major; +} +static inline void +nfsd_version_set_req_set_minor (struct nfsd_version_set_req *req,__u32 minor) +{ + req->_present.minor =1 ; + req->minor = minor; +} +static inline void +nfsd_version_set_req_set_status (struct nfsd_version_set_req *req,__u8 status) +{ + req->_present.status =1 ; + req->status = status; +} + +/* +* enable/disable server version +*/ +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req); + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +struct nfsd_version_get_list { +struct nfsd_version_get_list *next; +struct nfsd_version_get_rsp obj __attribute__ ((aligned (8 ))); +}; + +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp); + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */ Signature · 1 line
Jeff Layton <[email protected]>Signature · 1 line
Chuck Lever
Signature · 1 line
Chuck Lever
Re: [PATCH v5 2/3] NFSD: convert write_version to netlink command
Quoted 406 lines · Chuck Lever
Quoted 405 lines · Lorenzo Bianconi
Quoted 404 lines · Jeff Layton
Quoted 396 lines · Lorenzo Bianconi
Quoted 372 lines
Introduce
write_versionnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 32 ++++++++ fs/nfsd/netlink.c | 19 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 105 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 11 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 55 ++++++++++++++ 7 files changed, 306 insertions(+)Documentation/netlink/specs/nfsd.yaml +32
-0@@ -68,6 +68,18 @@ attribute-sets: - name: threads type: u32 + - + name: server-version + attributes: + - + name: major + type: u32 + - + name: minor + type: u32 + - + name: status + type: u8 operations: list:@@ -110,3 +122,23 @@ operations: reply: attributes: - threads + - + name: version-set + doc: enable/disable server version + attribute-set: server-version + flags: [ admin-perm ] + do: + request: + attributes: + - major + - minor + - status + - + name: version-get + doc: dump server versions + attribute-set: server-version + dump: + reply: + attributes: + - major + - minorfs/nfsd/netlink.c +19
-0@@ -15,6 +15,13 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_T [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, }; +/* NFSD_CMD_VERSION_SET - do */ +static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_STATUS +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .type =NLA_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .type =NLA_U8 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -36,6 +43,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_threads_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_VERSION_SET, + .doit = nfsd_nl_version_set_doit, + .policy = nfsd_version_set_nl_policy, + .maxattr = NFSD_A_SERVER_VERSION_STATUS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_VERSION_GET, + .dumpit = nfsd_nl_version_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {fs/nfsd/netlink.h +3
-0@@ -18,6 +18,9 @@ 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); +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;fs/nfsd/nfsctl.c +105
-0@@ -1757,6 +1757,111 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)return err; } +/** +* nfsd_nl_version_set_doit - enable/disable the provided nfs server version +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info) +{ +struct nfsd_net *nn =net_generic (genl_info_net (info), nfsd_net_id); +enum vers_op cmd; +u32 major, minor; +u8 status; +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MAJOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_MINOR ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_VERSION_STATUS )) +return -EINVAL ; + + major =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MAJOR ]); + minor =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_MINOR ]); + + status =nla_get_u32 (info->attrs[NFSD_A_SERVER_VERSION_STATUS ]); + cmd = !!status ?NFSD_SET :NFSD_CLEAR ; + +mutex_lock (&nfsd_mutex); +switch (major) { +case 4 : + ret =nfsd_minorversion (nn, minor, cmd); +break ; +case 2 : +case 3 : +if (!minor) { + ret =nfsd_vers (nn, major, cmd); +break ; + } + fallthrough; +default : + ret = -EINVAL ; +break ; + } +mutex_unlock (&nfsd_mutex); + +return ret; +} + +/** +* nfsd_nl_version_get_doit - Handle verion_get dumpit +* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_version_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb) +{ +struct nfsd_net *nn =net_generic (sock_net (skb->sk), nfsd_net_id); +int i, ret = -ENOMEM ; + +mutex_lock (&nfsd_mutex); + +for (i =2 ; i <=4 ; i++) { +int j; + +if (i < cb->args[0 ])/* already consumed */ +continue ; + +if (!nfsd_vers (nn, i,NFSD_AVAIL )) +continue ; + +for (j =0 ; j <=NFSD_SUPPORTED_MINOR_VERSION ; j++) { +void *hdr; + +if (!nfsd_vers (nn, i,NFSD_TEST )) +continue ; + +/* NFSv{2,3} does not support minor numbers */ +if (i <4 && j) +continue ; + +if (i ==4 && !nfsd_minorversion (nn, j,NFSD_TEST )) +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_VERSION_GET ); +if (!hdr) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MAJOR , i) || +nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MINOR , j)) + goto out; + +genlmsg_end (skb, hdr); + } + } + cb->args[0 ] = i; + ret = skb->len; +out: +mutex_unlock (&nfsd_mutex); + +return ret; +} +/** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace include/uapi/linux/nfsd_netlink.h +11
-0@@ -36,10 +36,21 @@ enum {NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX -1 ) }; +enum { +NFSD_A_SERVER_VERSION_MAJOR =1 , +NFSD_A_SERVER_VERSION_MINOR , +NFSD_A_SERVER_VERSION_STATUS , + + __NFSD_A_SERVER_VERSION_MAX, +NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET , +NFSD_CMD_VERSION_SET , +NFSD_CMD_VERSION_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )tools/net/ynl/generated/nfsd-user.c +81
-0@@ -17,6 +17,8 @@ static const char * const nfsd_op_strmap[] = { [NFSD_CMD_RPC_STATUS_GET] = "rpc-status-get", [NFSD_CMD_THREADS_SET] = "threads-set", [NFSD_CMD_THREADS_GET] = "threads-get", + [NFSD_CMD_VERSION_SET] = "version-set", + [NFSD_CMD_VERSION_GET] = "version-get", };const char *nfsd_op_str (int op)@@ -58,6 +60,17 @@ struct ynl_policy_nest nfsd_server_worker_nest = { .table = nfsd_server_worker_policy, }; +struct ynl_policy_attr nfsd_server_version_policy[NFSD_A_SERVER_VERSION_MAX +1 ] = { + [NFSD_A_SERVER_VERSION_MAJOR ] = { .name ="major" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_MINOR ] = { .name ="minor" , .type =YNL_PT_U32 , }, + [NFSD_A_SERVER_VERSION_STATUS ] = { .name ="status" , .type =YNL_PT_U8 , }, +}; + +struct ynl_policy_nest nfsd_server_version_nest = { + .max_attr =NFSD_A_SERVER_VERSION_MAX , + .table = nfsd_server_version_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -290,6 +303,74 @@ struct nfsd_threads_get_rsp *nfsd_threads_get(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +void nfsd_version_set_req_free (struct nfsd_version_set_req *req) +{ +free (req); +} + +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_VERSION_SET ,1 ); + ys->req_policy = &nfsd_server_version_nest; + +if (req->_present.major) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MAJOR , req->major); +if (req->_present.minor) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_VERSION_MINOR , req->minor); +if (req->_present.status) +mnl_attr_put_u8 (nlh,NFSD_A_SERVER_VERSION_STATUS , req->status); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp) +{ +struct nfsd_version_get_list *next = rsp; + +while ((void *)next !=YNL_LIST_END ) { + rsp = next; + next = rsp->next; + +free (rsp); + } +} + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys) +{ +struct ynl_dump_state yds = {}; +struct nlmsghdr *nlh; +int err; + + yds.ys = ys; + yds.alloc_sz =sizeof (struct nfsd_version_get_list ); + yds.cb = nfsd_version_get_rsp_parse; + yds.rsp_cmd =NFSD_CMD_VERSION_GET ; + yds.rsp_policy = &nfsd_server_version_nest; + + nlh =ynl_gemsg_start_dump (ys, ys->family_id,NFSD_CMD_VERSION_GET ,1 ); + + err =ynl_exec_dump (ys, nlh, &yds); +if (err <0 ) + goto free_list; + +return yds.first; + +free_list: +nfsd_version_get_list_free (yds.first); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +4
-0@@ -111,4 +111,59 @@ void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp);*/ struct nfsd_threads_get_rsp *nfsd_threads_get (struct ynl_sock *ys); +/* ============== NFSD_CMD_VERSION_SET ============== */ +/* NFSD_CMD_VERSION_SET - do */ +struct nfsd_version_set_req { + struct {tools/net/ynl/generated/nfsd-user.h void nfsd_threads_get_rsp_free(struct nfsd_threads_get_rsp *rsp); · line 127
Quoted 10 lines
tools/net/ynl/generated/nfsd-user.h +10
-0+ __u32 major:1; + __u32 minor:1; + __u32 status:1; + } _present; + +__u32 major; +__u32 minor; +__u8 status; +}; +This more or less mirrors how the "versions" file works today, but that interface is quite klunky. We don't have a use case that requires that we do this piecemeal like this. I think we'd be better served with a more declarative interface that reconfigures the supported versions in one shot:
Instead of having "major,minor,status" and potentially having to call this command several times from userland, it seems like it would be nicer to just have userland send down a list "major,minor" that should be enabled, and then just let the kernel figure out whether to enable or disable each. An empty list could mean "disable everything".
Quoted 3 lines
That's simpler to reason out as an interface from userland too. Trying to keep track of the enabled and disabled versions and twiddle it is really tricky in rpc.nfsd today.
Jeff and Lorenzo, this sounds to me like a useful and narrow improvement to this interface, one that should be implemented as part of this patch series.
Quoted 6 lines
Quoted 2 lines
ack, I am fine with it, I will work on patch 2/3 and 3/3. @Chuck: am I suppose to respin patch 1/3 too?
I assumed there might be minor changes to 1/3 after Jakub's second review, so I have not applied it yet. You can resend all three to me.
iirc jakub's review was just for patch 2/3, anyway up to you.
Regards,
Lorenzo
Quoted 63 lines
Quoted 58 lines
Regards,
LorenzoQuoted 53 lines
Ditto for Jeff's review comment on 3/3.
Quoted 46 lines
Quoted 42 lines
tools/net/ynl/generated/nfsd-user.h +41
-0+static inline struct nfsd_version_set_req *nfsd_version_set_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_version_set_req )); +} +void nfsd_version_set_req_free (struct nfsd_version_set_req *req); + +static inline void +nfsd_version_set_req_set_major (struct nfsd_version_set_req *req,__u32 major) +{ + req->_present.major =1 ; + req->major = major; +} +static inline void +nfsd_version_set_req_set_minor (struct nfsd_version_set_req *req,__u32 minor) +{ + req->_present.minor =1 ; + req->minor = minor; +} +static inline void +nfsd_version_set_req_set_status (struct nfsd_version_set_req *req,__u8 status) +{ + req->_present.status =1 ; + req->status = status; +} + +/* +* enable/disable server version +*/ +int nfsd_version_set (struct ynl_sock *ys,struct nfsd_version_set_req *req); + +/* ============== NFSD_CMD_VERSION_GET ============== */ +/* NFSD_CMD_VERSION_GET - dump */ +struct nfsd_version_get_list { +struct nfsd_version_get_list *next; +struct nfsd_version_get_rsp obj __attribute__ ((aligned (8 ))); +}; + +void nfsd_version_get_list_free (struct nfsd_version_get_list *rsp); + +struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */ Signature · 1 line
Jeff Layton <[email protected]>Signature · 1 line
Chuck LeverSignature · 1 line
Chuck Lever
Jakub Kicinski
maintainerRe: [PATCH v5 2/3] NFSD: convert write_version to netlink command
In reply to Lorenzo BianconiDocumentation/netlink/specs/nfsd.yaml attribute-sets: · line 82
Quoted 3 lines · On Wed, 29 Nov 2023 18:12:44 +0100 Lorenzo Bianconi wrote:
Documentation/netlink/specs/nfsd.yaml +3
-0+ - + name: status + type: u8
u8? I guess...
Quoted 2 lines
+/**
+ *nfsd_nl_version_get_doit- Handleverion_getdumpit
doesn't match the function name (do -> dump)
fs/nfsd/nfsctl.c int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info) · line 1846
Quoted 10 lines
fs/nfsd/nfsctl.c +10
-0+/* NFSv{2,3} does not support minor numbers */ +if (i <4 && j) +continue ; + +if (i ==4 && !nfsd_minorversion (nn, j,NFSD_TEST )) +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_VERSION_GET );
Why not iput()?
Quoted 10 lines
fs/nfsd/nfsctl.c +10
-0+if (!hdr) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MAJOR , i) || +nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MINOR , j)) + goto out; + +genlmsg_end (skb, hdr); + } + }
Re: [PATCH v5 2/3] NFSD: convert write_version to netlink command
Quoted 6 lines · On Wed, 29 Nov 2023 18:12:44 +0100 Lorenzo Bianconi wrote:
Documentation/netlink/specs/nfsd.yaml attribute-sets: · line 82
Quoted 3 lines
Documentation/netlink/specs/nfsd.yaml +3
-0+ - + name: status + type: u8u8? I guess...
here we need just 0 or 1 I would say. Do you suggest create something like an enum?
Quoted 4 lines
Quoted 2 lines
+/**
+ *nfsd_nl_version_get_doit- Handleverion_getdumpitdoesn't match the function name (do -> dump)
ack, I will fix it.
Quoted 13 lines
fs/nfsd/nfsctl.c int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info) · line 1846
Quoted 11 lines
fs/nfsd/nfsctl.c +10
-0+/* NFSv{2,3} does not support minor numbers */ +if (i <4 && j) +continue ; + +if (i ==4 && !nfsd_minorversion (nn, j,NFSD_TEST )) +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_VERSION_GET );Why not
iput()?
ack, I will fix it.
Regards,
Lorenzo
Quoted 12 lines
Quoted 11 lines
fs/nfsd/nfsctl.c +10
-0+if (!hdr) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MAJOR , i) || +nla_put_u32 (skb,NFSD_A_SERVER_VERSION_MINOR , j)) + goto out; + +genlmsg_end (skb, hdr); + } + }
Jakub Kicinski
maintainerRe: [PATCH v5 2/3] NFSD: convert write_version to netlink command
Quoted 4 lines · On Thu, 30 Nov 2023 11:32:17 +0100 Lorenzo Bianconi wrote:
Quoted 1 line
u8? I guess...
here we need just 0 or 1 I would say. Do you suggest create something like an enum?
Ah, sorry, thought I must have already complained to you about this in the past - netlink aligns everything to 4B. So u8 or u16 or u32 it's all the same size at the message level. For the <u32 types some bytes are just treated as padding instead of being useful.
But if you explicitly need only 0/1 then it doesn't matter.
Simon Horman
reviewerRe: [PATCH v5 2/3] NFSD: convert write_version to netlink command
In reply to Lorenzo BianconiQuoted 4 lines · Lorenzo Bianconi
Introduce
write_versionnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>
...
Quoted 2 lines
+/**
+ *nfsd_nl_version_get_doit- Handleverion_getdumpit
Hi Lorenzo,
a minor nit: this function is nfsd_nl_version_get_dumpit
Quoted 6 lines
+ * @skb: reply buffer
+ * @cb: netlink metadata and command arguments
+ *
+ * Returns the size of the reply or a negative errno.
+ */
+int nfsd_nl_version_get_dumpit(structsk_buff*skb,
...
PATCH v5 3/3 NFSD: convert write_ports to netlink command
In reply to Lorenzo BianconiIntroduce write_ports netlink command similar to the ones available through the procfs.
--- Documentation/netlink/specs/nfsd.yaml | 28 +++++++ fs/nfsd/netlink.c | 18 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 104 ++++++++++++++++++++++++-- include/uapi/linux/nfsd_netlink.h | 10 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 54 +++++++++++++ 7 files changed, 291 insertions(+), 7 deletions(-)
Documentation/netlink/specs/nfsd.yaml +28 -0
@@ -80,6 +80,15 @@ attribute-sets: - name: status type: u8 + - + name: server-listener + attributes: + - + name: transport-name + type: string + - + name: port + type: u32 operations: list:
@@ -142,3 +151,22 @@ operations: attributes: - major - minor + - + name: listener-start + doc: start server listener + attribute-set: server-listener + flags: [ admin-perm ] + do: + request: + attributes: + - transport-name + - port + - + name: listener-get + doc: dump server listeners + attribute-set: server-listener + dump: + reply: + attributes: + - transport-name + - port
fs/nfsd/netlink.c +18 -0
@@ -22,6 +22,12 @@ static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_ [NFSD_A_SERVER_VERSION_STATUS] = { .type = NLA_U8, }, }; +/* NFSD_CMD_LISTENER_START - do */ +static const struct nla_policy nfsd_listener_start_nl_policy[NFSD_A_SERVER_LISTENER_PORT +1 ] = { + [NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ] = { .type =NLA_NUL_STRING , }, + [NFSD_A_SERVER_LISTENER_PORT ] = { .type =NLA_U32 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {
@@ -55,6 +61,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .dumpit = nfsd_nl_version_get_dumpit, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = NFSD_CMD_LISTENER_START, + .doit = nfsd_nl_listener_start_doit, + .policy = nfsd_listener_start_nl_policy, + .maxattr = NFSD_A_SERVER_LISTENER_PORT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_LISTENER_GET, + .dumpit = nfsd_nl_listener_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {
fs/nfsd/netlink.h +3 -0
@@ -21,6 +21,9 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info);int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info);int nfsd_nl_version_get_dumpit (struct sk_buff *skb,struct netlink_callback *cb); +int nfsd_nl_listener_start_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_listener_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;
fs/nfsd/nfsctl.c +97 -7
127 lines not on this page · raw message
include/uapi/linux/nfsd_netlink.h +10 -0
@@ -45,12 +45,22 @@ enum {NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) }; +enum { +NFSD_A_SERVER_LISTENER_TRANSPORT_NAME =1 , +NFSD_A_SERVER_LISTENER_PORT , + + __NFSD_A_SERVER_LISTENER_MAX, +NFSD_A_SERVER_LISTENER_MAX = (__NFSD_A_SERVER_LISTENER_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET ,NFSD_CMD_VERSION_SET ,NFSD_CMD_VERSION_GET , +NFSD_CMD_LISTENER_START , +NFSD_CMD_LISTENER_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )
tools/net/ynl/generated/nfsd-user.c +81 -0
99 lines not on this page · raw message
tools/net/ynl/generated/nfsd-user.h +54 -0
58 lines not on this page · raw message
Signature · 1 line
2.43.0
Jeff Layton
maintainerRe: [PATCH v5 3/3] NFSD: convert write_ports to netlink command
Quoted 383 lines · Lorenzo Bianconi
Introduce
write_portsnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 28 +++++++ fs/nfsd/netlink.c | 18 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 104 ++++++++++++++++++++++++-- include/uapi/linux/nfsd_netlink.h | 10 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 54 +++++++++++++ 7 files changed, 291 insertions(+), 7 deletions(-)Documentation/netlink/specs/nfsd.yaml +28
-0@@ -80,6 +80,15 @@ attribute-sets: - name: status type: u8 + - + name: server-listener + attributes: + - + name: transport-name + type: string + - + name: port + type: u32 operations: list:@@ -142,3 +151,22 @@ operations: attributes: - major - minor + - + name: listener-start + doc: start server listener + attribute-set: server-listener + flags: [ admin-perm ] + do: + request: + attributes: + - transport-name + - port + - + name: listener-get + doc: dump server listeners + attribute-set: server-listener + dump: + reply: + attributes: + - transport-name + - portfs/nfsd/netlink.c +18
-0@@ -22,6 +22,12 @@ static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_ [NFSD_A_SERVER_VERSION_STATUS] = { .type = NLA_U8, }, }; +/* NFSD_CMD_LISTENER_START - do */ +static const struct nla_policy nfsd_listener_start_nl_policy[NFSD_A_SERVER_LISTENER_PORT +1 ] = { + [NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ] = { .type =NLA_NUL_STRING , }, + [NFSD_A_SERVER_LISTENER_PORT ] = { .type =NLA_U32 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -55,6 +61,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .dumpit = nfsd_nl_version_get_dumpit, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = NFSD_CMD_LISTENER_START, + .doit = nfsd_nl_listener_start_doit, + .policy = nfsd_listener_start_nl_policy, + .maxattr = NFSD_A_SERVER_LISTENER_PORT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_LISTENER_GET, + .dumpit = nfsd_nl_listener_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {fs/nfsd/netlink.h +3
-0@@ -21,6 +21,9 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info);int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info);int nfsd_nl_version_get_dumpit (struct sk_buff *skb,struct netlink_callback *cb); +int nfsd_nl_listener_start_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_listener_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;fs/nfsd/nfsctl.c +97
-7@@ -721,18 +721,16 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred* A transport listener is added by writing its transport name and * a port number. */ -static ssize_t __write_ports_addxprt (char *buf,struct net *net,const struct cred *cred) +static ssize_t ___write_ports_addxprt (struct net *net,const struct cred *cred, +const char *transport,const int port) { -char transport[16 ]; -struct svc_xprt *xprt; -int port, err;struct nfsd_net *nn =net_generic (net, nfsd_net_id); - -if (sscanf (buf,"%15s %5u" , transport, &port) !=2 ) -return -EINVAL ; +struct svc_xprt *xprt; +int err;if (port <1 || port >USHRT_MAX )return -EINVAL ; +trace_nfsd_ctl_ports_addxprt (net, transport, port); err =nfsd_create_serv (net);@@ -765,6 +763,17 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct crreturn err; } +static ssize_t __write_ports_addxprt (char *buf,struct net *net,const struct cred *cred) +{ +char transport[16 ]; +int port; + +if (sscanf (buf,"%15s %5u" , transport, &port) !=2 ) +return -EINVAL ; + +return ___write_ports_addxprt (net, cred, transport, port); +} +static ssize_t __write_ports (struct file *file,char *buf,size_t size,struct net *net) {@@ -1862,6 +1871,87 @@ int nfsd_nl_version_get_dumpit(struct sk_buff *skb,return ret; } +/** +* nfsd_nl_listener_start_doit - start the provided nfs server listener +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_listener_start_doit (struct sk_buff *skb,struct genl_info *info) +{ +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_LISTENER_PORT )) +return -EINVAL ; + +mutex_lock (&nfsd_mutex); + ret =___write_ports_addxprt (genl_info_net (info),get_current_cred (), +nla_data (info->attrs[NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ]), +nla_get_u32 (info->attrs[NFSD_A_SERVER_LISTENER_PORT ])); +mutex_unlock (&nfsd_mutex); + +return 0 ; +} + +/** +* nfsd_nl_version_get_dumpit - Handle listener_get dumpit +* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_listener_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb) +{ +struct nfsd_net *nn =net_generic (sock_net (skb->sk), nfsd_net_id); +int i =0 , ret = -ENOMEM ; +struct svc_xprt *xprt; +struct svc_serv *serv; + +mutex_lock (&nfsd_mutex); + + serv = nn->nfsd_serv; +if (!serv) { +mutex_unlock (&nfsd_mutex); +return 0 ; + } + +spin_lock_bh (&serv->sv_lock); +list_for_each_entry (xprt, &serv->sv_permsocks, xpt_list) { +void *hdr; + +if (i < cb->args[0 ])/* already consumed */ +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_LISTENER_GET ); +if (!hdr) + goto out; + +if (nla_put_string (skb,NFSD_A_SERVER_LISTENER_TRANSPORT_NAME , + xprt->xpt_class->xcl_name)) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_LISTENER_PORT , +svc_xprt_local_port (xprt))) + goto out; + +genlmsg_end (skb, hdr); + i++; + } + cb->args[0 ] = i; + ret = skb->len; +out: +spin_unlock_bh (&serv->sv_lock); + +mutex_unlock (&nfsd_mutex); + +return ret; +} +/** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace include/uapi/linux/nfsd_netlink.h +10
-0@@ -45,12 +45,22 @@ enum {NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) }; +enum { +NFSD_A_SERVER_LISTENER_TRANSPORT_NAME =1 , +NFSD_A_SERVER_LISTENER_PORT , + + __NFSD_A_SERVER_LISTENER_MAX, +NFSD_A_SERVER_LISTENER_MAX = (__NFSD_A_SERVER_LISTENER_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET ,NFSD_CMD_VERSION_SET ,NFSD_CMD_VERSION_GET , +NFSD_CMD_LISTENER_START , +NFSD_CMD_LISTENER_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )tools/net/ynl/generated/nfsd-user.c +81
-0@@ -19,6 +19,8 @@ static const char * const nfsd_op_strmap[] = { [NFSD_CMD_THREADS_GET] = "threads-get", [NFSD_CMD_VERSION_SET] = "version-set", [NFSD_CMD_VERSION_GET] = "version-get", + [NFSD_CMD_LISTENER_START] = "listener-start", + [NFSD_CMD_LISTENER_GET] = "listener-get", };const char *nfsd_op_str (int op)@@ -71,6 +73,16 @@ struct ynl_policy_nest nfsd_server_version_nest = { .table = nfsd_server_version_policy, }; +struct ynl_policy_attr nfsd_server_listener_policy[NFSD_A_SERVER_LISTENER_MAX +1 ] = { + [NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ] = { .name ="transport-name" , .type =YNL_PT_NUL_STR , }, + [NFSD_A_SERVER_LISTENER_PORT ] = { .name ="port" , .type =YNL_PT_U32 , }, +}; + +struct ynl_policy_nest nfsd_server_listener_nest = { + .max_attr =NFSD_A_SERVER_LISTENER_MAX , + .table = nfsd_server_listener_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -371,6 +383,75 @@ struct nfsd_version_get_list *nfsd_version_get_dump(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_LISTENER_START ============== */ +/* NFSD_CMD_LISTENER_START - do */ +void nfsd_listener_start_req_free (struct nfsd_listener_start_req *req) +{ +free (req->transport_name); +free (req); +} + +int nfsd_listener_start (struct ynl_sock *ys, +struct nfsd_listener_start_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_LISTENER_START ,1 ); + ys->req_policy = &nfsd_server_listener_nest; + +if (req->_present.transport_name_len) +mnl_attr_put_strz (nlh,NFSD_A_SERVER_LISTENER_TRANSPORT_NAME , req->transport_name); +if (req->_present.port) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_LISTENER_PORT , req->port); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_LISTENER_GET ============== */ +/* NFSD_CMD_LISTENER_GET - dump */ +void nfsd_listener_get_list_free (struct nfsd_listener_get_list *rsp) +{ +struct nfsd_listener_get_list *next = rsp; + +while ((void *)next !=YNL_LIST_END ) { + rsp = next; + next = rsp->next; + +free (rsp->obj.transport_name); +free (rsp); + } +} + +struct nfsd_listener_get_list *nfsd_listener_get_dump (struct ynl_sock *ys) +{ +struct ynl_dump_state yds = {}; +struct nlmsghdr *nlh; +int err; + + yds.ys = ys; + yds.alloc_sz =sizeof (struct nfsd_listener_get_list ); + yds.cb = nfsd_listener_get_rsp_parse; + yds.rsp_cmd =NFSD_CMD_LISTENER_GET ; + yds.rsp_policy = &nfsd_server_listener_nest; + + nlh =ynl_gemsg_start_dump (ys, ys->family_id,NFSD_CMD_LISTENER_GET ,1 ); + + err =ynl_exec_dump (ys, nlh, &yds); +if (err <0 ) + goto free_list; + +return yds.first; + +free_list: +nfsd_listener_get_list_free (yds.first); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +1
-0@@ -166,4 +166,58 @@ void nfsd_version_get_list_free(struct nfsd_version_get_list *rsp);struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys); +/* ============== NFSD_CMD_LISTENER_START ============== */
tools/net/ynl/generated/nfsd-user.h void nfsd_version_get_list_free(struct nfsd_version_get_list *rsp); · line 179
Quoted 10 lines
tools/net/ynl/generated/nfsd-user.h +10
-0+/* NFSD_CMD_LISTENER_START - do */ +struct nfsd_listener_start_req { +struct { +__u32 transport_name_len; +__u32 port:1 ; + } _present; + +char *transport_name; +__u32 port; +};
How do you deconfigure a listener with this interface? i.e. suppose I want to stop nfsd from listening on a particular port? I think this too is a place where a declarative interface would be better:
Have userland send down a list of the ports that we should currently be listening on, and let the kernel do the work to match the request. Again too, an empty list could mean "close everything".
Quoted 44 lines
tools/net/ynl/generated/nfsd-user.h +43
-0+ +static inline struct nfsd_listener_start_req * +nfsd_listener_start_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_listener_start_req )); +} +void nfsd_listener_start_req_free (struct nfsd_listener_start_req *req); + +static inline void +nfsd_listener_start_req_set_transport_name (struct nfsd_listener_start_req *req, +const char *transport_name) +{ +free (req->transport_name); + req->_present.transport_name_len =strlen (transport_name); + req->transport_name =malloc (req->_present.transport_name_len +1 ); +memcpy (req->transport_name, transport_name, req->_present.transport_name_len); + req->transport_name[req->_present.transport_name_len] =0 ; +} +static inline void +nfsd_listener_start_req_set_port (struct nfsd_listener_start_req *req, +__u32 port) +{ + req->_present.port =1 ; + req->port = port; +} + +/* +* start server listener +*/ +int nfsd_listener_start (struct ynl_sock *ys, +struct nfsd_listener_start_req *req); + +/* ============== NFSD_CMD_LISTENER_GET ============== */ +/* NFSD_CMD_LISTENER_GET - dump */ +struct nfsd_listener_get_list { +struct nfsd_listener_get_list *next; +struct nfsd_listener_get_rsp obj __attribute__ ((aligned (8 ))); +}; + +void nfsd_listener_get_list_free (struct nfsd_listener_get_list *rsp); + +struct nfsd_listener_get_list *nfsd_listener_get_dump (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v5 3/3] NFSD: convert write_ports to netlink command
Quoted 383 lines · Lorenzo Bianconi
Quoted 382 lines
Introduce
write_portsnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>--- Documentation/netlink/specs/nfsd.yaml | 28 +++++++ fs/nfsd/netlink.c | 18 +++++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 104 ++++++++++++++++++++++++-- include/uapi/linux/nfsd_netlink.h | 10 +++ tools/net/ynl/generated/nfsd-user.c | 81 ++++++++++++++++++++ tools/net/ynl/generated/nfsd-user.h | 54 +++++++++++++ 7 files changed, 291 insertions(+), 7 deletions(-)Documentation/netlink/specs/nfsd.yaml +28
-0@@ -80,6 +80,15 @@ attribute-sets: - name: status type: u8 + - + name: server-listener + attributes: + - + name: transport-name + type: string + - + name: port + type: u32 operations: list:@@ -142,3 +151,22 @@ operations: attributes: - major - minor + - + name: listener-start + doc: start server listener + attribute-set: server-listener + flags: [ admin-perm ] + do: + request: + attributes: + - transport-name + - port + - + name: listener-get + doc: dump server listeners + attribute-set: server-listener + dump: + reply: + attributes: + - transport-name + - portfs/nfsd/netlink.c +18
-0@@ -22,6 +22,12 @@ static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_VERSION_ [NFSD_A_SERVER_VERSION_STATUS] = { .type = NLA_U8, }, }; +/* NFSD_CMD_LISTENER_START - do */ +static const struct nla_policy nfsd_listener_start_nl_policy[NFSD_A_SERVER_LISTENER_PORT +1 ] = { + [NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ] = { .type =NLA_NUL_STRING , }, + [NFSD_A_SERVER_LISTENER_PORT ] = { .type =NLA_U32 , }, +}; +/* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { {@@ -55,6 +61,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .dumpit = nfsd_nl_version_get_dumpit, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = NFSD_CMD_LISTENER_START, + .doit = nfsd_nl_listener_start_doit, + .policy = nfsd_listener_start_nl_policy, + .maxattr = NFSD_A_SERVER_LISTENER_PORT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_LISTENER_GET, + .dumpit = nfsd_nl_listener_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, }; struct genl_family nfsd_nl_family __ro_after_init = {fs/nfsd/netlink.h +3
-0@@ -21,6 +21,9 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info);int nfsd_nl_version_set_doit (struct sk_buff *skb,struct genl_info *info);int nfsd_nl_version_get_dumpit (struct sk_buff *skb,struct netlink_callback *cb); +int nfsd_nl_listener_start_doit (struct sk_buff *skb,struct genl_info *info); +int nfsd_nl_listener_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb);extern struct genl_family nfsd_nl_family;fs/nfsd/nfsctl.c +97
-7@@ -721,18 +721,16 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred* A transport listener is added by writing its transport name and * a port number. */ -static ssize_t __write_ports_addxprt (char *buf,struct net *net,const struct cred *cred) +static ssize_t ___write_ports_addxprt (struct net *net,const struct cred *cred, +const char *transport,const int port) { -char transport[16 ]; -struct svc_xprt *xprt; -int port, err;struct nfsd_net *nn =net_generic (net, nfsd_net_id); - -if (sscanf (buf,"%15s %5u" , transport, &port) !=2 ) -return -EINVAL ; +struct svc_xprt *xprt; +int err;if (port <1 || port >USHRT_MAX )return -EINVAL ; +trace_nfsd_ctl_ports_addxprt (net, transport, port); err =nfsd_create_serv (net);@@ -765,6 +763,17 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct crreturn err; } +static ssize_t __write_ports_addxprt (char *buf,struct net *net,const struct cred *cred) +{ +char transport[16 ]; +int port; + +if (sscanf (buf,"%15s %5u" , transport, &port) !=2 ) +return -EINVAL ; + +return ___write_ports_addxprt (net, cred, transport, port); +} +static ssize_t __write_ports (struct file *file,char *buf,size_t size,struct net *net) {@@ -1862,6 +1871,87 @@ int nfsd_nl_version_get_dumpit(struct sk_buff *skb,return ret; } +/** +* nfsd_nl_listener_start_doit - start the provided nfs server listener +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_listener_start_doit (struct sk_buff *skb,struct genl_info *info) +{ +int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_LISTENER_PORT )) +return -EINVAL ; + +mutex_lock (&nfsd_mutex); + ret =___write_ports_addxprt (genl_info_net (info),get_current_cred (), +nla_data (info->attrs[NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ]), +nla_get_u32 (info->attrs[NFSD_A_SERVER_LISTENER_PORT ])); +mutex_unlock (&nfsd_mutex); + +return 0 ; +} + +/** +* nfsd_nl_version_get_dumpit - Handle listener_get dumpit +* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_listener_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb) +{ +struct nfsd_net *nn =net_generic (sock_net (skb->sk), nfsd_net_id); +int i =0 , ret = -ENOMEM ; +struct svc_xprt *xprt; +struct svc_serv *serv; + +mutex_lock (&nfsd_mutex); + + serv = nn->nfsd_serv; +if (!serv) { +mutex_unlock (&nfsd_mutex); +return 0 ; + } + +spin_lock_bh (&serv->sv_lock); +list_for_each_entry (xprt, &serv->sv_permsocks, xpt_list) { +void *hdr; + +if (i < cb->args[0 ])/* already consumed */ +continue ; + + hdr =genlmsg_put (skb,NETLINK_CB (cb->skb).portid, + cb->nlh->nlmsg_seq, &nfsd_nl_family, +0 ,NFSD_CMD_LISTENER_GET ); +if (!hdr) + goto out; + +if (nla_put_string (skb,NFSD_A_SERVER_LISTENER_TRANSPORT_NAME , + xprt->xpt_class->xcl_name)) + goto out; + +if (nla_put_u32 (skb,NFSD_A_SERVER_LISTENER_PORT , +svc_xprt_local_port (xprt))) + goto out; + +genlmsg_end (skb, hdr); + i++; + } + cb->args[0 ] = i; + ret = skb->len; +out: +spin_unlock_bh (&serv->sv_lock); + +mutex_unlock (&nfsd_mutex); + +return ret; +} +/** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace include/uapi/linux/nfsd_netlink.h +10
-0@@ -45,12 +45,22 @@ enum {NFSD_A_SERVER_VERSION_MAX = (__NFSD_A_SERVER_VERSION_MAX -1 ) }; +enum { +NFSD_A_SERVER_LISTENER_TRANSPORT_NAME =1 , +NFSD_A_SERVER_LISTENER_PORT , + + __NFSD_A_SERVER_LISTENER_MAX, +NFSD_A_SERVER_LISTENER_MAX = (__NFSD_A_SERVER_LISTENER_MAX -1 ) +}; +enum {NFSD_CMD_RPC_STATUS_GET =1 ,NFSD_CMD_THREADS_SET ,NFSD_CMD_THREADS_GET ,NFSD_CMD_VERSION_SET ,NFSD_CMD_VERSION_GET , +NFSD_CMD_LISTENER_START , +NFSD_CMD_LISTENER_GET , __NFSD_CMD_MAX,NFSD_CMD_MAX = (__NFSD_CMD_MAX -1 )tools/net/ynl/generated/nfsd-user.c +81
-0@@ -19,6 +19,8 @@ static const char * const nfsd_op_strmap[] = { [NFSD_CMD_THREADS_GET] = "threads-get", [NFSD_CMD_VERSION_SET] = "version-set", [NFSD_CMD_VERSION_GET] = "version-get", + [NFSD_CMD_LISTENER_START] = "listener-start", + [NFSD_CMD_LISTENER_GET] = "listener-get", };const char *nfsd_op_str (int op)@@ -71,6 +73,16 @@ struct ynl_policy_nest nfsd_server_version_nest = { .table = nfsd_server_version_policy, }; +struct ynl_policy_attr nfsd_server_listener_policy[NFSD_A_SERVER_LISTENER_MAX +1 ] = { + [NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ] = { .name ="transport-name" , .type =YNL_PT_NUL_STR , }, + [NFSD_A_SERVER_LISTENER_PORT ] = { .name ="port" , .type =YNL_PT_U32 , }, +}; + +struct ynl_policy_nest nfsd_server_listener_nest = { + .max_attr =NFSD_A_SERVER_LISTENER_MAX , + .table = nfsd_server_listener_policy, +}; +/* Common nested types */ /* ============== NFSD_CMD_RPC_STATUS_GET ============== */ /* NFSD_CMD_RPC_STATUS_GET - dump */ @@ -371,6 +383,75 @@ struct nfsd_version_get_list *nfsd_version_get_dump(struct ynl_sock *ys)return NULL ; } +/* ============== NFSD_CMD_LISTENER_START ============== */ +/* NFSD_CMD_LISTENER_START - do */ +void nfsd_listener_start_req_free (struct nfsd_listener_start_req *req) +{ +free (req->transport_name); +free (req); +} + +int nfsd_listener_start (struct ynl_sock *ys, +struct nfsd_listener_start_req *req) +{ +struct nlmsghdr *nlh; +int err; + + nlh =ynl_gemsg_start_req (ys, ys->family_id,NFSD_CMD_LISTENER_START ,1 ); + ys->req_policy = &nfsd_server_listener_nest; + +if (req->_present.transport_name_len) +mnl_attr_put_strz (nlh,NFSD_A_SERVER_LISTENER_TRANSPORT_NAME , req->transport_name); +if (req->_present.port) +mnl_attr_put_u32 (nlh,NFSD_A_SERVER_LISTENER_PORT , req->port); + + err =ynl_exec (ys, nlh,NULL ); +if (err <0 ) +return -1 ; + +return 0 ; +} + +/* ============== NFSD_CMD_LISTENER_GET ============== */ +/* NFSD_CMD_LISTENER_GET - dump */ +void nfsd_listener_get_list_free (struct nfsd_listener_get_list *rsp) +{ +struct nfsd_listener_get_list *next = rsp; + +while ((void *)next !=YNL_LIST_END ) { + rsp = next; + next = rsp->next; + +free (rsp->obj.transport_name); +free (rsp); + } +} + +struct nfsd_listener_get_list *nfsd_listener_get_dump (struct ynl_sock *ys) +{ +struct ynl_dump_state yds = {}; +struct nlmsghdr *nlh; +int err; + + yds.ys = ys; + yds.alloc_sz =sizeof (struct nfsd_listener_get_list ); + yds.cb = nfsd_listener_get_rsp_parse; + yds.rsp_cmd =NFSD_CMD_LISTENER_GET ; + yds.rsp_policy = &nfsd_server_listener_nest; + + nlh =ynl_gemsg_start_dump (ys, ys->family_id,NFSD_CMD_LISTENER_GET ,1 ); + + err =ynl_exec_dump (ys, nlh, &yds); +if (err <0 ) + goto free_list; + +return yds.first; + +free_list: +nfsd_listener_get_list_free (yds.first); +return NULL ; +} +const struct ynl_family ynl_nfsd_family = { .name ="nfsd" , };tools/net/ynl/generated/nfsd-user.h +0
-0@@ -166,4 +166,58 @@ void nfsd_version_get_list_free(struct nfsd_version_get_list *rsp);struct nfsd_version_get_list *nfsd_version_get_dump (struct ynl_sock *ys);
Quoted 15 lines
tools/net/ynl/generated/nfsd-user.h void nfsd_version_get_list_free(struct nfsd_version_get_list *rsp); · line 179
Quoted 11 lines
tools/net/ynl/generated/nfsd-user.h +11
-0+/* ============== NFSD_CMD_LISTENER_START ============== */ +/* NFSD_CMD_LISTENER_START - do */ +struct nfsd_listener_start_req { +struct { +__u32 transport_name_len; +__u32 port:1 ; + } _present; + +char *transport_name; +__u32 port; +};How do you deconfigure a listener with this interface? i.e. suppose I want to stop nfsd from listening on a particular port? I think this too is a place where a declarative interface would be better:
Is it possible with current APIs? as for 2/3 so far I have just added netlink counter for current implementation but I am fine to change the logic here to better APIs.
Regards,
Lorenzo
Quoted 53 lines
Have userland send down a list of the ports that we should currently be listening on, and let the kernel do the work to match the request. Again too, an empty list could mean "close everything".
Quoted 44 lines
tools/net/ynl/generated/nfsd-user.h +43
-0+ +static inline struct nfsd_listener_start_req * +nfsd_listener_start_req_alloc (void ) +{ +return calloc (1 ,sizeof (struct nfsd_listener_start_req )); +} +void nfsd_listener_start_req_free (struct nfsd_listener_start_req *req); + +static inline void +nfsd_listener_start_req_set_transport_name (struct nfsd_listener_start_req *req, +const char *transport_name) +{ +free (req->transport_name); + req->_present.transport_name_len =strlen (transport_name); + req->transport_name =malloc (req->_present.transport_name_len +1 ); +memcpy (req->transport_name, transport_name, req->_present.transport_name_len); + req->transport_name[req->_present.transport_name_len] =0 ; +} +static inline void +nfsd_listener_start_req_set_port (struct nfsd_listener_start_req *req, +__u32 port) +{ + req->_present.port =1 ; + req->port = port; +} + +/* +* start server listener +*/ +int nfsd_listener_start (struct ynl_sock *ys, +struct nfsd_listener_start_req *req); + +/* ============== NFSD_CMD_LISTENER_GET ============== */ +/* NFSD_CMD_LISTENER_GET - dump */ +struct nfsd_listener_get_list { +struct nfsd_listener_get_list *next; +struct nfsd_listener_get_rsp obj __attribute__ ((aligned (8 ))); +}; + +void nfsd_listener_get_list_free (struct nfsd_listener_get_list *rsp); + +struct nfsd_listener_get_list *nfsd_listener_get_dump (struct ynl_sock *ys); +#endif /* _LINUX_NFSD_GEN_H */ Signature · 1 line
Jeff Layton <[email protected]>
Jeff Layton
maintainerRe: [PATCH v5 3/3] NFSD: convert write_ports to netlink command
Quoted 17 lines · Lorenzo Bianconi
Quoted 16 lines
tools/net/ynl/generated/nfsd-user.h void nfsd_version_get_list_free(struct nfsd_version_get_list *rsp); · line 179
Quoted 12 lines
tools/net/ynl/generated/nfsd-user.h +11
-0+/* ============== NFSD_CMD_LISTENER_START ============== */ +/* NFSD_CMD_LISTENER_START - do */ +struct nfsd_listener_start_req { +struct { +__u32 transport_name_len; +__u32 port:1 ; + } _present; + +char *transport_name; +__u32 port; +};How do you deconfigure a listener with this interface? i.e. suppose I want to stop nfsd from listening on a particular port? I think this too is a place where a declarative interface would be better:
Quoted 5 lines
Is it possible with current APIs? as for 2/3 so far I have just added netlink counter for current implementation but I am fine to change the logic here to better APIs.
Quoted 1 line
No, I don't think you can do this with the current API at all. I consider it a major deficiency. I don't think we want to repeat that mistake in the new interface.
Quoted 5 lines
Quoted 5 lines
Have userland send down a list of the ports that we should currently be listening on, and let the kernel do the work to match the request. Again too, an empty list could mean "close everything".
Signature · 1 line
Jeff Layton <[email protected]>
Jeff Layton
maintainerRe: [PATCH v5 3/3] NFSD: convert write_ports to netlink command
Quoted 24 lines · Jeff Layton
Quoted 17 lines · Lorenzo Bianconi
Quoted 16 lines
tools/net/ynl/generated/nfsd-user.h void nfsd_version_get_list_free(struct nfsd_version_get_list *rsp); · line 179
Quoted 12 lines
tools/net/ynl/generated/nfsd-user.h +11
-0+/* ============== NFSD_CMD_LISTENER_START ============== */ +/* NFSD_CMD_LISTENER_START - do */ +struct nfsd_listener_start_req { +struct { +__u32 transport_name_len; +__u32 port:1 ; + } _present; + +char *transport_name; +__u32 port; +};How do you deconfigure a listener with this interface? i.e. suppose I want to stop nfsd from listening on a particular port? I think this too is a place where a declarative interface would be better:
Quoted 5 lines
Is it possible with current APIs? as for 2/3 so far I have just added netlink counter for current implementation but I am fine to change the logic here to better APIs.
Quoted 1 line
Quoted 10 lines
No, I don't think you can do this with the current API at all. I consider it a major deficiency. I don't think we want to repeat that mistake in the new interface.
Quoted 5 lines
Quoted 5 lines
Have userland send down a list of the ports that we should currently be listening on, and let the kernel do the work to match the request. Again too, an empty list could mean "close everything".
Another thought: should this interface also report and allow you to specify the address to listen on?
When the write_ports interface was first created, it lacked a field for the address to listen on. Later we added a way to just hand off a socket to the kernel to pass that info.
I think it's possible today to send down a socket that only listens on a particular address, and you have no real way to tell that with the current "ports" file.
Should we instead plumb a complete struct sockaddr_storage (or some other suitable address structure) into this interface?
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v5 3/3] NFSD: convert write_ports to netlink command
Quoted 36 lines · Jeff Layton
Quoted 24 lines · Jeff Layton
Quoted 17 lines · Lorenzo Bianconi
Quoted 16 lines
tools/net/ynl/generated/nfsd-user.h void nfsd_version_get_list_free(struct nfsd_version_get_list *rsp); · line 179
Quoted 12 lines
tools/net/ynl/generated/nfsd-user.h +11
-0+/* ============== NFSD_CMD_LISTENER_START ============== */ +/* NFSD_CMD_LISTENER_START - do */ +struct nfsd_listener_start_req { +struct { +__u32 transport_name_len; +__u32 port:1 ; + } _present; + +char *transport_name; +__u32 port; +};How do you deconfigure a listener with this interface? i.e. suppose I want to stop nfsd from listening on a particular port? I think this too is a place where a declarative interface would be better:
Quoted 5 lines
Is it possible with current APIs? as for 2/3 so far I have just added netlink counter for current implementation but I am fine to change the logic here to better APIs.
Quoted 1 line
Quoted 7 lines
No, I don't think you can do this with the current API at all. I consider it a major deficiency. I don't think we want to repeat that mistake in the new interface.
Quoted 3 lines
Quoted 3 lines
Have userland send down a list of the ports that we should currently be listening on, and let the kernel do the work to match the request. Again too, an empty list could mean "close everything".
Another thought: should this interface also report and allow you to specify the address to listen on?
Quoted 7 lines
When the
write_portsinterface was first created, it lacked a field for the address to listen on. Later we added a way to just hand off a socket to the kernel to pass that info.I think it's possible today to send down a socket that only listens on a particular address, and you have no real way to tell that with the current "ports" file.
All agreed, but listening on a particular address isn't something we need today. (Or is it?)
Does the socket-passing thing work for non socket-based transports like RDMA? I would think that mechanism is legacy.
Quoted 2 lines
Should we instead plumb a complete struct
sockaddr_storage(or some other suitable address structure) into this interface?
How difficult would it be to add this later, when we actually have a specific use case?
Signature · 1 line
Chuck Lever
Jeff Layton
maintainerRe: [PATCH v5 3/3] NFSD: convert write_ports to netlink command
Quoted 41 lines · Chuck Lever
Quoted 40 lines · Jeff Layton
Quoted 24 lines · Jeff Layton
Quoted 17 lines · Lorenzo Bianconi
Quoted 16 lines
tools/net/ynl/generated/nfsd-user.h void nfsd_version_get_list_free(struct nfsd_version_get_list *rsp); · line 179
Quoted 12 lines
tools/net/ynl/generated/nfsd-user.h +11
-0+/* ============== NFSD_CMD_LISTENER_START ============== */ +/* NFSD_CMD_LISTENER_START - do */ +struct nfsd_listener_start_req { +struct { +__u32 transport_name_len; +__u32 port:1 ; + } _present; + +char *transport_name; +__u32 port; +};How do you deconfigure a listener with this interface? i.e. suppose I want to stop nfsd from listening on a particular port? I think this too is a place where a declarative interface would be better:
Quoted 5 lines
Is it possible with current APIs? as for 2/3 so far I have just added netlink counter for current implementation but I am fine to change the logic here to better APIs.
Quoted 1 line
Quoted 7 lines
No, I don't think you can do this with the current API at all. I consider it a major deficiency. I don't think we want to repeat that mistake in the new interface.
Quoted 3 lines
Quoted 3 lines
Have userland send down a list of the ports that we should currently be listening on, and let the kernel do the work to match the request. Again too, an empty list could mean "close everything".
Another thought: should this interface also report and allow you to specify the address to listen on?
When the
write_portsinterface was first created, it lacked a field for the address to listen on. Later we added a way to just hand off a socket to the kernel to pass that info.
Quoted 7 lines
Quoted 3 lines
I think it's possible today to send down a socket that only listens on a particular address, and you have no real way to tell that with the current "ports" file.
All agreed, but listening on a particular address isn't something we need today. (Or is it?)
It is for TCP/UDP -- see the -H option to rpc.nfsd.
Quoted 3 lines
Does the socket-passing thing work for non socket-based transports like RDMA? I would think that mechanism is legacy.
To the contrary actually. rpc.nfsd almost always does this today unless you're configuring rdma. But, that was just a convenient way to do this with a fd based interface.
I think with netlink, we just want to send down a list of (transport_name, sockaddr) pairs and let the kernel open and close the appropriate sockets. For RDMA, we can just fill out the sa_port field and ignore the rest.
Quoted 6 lines
Quoted 3 lines
Should we instead plumb a complete struct
sockaddr_storage(or some other suitable address structure) into this interface?How difficult would it be to add this later, when we actually have a specific use case?
I think we have one now. rpc.nfsd passes down sockets to the kernel for TCP and UDP listeners, so we need a way to send down a complete sockaddr for the listeners.
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v5 3/3] NFSD: convert write_ports to netlink command
Quoted 54 lines · Jeff Layton
Quoted 41 lines · Chuck Lever
Quoted 40 lines · Jeff Layton
Quoted 24 lines · Jeff Layton
Quoted 17 lines · Lorenzo Bianconi
Quoted 16 lines
Review
Quoted 12 lines
(quoted diff) +11
-0+/* ============== NFSD_CMD_LISTENER_START ============== */ +/* NFSD_CMD_LISTENER_START - do */ +struct nfsd_listener_start_req { + struct { + __u32 transport_name_len; + __u32 port:1; + } _present; + + char *transport_name; + __u32 port; +};How do you deconfigure a listener with this interface? i.e. suppose I want to stop nfsd from listening on a particular port? I think this too is a place where a declarative interface would be better:
Quoted 5 lines
Is it possible with current APIs? as for 2/3 so far I have just added netlink counter for current implementation but I am fine to change the logic here to better APIs.
Quoted 1 line
Quoted 7 lines
No, I don't think you can do this with the current API at all. I consider it a major deficiency. I don't think we want to repeat that mistake in the new interface.
Quoted 3 lines
Quoted 3 lines
Have userland send down a list of the ports that we should currently be listening on, and let the kernel do the work to match the request. Again too, an empty list could mean "close everything".
Another thought: should this interface also report and allow you to specify the address to listen on?
When the
write_portsinterface was first created, it lacked a field for the address to listen on. Later we added a way to just hand off a socket to the kernel to pass that info.Quoted 6 lines
Quoted 3 lines
I think it's possible today to send down a socket that only listens on a particular address, and you have no real way to tell that with the current "ports" file.
All agreed, but listening on a particular address isn't something we need today. (Or is it?)
It is for TCP/UDP -- see the -H option to rpc.nfsd.
Quoted 2 lines
Does the socket-passing thing work for non socket-based transports like RDMA? I would think that mechanism is legacy.
Quoted 8 lines
To the contrary actually. rpc.nfsd almost always does this today unless you're configuring rdma. But, that was just a convenient way to do this with a fd based interface.
I think with netlink, we just want to send down a list of (
transport_name, sockaddr) pairs and let the kernel open and close the appropriate sockets. For RDMA, we can just fill out thesa_portfield and ignore the rest.
Agreed, it would be cleaner to handle all transport classes the same way and eventually deprecate the fd-passing mechanism.
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
Should we instead plumb a complete struct
sockaddr_storage(or some other suitable address structure) into this interface?How difficult would it be to add this later, when we actually have a specific use case?
I think we have one now. rpc.nfsd passes down sockets to the kernel for TCP and UDP listeners, so we need a way to send down a complete sockaddr for the listeners.
If we have a usage scenario, then it makes sense to try it now.
Signature · 1 line
Chuck Lever
Simon Horman
reviewerRe: [PATCH v5 3/3] NFSD: convert write_ports to netlink command
In reply to Lorenzo BianconiQuoted 4 lines · Lorenzo Bianconi
Introduce
write_portsnetlink command similar to the ones available through the procfs.Signed-off-by Lorenzo Bianconi <[email protected]>
Hi Lorenzo,
some minor feedback from my side.
...
Quoted 13 lines
fs/nfsd/nfsctl.c +9
-0@@ -1862,6 +1871,87 @@ int nfsd_nl_version_get_dumpit(struct sk_buff *skb,return ret; } +/** +* nfsd_nl_listener_start_doit - start the provided nfs server listener +* @skb: reply buffer +* @info: netlink metadata and command arguments +* +* Return 0 on success or a negative errno. +*/ +int nfsd_nl_listener_start_doit (struct sk_buff *skb,struct genl_info *info) +{
fs/nfsd/nfsctl.c int nfsd_nl_version_get_dumpit(struct sk_buff *skb, · line 1892
Quoted 10 lines
fs/nfsd/nfsctl.c +10
-0+int ret; + +if (GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ) || +GENL_REQ_ATTR_CHECK (info,NFSD_A_SERVER_LISTENER_PORT )) +return -EINVAL ; + +mutex_lock (&nfsd_mutex); + ret =___write_ports_addxprt (genl_info_net (info),get_current_cred (), +nla_data (info->attrs[NFSD_A_SERVER_LISTENER_TRANSPORT_NAME ]), +nla_get_u32 (info->attrs[NFSD_A_SERVER_LISTENER_PORT ]));
gcc-13 and clang-17 W=1 builds warn that ret is set but otherwise unused in this function.
fs/nfsd/nfsctl.c int nfsd_nl_version_get_dumpit(struct sk_buff *skb, · line 1899
Quoted 7 lines
fs/nfsd/nfsctl.c +7
-0+mutex_unlock (&nfsd_mutex); + +return 0 ; +} + +/** +* nfsd_nl_version_get_dumpit - Handle listener_get dumpit
nit: nfsd_nl_listener_get_dumpit
Quoted 7 lines
fs/nfsd/nfsctl.c +7
-0+* @skb: reply buffer +* @cb: netlink metadata and command arguments +* +* Returns the size of the reply or a negative errno. +*/ +int nfsd_nl_listener_get_dumpit (struct sk_buff *skb, +struct netlink_callback *cb)
...