mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	NFSD: add listener-{set,get} netlink command
Introduce write_ports netlink command. For listener-set, userspace is expected to provide a NFS listeners list it wants enabled. All other sockets will be closed. Reviewed-by: Jeff Layton <jlayton@kernel.org> Co-developed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
		
							parent
							
								
									cf619507ae
								
							
						
					
					
						commit
						16a4711774
					
				
					 5 changed files with 296 additions and 0 deletions
				
			
		| 
						 | 
					@ -98,6 +98,23 @@ attribute-sets:
 | 
				
			||||||
        type: nest
 | 
					        type: nest
 | 
				
			||||||
        nested-attributes: version
 | 
					        nested-attributes: version
 | 
				
			||||||
        multi-attr: true
 | 
					        multi-attr: true
 | 
				
			||||||
 | 
					  -
 | 
				
			||||||
 | 
					    name: sock
 | 
				
			||||||
 | 
					    attributes:
 | 
				
			||||||
 | 
					      -
 | 
				
			||||||
 | 
					        name: addr
 | 
				
			||||||
 | 
					        type: binary
 | 
				
			||||||
 | 
					      -
 | 
				
			||||||
 | 
					        name: transport-name
 | 
				
			||||||
 | 
					        type: string
 | 
				
			||||||
 | 
					  -
 | 
				
			||||||
 | 
					    name: server-sock
 | 
				
			||||||
 | 
					    attributes:
 | 
				
			||||||
 | 
					      -
 | 
				
			||||||
 | 
					        name: addr
 | 
				
			||||||
 | 
					        type: nest
 | 
				
			||||||
 | 
					        nested-attributes: sock
 | 
				
			||||||
 | 
					        multi-attr: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
operations:
 | 
					operations:
 | 
				
			||||||
  list:
 | 
					  list:
 | 
				
			||||||
| 
						 | 
					@ -163,3 +180,20 @@ operations:
 | 
				
			||||||
        reply:
 | 
					        reply:
 | 
				
			||||||
          attributes:
 | 
					          attributes:
 | 
				
			||||||
            - version
 | 
					            - version
 | 
				
			||||||
 | 
					    -
 | 
				
			||||||
 | 
					      name: listener-set
 | 
				
			||||||
 | 
					      doc: set nfs running sockets
 | 
				
			||||||
 | 
					      attribute-set: server-sock
 | 
				
			||||||
 | 
					      flags: [ admin-perm ]
 | 
				
			||||||
 | 
					      do:
 | 
				
			||||||
 | 
					        request:
 | 
				
			||||||
 | 
					          attributes:
 | 
				
			||||||
 | 
					            - addr
 | 
				
			||||||
 | 
					    -
 | 
				
			||||||
 | 
					      name: listener-get
 | 
				
			||||||
 | 
					      doc: get nfs running listeners
 | 
				
			||||||
 | 
					      attribute-set: server-sock
 | 
				
			||||||
 | 
					      do:
 | 
				
			||||||
 | 
					        reply:
 | 
				
			||||||
 | 
					          attributes:
 | 
				
			||||||
 | 
					            - addr
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,11 @@
 | 
				
			||||||
