Skip to content

Commit 16a4711

Browse files
LorenzoBianconichucklever
authored andcommitted
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 <[email protected]> Co-developed-by: Jeff Layton <[email protected]> Signed-off-by: Jeff Layton <[email protected]> Signed-off-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent cf61950 commit 16a4711

File tree

5 files changed

+296
-0
lines changed

5 files changed

+296
-0
lines changed

Documentation/netlink/specs/nfsd.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,23 @@ attribute-sets:
9898
type: nest
9999
nested-attributes: version
100100
multi-attr: true
101+
-
102+
name: sock
103+
attributes:
104+
-
105+
name: addr
106+
type: binary
107+
-
108+
name: transport-name
109+
type: string
110+
-
111+
name: server-sock
112+
attributes:
113+
-
114+
name: addr
115+
type: nest
116+
nested-attributes: sock
117+
multi-attr: true
101118

102119
operations:
103120
list:
@@ -163,3 +180,20 @@ operations:
163180
reply:
164181
attributes:
165182
- version
183+
-
184+
name: listener-set
185+
doc: set nfs running sockets
186+
attribute-set: server-sock
187+
flags: [ admin-perm ]
188+
do:
189+
request:
190+
attributes:
191+
- addr
192+
-
193+
name: listener-get
194+
doc: get nfs running listeners
195+
attribute-set: server-sock
196+
do:
197+
reply:
198+
attributes:
199+
- addr

fs/nfsd/netlink.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
#include <uapi/linux/nfsd_netlink.h>
1212

1313
/* Common nested types */
14+
const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1] = {
15+
[NFSD_A_SOCK_ADDR] = { .type = NLA_BINARY, },
16+
[NFSD_A_SOCK_TRANSPORT_NAME] = { .type = NLA_NUL_STRING, },
17+
};
18+
1419
const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
1520
[NFSD_A_VERSION_MAJOR] = { .type = NLA_U32, },
1621
[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
3035
[NFSD_A_SERVER_PROTO_VERSION] = NLA_POLICY_NESTED(nfsd_version_nl_policy),
3136
};
3237

38+
/* NFSD_CMD_LISTENER_SET - do */
39+
static const struct nla_policy nfsd_listener_set_nl_policy[NFSD_A_SERVER_SOCK_ADDR + 1] = {
40+
[NFSD_A_SERVER_SOCK_ADDR] = NLA_POLICY_NESTED(nfsd_sock_nl_policy),
41+
};
42+
3343
/* Ops table for nfsd */
3444
static const struct genl_split_ops nfsd_nl_ops[] = {
3545
{
@@ -63,6 +73,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
6373
.doit = nfsd_nl_version_get_doit,
6474
.flags = GENL_CMD_CAP_DO,
6575
},
76+
{
77+
.cmd = NFSD_CMD_LISTENER_SET,
78+
.doit = nfsd_nl_listener_set_doit,
79+
.policy = nfsd_listener_set_nl_policy,
80+
.maxattr = NFSD_A_SERVER_SOCK_ADDR,
81+
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
82+
},
83+
{
84+
.cmd = NFSD_CMD_LISTENER_GET,
85+
.doit = nfsd_nl_listener_get_doit,
86+
.flags = GENL_CMD_CAP_DO,
87+
},
6688
};
6789

6890
struct genl_family nfsd_nl_family __ro_after_init = {

fs/nfsd/netlink.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <uapi/linux/nfsd_netlink.h>
1313

1414
/* Common nested types */
15+
extern const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1];
1516
extern const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1];
1617

1718
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);
2324
int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info);
2425
int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info);
2526
int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info);
27+
int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info);
28+
int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info);
2629

2730
extern struct genl_family nfsd_nl_family;
2831

fs/nfsd/nfsctl.c

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,6 +1946,226 @@ int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info)
19461946
return err;
19471947
}
19481948

1949+
/**
1950+
* nfsd_nl_listener_set_doit - set the nfs running sockets
1951+
* @skb: reply buffer
1952+
* @info: netlink metadata and command arguments
1953+
*
1954+
* Return 0 on success or a negative errno.
1955+
*/
1956+
int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
1957+
{
1958+
struct net *net = genl_info_net(info);
1959+
struct svc_xprt *xprt, *tmp;
1960+
const struct nlattr *attr;
1961+
struct svc_serv *serv;
1962+
LIST_HEAD(permsocks);
1963+
struct nfsd_net *nn;
1964+
int err, rem;
1965+
1966+
mutex_lock(&nfsd_mutex);
1967+
1968+
err = nfsd_create_serv(net);
1969+
if (err) {
1970+
mutex_unlock(&nfsd_mutex);
1971+
return err;
1972+
}
1973+
1974+
nn = net_generic(net, nfsd_net_id);
1975+
serv = nn->nfsd_serv;
1976+
1977+
spin_lock_bh(&serv->sv_lock);
1978+
1979+
/* Move all of the old listener sockets to a temp list */
1980+
list_splice_init(&serv->sv_permsocks, &permsocks);
1981+
1982+
/*
1983+
* Walk the list of server_socks from userland and move any that match
1984+
* back to sv_permsocks
1985+
*/
1986+
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
1987+
struct nlattr *tb[NFSD_A_SOCK_MAX + 1];
1988+
const char *xcl_name;
1989+
struct sockaddr *sa;
1990+
1991+
if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR)
1992+
continue;
1993+
1994+
if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr,
1995+
nfsd_sock_nl_policy, info->extack) < 0)
1996+
continue;
1997+
1998+
if (!tb[NFSD_A_SOCK_ADDR] || !tb[NFSD_A_SOCK_TRANSPORT_NAME])
1999+
continue;
2000+
2001+
if (nla_len(tb[NFSD_A_SOCK_ADDR]) < sizeof(*sa))
2002+
continue;
2003+
2004+
xcl_name = nla_data(tb[NFSD_A_SOCK_TRANSPORT_NAME]);
2005+
sa = nla_data(tb[NFSD_A_SOCK_ADDR]);
2006+
2007+
/* Put back any matching sockets */
2008+
list_for_each_entry_safe(xprt, tmp, &permsocks, xpt_list) {
2009+
/* This shouldn't be possible */
2010+
if (WARN_ON_ONCE(xprt->xpt_net != net)) {
2011+
list_move(&xprt->xpt_list, &serv->sv_permsocks);
2012+
continue;
2013+
}
2014+
2015+
/* If everything matches, put it back */
2016+
if (!strcmp(xprt->xpt_class->xcl_name, xcl_name) &&
2017+
rpc_cmp_addr_port(sa, (struct sockaddr *)&xprt->xpt_local)) {
2018+
list_move(&xprt->xpt_list, &serv->sv_permsocks);
2019+
break;
2020+
}
2021+
}
2022+
}
2023+
2024+
/* For now, no removing old sockets while server is running */
2025+
if (serv->sv_nrthreads && !list_empty(&permsocks)) {
2026+
list_splice_init(&permsocks, &serv->sv_permsocks);
2027+
spin_unlock_bh(&serv->sv_lock);
2028+
err = -EBUSY;
2029+
goto out_unlock_mtx;
2030+
}
2031+
2032+
/* Close the remaining sockets on the permsocks list */
2033+
while (!list_empty(&permsocks)) {
2034+
xprt = list_first_entry(&permsocks, struct svc_xprt, xpt_list);
2035+
list_move(&xprt->xpt_list, &serv->sv_permsocks);
2036+
2037+
/*
2038+
* Newly-created sockets are born with the BUSY bit set. Clear
2039+
* it if there are no threads, since nothing can pick it up
2040+
* in that case.
2041+
*/
2042+
if (!serv->sv_nrthreads)
2043+
clear_bit(XPT_BUSY, &xprt->xpt_flags);
2044+
2045+
set_bit(XPT_CLOSE, &xprt->xpt_flags);
2046+
spin_unlock_bh(&serv->sv_lock);
2047+
svc_xprt_close(xprt);
2048+
spin_lock_bh(&serv->sv_lock);
2049+
}
2050+
2051+
spin_unlock_bh(&serv->sv_lock);
2052+
2053+
/* walk list of addrs again, open any that still don't exist */
2054+
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
2055+
struct nlattr *tb[NFSD_A_SOCK_MAX + 1];
2056+
const char *xcl_name;
2057+
struct sockaddr *sa;
2058+
int ret;
2059+
2060+
if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR)
2061+
continue;
2062+
2063+
if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr,
2064+
nfsd_sock_nl_policy, info->extack) < 0)
2065+
continue;
2066+
2067+
if (!tb[NFSD_A_SOCK_ADDR] || !tb[NFSD_A_SOCK_TRANSPORT_NAME])
2068+
continue;
2069+
2070+
if (nla_len(tb[NFSD_A_SOCK_ADDR]) < sizeof(*sa))
2071+
continue;
2072+
2073+
xcl_name = nla_data(tb[NFSD_A_SOCK_TRANSPORT_NAME]);
2074+
sa = nla_data(tb[NFSD_A_SOCK_ADDR]);
2075+
2076+
xprt = svc_find_listener(serv, xcl_name, net, sa);
2077+
if (xprt) {
2078+
svc_xprt_put(xprt);
2079+
continue;
2080+
}
2081+
2082+
ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa,
2083+
SVC_SOCK_ANONYMOUS,
2084+
get_current_cred());
2085+
/* always save the latest error */
2086+
if (ret < 0)
2087+
err = ret;
2088+
}
2089+
2090+
if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
2091+
nfsd_destroy_serv(net);
2092+
2093+
out_unlock_mtx:
2094+
mutex_unlock(&nfsd_mutex);
2095+
2096+
return err;
2097+
}
2098+
2099+
/**
2100+
* nfsd_nl_listener_get_doit - get the nfs running listeners
2101+
* @skb: reply buffer
2102+
* @info: netlink metadata and command arguments
2103+
*
2104+
* Return 0 on success or a negative errno.
2105+
*/
2106+
int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info)
2107+
{
2108+
struct svc_xprt *xprt;
2109+
struct svc_serv *serv;
2110+
struct nfsd_net *nn;
2111+
void *hdr;
2112+
int err;
2113+
2114+
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
2115+
if (!skb)
2116+
return -ENOMEM;
2117+
2118+
hdr = genlmsg_iput(skb, info);
2119+
if (!hdr) {
2120+
err = -EMSGSIZE;
2121+
goto err_free_msg;
2122+
}
2123+
2124+
mutex_lock(&nfsd_mutex);
2125+
nn = net_generic(genl_info_net(info), nfsd_net_id);
2126+
2127+
/* no nfs server? Just send empty socket list */
2128+
if (!nn->nfsd_serv)
2129+
goto out_unlock_mtx;
2130+
2131+
serv = nn->nfsd_serv;
2132+
spin_lock_bh(&serv->sv_lock);
2133+
list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
2134+
struct nlattr *attr;
2135+
2136+
attr = nla_nest_start(skb, NFSD_A_SERVER_SOCK_ADDR);
2137+
if (!attr) {
2138+
err = -EINVAL;
2139+
goto err_serv_unlock;
2140+
}
2141+
2142+
if (nla_put_string(skb, NFSD_A_SOCK_TRANSPORT_NAME,
2143+
xprt->xpt_class->xcl_name) ||
2144+
nla_put(skb, NFSD_A_SOCK_ADDR,
2145+
sizeof(struct sockaddr_storage),
2146+
&xprt->xpt_local)) {
2147+
err = -EINVAL;
2148+
goto err_serv_unlock;
2149+
}
2150+
2151+
nla_nest_end(skb, attr);
2152+
}
2153+
spin_unlock_bh(&serv->sv_lock);
2154+
out_unlock_mtx:
2155+
mutex_unlock(&nfsd_mutex);
2156+
genlmsg_end(skb, hdr);
2157+
2158+
return genlmsg_reply(skb, info);
2159+
2160+
err_serv_unlock:
2161+
spin_unlock_bh(&serv->sv_lock);
2162+
mutex_unlock(&nfsd_mutex);
2163+
err_free_msg:
2164+
nlmsg_free(skb);
2165+
2166+
return err;
2167+
}
2168+
19492169
/**
19502170
* nfsd_net_init - Prepare the nfsd_net portion of a new net namespace
19512171
* @net: a freshly-created network namespace

include/uapi/linux/nfsd_netlink.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,29 @@ enum {
5555
NFSD_A_SERVER_PROTO_MAX = (__NFSD_A_SERVER_PROTO_MAX - 1)
5656
};
5757

58+
enum {
59+
NFSD_A_SOCK_ADDR = 1,
60+
NFSD_A_SOCK_TRANSPORT_NAME,
61+
62+
__NFSD_A_SOCK_MAX,
63+
NFSD_A_SOCK_MAX = (__NFSD_A_SOCK_MAX - 1)
64+
};
65+
66+
enum {
67+
NFSD_A_SERVER_SOCK_ADDR = 1,
68+
69+
__NFSD_A_SERVER_SOCK_MAX,
70+
NFSD_A_SERVER_SOCK_MAX = (__NFSD_A_SERVER_SOCK_MAX - 1)
71+
};
72+
5873
enum {
5974
NFSD_CMD_RPC_STATUS_GET = 1,
6075
NFSD_CMD_THREADS_SET,
6176
NFSD_CMD_THREADS_GET,
6277
NFSD_CMD_VERSION_SET,
6378
NFSD_CMD_VERSION_GET,
79+
NFSD_CMD_LISTENER_SET,
80+
NFSD_CMD_LISTENER_GET,
6481

6582
__NFSD_CMD_MAX,
6683
NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)

0 commit comments

Comments
 (0)