#include <uapi/linux/nfsd_netlink.h>
 | 
					#include <uapi/linux/nfsd_netlink.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Common nested types */
 | 
					/* Common nested types */
 | 
				
			||||||
 | 
					const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1] = {
 | 
				
			||||||
 | 
						[NFSD_A_SOCK_ADDR] = { .type = NLA_BINARY, },
 | 
				
			||||||
 | 
						[NFSD_A_SOCK_TRANSPORT_NAME] = { .type = NLA_NUL_STRING, },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
 | 
					const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
 | 
				
			||||||
	[NFSD_A_VERSION_MAJOR] = { .type = NLA_U32, },
 | 
						[NFSD_A_VERSION_MAJOR] = { .type = NLA_U32, },
 | 
				
			||||||
	[NFSD_A_VERSION_MINOR] = { .type = NLA_U32, },
 | 
						[NFSD_A_VERSION_MINOR] = { .type = NLA_U32, },
 | 
				
			||||||
| 
						 | 
					@ -30,6 +35,11 @@ static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_PROTO_VE
 | 
				
			||||||
	[NFSD_A_SERVER_PROTO_VERSION] = NLA_POLICY_NESTED(nfsd_version_nl_policy),
 | 
						[NFSD_A_SERVER_PROTO_VERSION] = NLA_POLICY_NESTED(nfsd_version_nl_policy),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* NFSD_CMD_LISTENER_SET - do */
 | 
				
			||||||
 | 
					static const struct nla_policy nfsd_listener_set_nl_policy[NFSD_A_SERVER_SOCK_ADDR + 1] = {
 | 
				
			||||||
 | 
						[NFSD_A_SERVER_SOCK_ADDR] = NLA_POLICY_NESTED(nfsd_sock_nl_policy),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Ops table for nfsd */
 | 
					/* Ops table for nfsd */
 | 
				
			||||||
static const struct genl_split_ops nfsd_nl_ops[] = {
 | 
					static const struct genl_split_ops nfsd_nl_ops[] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -63,6 +73,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
 | 
				
			||||||
		.doit	= nfsd_nl_version_get_doit,
 | 
							.doit	= nfsd_nl_version_get_doit,
 | 
				
			||||||
		.flags	= GENL_CMD_CAP_DO,
 | 
							.flags	= GENL_CMD_CAP_DO,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.cmd		= NFSD_CMD_LISTENER_SET,
 | 
				
			||||||
 | 
							.doit		= nfsd_nl_listener_set_doit,
 | 
				
			||||||
 | 
							.policy		= nfsd_listener_set_nl_policy,
 | 
				
			||||||
 | 
							.maxattr	= NFSD_A_SERVER_SOCK_ADDR,
 | 
				
			||||||
 | 
							.flags		= GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.cmd	= NFSD_CMD_LISTENER_GET,
 | 
				
			||||||
 | 
							.doit	= nfsd_nl_listener_get_doit,
 | 
				
			||||||
 | 
							.flags	= GENL_CMD_CAP_DO,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct genl_family nfsd_nl_family __ro_after_init = {
 | 
					struct genl_family nfsd_nl_family __ro_after_init = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include <uapi/linux/nfsd_netlink.h>
 | 
					#include <uapi/linux/nfsd_netlink.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Common nested types */
 | 
					/* Common nested types */
 | 
				
			||||||
 | 
					extern const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1];
 | 
				
			||||||
extern const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1];
 | 
					extern const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb);
 | 
					int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb);
 | 
				
			||||||
| 
						 | 
					@ -23,6 +24,8 @@ 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_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_set_doit(struct sk_buff *skb, struct genl_info *info);
 | 
				
			||||||
int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info);
 | 
					int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info);
 | 
				
			||||||
 | 
					int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info);
 | 
				
			||||||
 | 
					int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct genl_family nfsd_nl_family;
 | 
					extern struct genl_family nfsd_nl_family;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										220
									
								
								fs/nfsd/nfsctl.c
									
									
									
									
									
								
							
							
						
						
									
										220
									
								
								fs/nfsd/nfsctl.c
									
									
									
									
									
								
							| 
						 | 
					@ -1946,6 +1946,226 @@ int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * nfsd_nl_listener_set_doit - set the nfs running sockets
 | 
				
			||||||
 | 
					 * @skb: reply buffer
 | 
				
			||||||
 | 
					 * @info: netlink metadata and command arguments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success or a negative errno.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net *net = genl_info_net(info);
 | 
				
			||||||
 | 
						struct svc_xprt *xprt, *tmp;
 | 
				
			||||||
 | 
						const struct nlattr *attr;
 | 
				
			||||||
 | 
						struct svc_serv *serv;
 | 
				
			||||||
 | 
						LIST_HEAD(permsocks);
 | 
				
			||||||
 | 
						struct nfsd_net *nn;
 | 
				
			||||||
 | 
						int err, rem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&nfsd_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = nfsd_create_serv(net);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							mutex_unlock(&nfsd_mutex);
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nn = net_generic(net, nfsd_net_id);
 | 
				
			||||||
 | 
						serv = nn->nfsd_serv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_bh(&serv->sv_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Move all of the old listener sockets to a temp list */
 | 
				
			||||||
 | 
						list_splice_init(&serv->sv_permsocks, &permsocks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Walk the list of server_socks from userland and move any that match
 | 
				
			||||||
 | 
						 * back to sv_permsocks
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
 | 
				
			||||||
 | 
							struct nlattr *tb[NFSD_A_SOCK_MAX + 1];
 | 
				
			||||||
 | 
							const char *xcl_name;
 | 
				
			||||||
 | 
							struct sockaddr *sa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr,
 | 
				
			||||||
 | 
									     nfsd_sock_nl_policy, info->extack) < 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!tb[NFSD_A_SOCK_ADDR] || !tb[NFSD_A_SOCK_TRANSPORT_NAME])
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (nla_len(tb[NFSD_A_SOCK_ADDR]) < sizeof(*sa))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							xcl_name = nla_data(tb[NFSD_A_SOCK_TRANSPORT_NAME]);
 | 
				
			||||||
 | 
							sa = nla_data(tb[NFSD_A_SOCK_ADDR]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Put back any matching sockets */
 | 
				
			||||||
 | 
							list_for_each_entry_safe(xprt, tmp, &permsocks, xpt_list) {
 | 
				
			||||||
 | 
								/* This shouldn't be possible */
 | 
				
			||||||
 | 
								if (WARN_ON_ONCE(xprt->xpt_net != net)) {
 | 
				
			||||||
 | 
									list_move(&xprt->xpt_list, &serv->sv_permsocks);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* If everything matches, put it back */
 | 
				
			||||||
 | 
								if (!strcmp(xprt->xpt_class->xcl_name, xcl_name) &&
 | 
				
			||||||
 | 
								    rpc_cmp_addr_port(sa, (struct sockaddr *)&xprt->xpt_local)) {
 | 
				
			||||||
 | 
									list_move(&xprt->xpt_list, &serv->sv_permsocks);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* For now, no removing old sockets while server is running */
 | 
				
			||||||
 | 
						if (serv->sv_nrthreads && !list_empty(&permsocks)) {
 | 
				
			||||||
 | 
							list_splice_init(&permsocks, &serv->sv_permsocks);
 | 
				
			||||||
 | 
							spin_unlock_bh(&serv->sv_lock);
 | 
				
			||||||
 | 
							err = -EBUSY;
 | 
				
			||||||
 | 
							goto out_unlock_mtx;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Close the remaining sockets on the permsocks list */
 | 
				
			||||||
 | 
						while (!list_empty(&permsocks)) {
 | 
				
			||||||
 | 
							xprt = list_first_entry(&permsocks, struct svc_xprt, xpt_list);
 | 
				
			||||||
 | 
							list_move(&xprt->xpt_list, &serv->sv_permsocks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Newly-created sockets are born with the BUSY bit set. Clear
 | 
				
			||||||
 | 
							 * it if there are no threads, since nothing can pick it up
 | 
				
			||||||
 | 
							 * in that case.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (!serv->sv_nrthreads)
 | 
				
			||||||
 | 
								clear_bit(XPT_BUSY, &xprt->xpt_flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							set_bit(XPT_CLOSE, &xprt->xpt_flags);
 | 
				
			||||||
 | 
							spin_unlock_bh(&serv->sv_lock);
 | 
				
			||||||
 | 
							svc_xprt_close(xprt);
 | 
				
			||||||
 | 
							spin_lock_bh(&serv->sv_lock);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock_bh(&serv->sv_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* walk list of addrs again, open any that still don't exist */
 | 
				
			||||||
 | 
						nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
 | 
				
			||||||
 | 
							struct nlattr *tb[NFSD_A_SOCK_MAX + 1];
 | 
				
			||||||
 | 
							const char *xcl_name;
 | 
				
			||||||
 | 
							struct sockaddr *sa;
 | 
				
			||||||
 | 
							int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr,
 | 
				
			||||||
 | 
									     nfsd_sock_nl_policy, info->extack) < 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!tb[NFSD_A_SOCK_ADDR] || !tb[NFSD_A_SOCK_TRANSPORT_NAME])
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (nla_len(tb[NFSD_A_SOCK_ADDR]) < sizeof(*sa))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							xcl_name = nla_data(tb[NFSD_A_SOCK_TRANSPORT_NAME]);
 | 
				
			||||||
 | 
							sa = nla_data(tb[NFSD_A_SOCK_ADDR]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							xprt = svc_find_listener(serv, xcl_name, net, sa);
 | 
				
			||||||
 | 
							if (xprt) {
 | 
				
			||||||
 | 
								svc_xprt_put(xprt);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa,
 | 
				
			||||||
 | 
										      SVC_SOCK_ANONYMOUS,
 | 
				
			||||||
 | 
										      get_current_cred());
 | 
				
			||||||
 | 
							/* always save the latest error */
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								err = ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
 | 
				
			||||||
 | 
							nfsd_destroy_serv(net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_unlock_mtx:
 | 
				
			||||||
 | 
						mutex_unlock(&nfsd_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * nfsd_nl_listener_get_doit - get the nfs running listeners
 | 
				
			||||||
 | 
					 * @skb: reply buffer
 | 
				
			||||||
 | 
					 * @info: netlink metadata and command arguments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success or a negative errno.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct svc_xprt *xprt;
 | 
				
			||||||
 | 
						struct svc_serv *serv;
 | 
				
			||||||
 | 
						struct nfsd_net *nn;
 | 
				
			||||||
 | 
						void *hdr;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!skb)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hdr = genlmsg_iput(skb, info);
 | 
				
			||||||
 | 
						if (!hdr) {
 | 
				
			||||||
 | 
							err = -EMSGSIZE;
 | 
				
			||||||
 | 
							goto err_free_msg;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&nfsd_mutex);
 | 
				
			||||||
 | 
						nn = net_generic(genl_info_net(info), nfsd_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* no nfs server? Just send empty socket list */
 | 
				
			||||||
 | 
						if (!nn->nfsd_serv)
 | 
				
			||||||
 | 
							goto out_unlock_mtx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						serv = nn->nfsd_serv;
 | 
				
			||||||
 | 
						spin_lock_bh(&serv->sv_lock);
 | 
				
			||||||
 | 
						list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
 | 
				
			||||||
 | 
							struct nlattr *attr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							attr = nla_nest_start(skb, NFSD_A_SERVER_SOCK_ADDR);
 | 
				
			||||||
 | 
							if (!attr) {
 | 
				
			||||||
 | 
								err = -EINVAL;
 | 
				
			||||||
 | 
								goto err_serv_unlock;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (nla_put_string(skb, NFSD_A_SOCK_TRANSPORT_NAME,
 | 
				
			||||||
 | 
									   xprt->xpt_class->xcl_name) ||
 | 
				
			||||||
 | 
							    nla_put(skb, NFSD_A_SOCK_ADDR,
 | 
				
			||||||
 | 
								    sizeof(struct sockaddr_storage),
 | 
				
			||||||
 | 
								    &xprt->xpt_local)) {
 | 
				
			||||||
 | 
								err = -EINVAL;
 | 
				
			||||||
 | 
								goto err_serv_unlock;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							nla_nest_end(skb, attr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock_bh(&serv->sv_lock);
 | 
				
			||||||
 | 
					out_unlock_mtx:
 | 
				
			||||||
 | 
						mutex_unlock(&nfsd_mutex);
 | 
				
			||||||
 | 
						genlmsg_end(skb, hdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return genlmsg_reply(skb, info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_serv_unlock:
 | 
				
			||||||
 | 
						spin_unlock_bh(&serv->sv_lock);
 | 
				
			||||||
 | 
						mutex_unlock(&nfsd_mutex);
 | 
				
			||||||
 | 
					err_free_msg:
 | 
				
			||||||
 | 
						nlmsg_free(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace
 | 
					 * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace
 | 
				
			||||||
 * @net: a freshly-created network namespace
 | 
					 * @net: a freshly-created network namespace
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,12 +55,29 @@ enum {
 | 
				
			||||||
	NFSD_A_SERVER_PROTO_MAX = (__NFSD_A_SERVER_PROTO_MAX - 1)
 | 
						NFSD_A_SERVER_PROTO_MAX = (__NFSD_A_SERVER_PROTO_MAX - 1)
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						NFSD_A_SOCK_ADDR = 1,
 | 
				
			||||||
 | 
						NFSD_A_SOCK_TRANSPORT_NAME,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__NFSD_A_SOCK_MAX,
 | 
				
			||||||
 | 
						NFSD_A_SOCK_MAX = (__NFSD_A_SOCK_MAX - 1)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						NFSD_A_SERVER_SOCK_ADDR = 1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__NFSD_A_SERVER_SOCK_MAX,
 | 
				
			||||||
 | 
						NFSD_A_SERVER_SOCK_MAX = (__NFSD_A_SERVER_SOCK_MAX - 1)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	NFSD_CMD_RPC_STATUS_GET = 1,
 | 
						NFSD_CMD_RPC_STATUS_GET = 1,
 | 
				
			||||||
	NFSD_CMD_THREADS_SET,
 | 
						NFSD_CMD_THREADS_SET,
 | 
				
			||||||
	NFSD_CMD_THREADS_GET,
 | 
						NFSD_CMD_THREADS_GET,
 | 
				
			||||||
	NFSD_CMD_VERSION_SET,
 | 
						NFSD_CMD_VERSION_SET,
 | 
				
			||||||
	NFSD_CMD_VERSION_GET,
 | 
						NFSD_CMD_VERSION_GET,
 | 
				
			||||||
 | 
						NFSD_CMD_LISTENER_SET,
 | 
				
			||||||
 | 
						NFSD_CMD_LISTENER_GET,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__NFSD_CMD_MAX,
 | 
						__NFSD_CMD_MAX,
 | 
				
			||||||
	NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)
 | 
						NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue