Skip to content

Commit 5a939be

Browse files
LorenzoBianconichucklever
authored andcommitted
NFSD: add write_version to netlink command
Introduce write_version netlink command through a "declarative" interface. This patch introduces a change in behavior since for version-set userspace is expected to provide a NFS major/minor version list it wants to enable while all the other ones will be disabled. (procfs write_version command implements imperative interface where the admin writes +3/-3 to enable/disable a single version. Reviewed-by: Jeff Layton <[email protected]> Tested-by: Jeff Layton <[email protected]> Signed-off-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent 924f4fb commit 5a939be

File tree

7 files changed

+236
-2
lines changed

7 files changed

+236
-2
lines changed

Documentation/netlink/specs/nfsd.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,26 @@ attribute-sets:
7878
-
7979
name: scope
8080
type: string
81+
-
82+
name: version
83+
attributes:
84+
-
85+
name: major
86+
type: u32
87+
-
88+
name: minor
89+
type: u32
90+
-
91+
name: enabled
92+
type: flag
93+
-
94+
name: server-proto
95+
attributes:
96+
-
97+
name: version
98+
type: nest
99+
nested-attributes: version
100+
multi-attr: true
81101

82102
operations:
83103
list:
@@ -126,3 +146,20 @@ operations:
126146
- gracetime
127147
- leasetime
128148
- scope
149+
-
150+
name: version-set
151+
doc: set nfs enabled versions
152+
attribute-set: server-proto
153+
flags: [ admin-perm ]
154+
do:
155+
request:
156+
attributes:
157+
- version
158+
-
159+
name: version-get
160+
doc: get nfs enabled versions
161+
attribute-set: server-proto
162+
do:
163+
reply:
164+
attributes:
165+
- version

fs/nfsd/netlink.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010

1111
#include <uapi/linux/nfsd_netlink.h>
1212

13+
/* Common nested types */
14+
const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
15+
[NFSD_A_VERSION_MAJOR] = { .type = NLA_U32, },
16+
[NFSD_A_VERSION_MINOR] = { .type = NLA_U32, },
17+
[NFSD_A_VERSION_ENABLED] = { .type = NLA_FLAG, },
18+
};
19+
1320
/* NFSD_CMD_THREADS_SET - do */
1421
static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_SCOPE + 1] = {
1522
[NFSD_A_SERVER_THREADS] = { .type = NLA_U32, },
@@ -18,6 +25,11 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_SCOPE +
1825
[NFSD_A_SERVER_SCOPE] = { .type = NLA_NUL_STRING, },
1926
};
2027

28+
/* NFSD_CMD_VERSION_SET - do */
29+
static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_PROTO_VERSION + 1] = {
30+
[NFSD_A_SERVER_PROTO_VERSION] = NLA_POLICY_NESTED(nfsd_version_nl_policy),
31+
};
32+
2133
/* Ops table for nfsd */
2234
static const struct genl_split_ops nfsd_nl_ops[] = {
2335
{
@@ -39,6 +51,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
3951
.doit = nfsd_nl_threads_get_doit,
4052
.flags = GENL_CMD_CAP_DO,
4153
},
54+
{
55+
.cmd = NFSD_CMD_VERSION_SET,
56+
.doit = nfsd_nl_version_set_doit,
57+
.policy = nfsd_version_set_nl_policy,
58+
.maxattr = NFSD_A_SERVER_PROTO_VERSION,
59+
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
60+
},
61+
{
62+
.cmd = NFSD_CMD_VERSION_GET,
63+
.doit = nfsd_nl_version_get_doit,
64+
.flags = GENL_CMD_CAP_DO,
65+
},
4266
};
4367

4468
struct genl_family nfsd_nl_family __ro_after_init = {

fs/nfsd/netlink.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,18 @@
1111

1212
#include <uapi/linux/nfsd_netlink.h>
1313

14+
/* Common nested types */
15+
extern const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1];
16+
1417
int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb);
1518
int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb);
1619

1720
int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
1821
struct netlink_callback *cb);
1922
int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info);
2023
int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info);
24+
int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info);
25+
int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info);
2126

2227
extern struct genl_family nfsd_nl_family;
2328

fs/nfsd/netns.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ struct nfsd_net {
218218
/* Simple check to find out if a given net was properly initialized */
219219
#define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl)
220220

221+
extern bool nfsd_support_version(int vers);
221222
extern void nfsd_netns_free_versions(struct nfsd_net *nn);
222223

223224
extern unsigned int nfsd_net_id;

fs/nfsd/nfsctl.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,6 +1796,156 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
17961796
return err;
17971797
}
17981798

1799+
/**
1800+
* nfsd_nl_version_set_doit - set the nfs enabled versions
1801+
* @skb: reply buffer
1802+
* @info: netlink metadata and command arguments
1803+
*
1804+
* Return 0 on success or a negative errno.
1805+
*/
1806+
int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info)
1807+
{
1808+
const struct nlattr *attr;
1809+
struct nfsd_net *nn;
1810+
int i, rem;
1811+
1812+
if (GENL_REQ_ATTR_CHECK(info, NFSD_A_SERVER_PROTO_VERSION))
1813+
return -EINVAL;
1814+
1815+
mutex_lock(&nfsd_mutex);
1816+
1817+
nn = net_generic(genl_info_net(info), nfsd_net_id);
1818+
if (nn->nfsd_serv) {
1819+
mutex_unlock(&nfsd_mutex);
1820+
return -EBUSY;
1821+
}
1822+
1823+
/* clear current supported versions. */
1824+
nfsd_vers(nn, 2, NFSD_CLEAR);
1825+
nfsd_vers(nn, 3, NFSD_CLEAR);
1826+
for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++)
1827+
nfsd_minorversion(nn, i, NFSD_CLEAR);
1828+
1829+
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
1830+
struct nlattr *tb[NFSD_A_VERSION_MAX + 1];
1831+
u32 major, minor = 0;
1832+
bool enabled;
1833+
1834+
if (nla_type(attr) != NFSD_A_SERVER_PROTO_VERSION)
1835+
continue;
1836+
1837+
if (nla_parse_nested(tb, NFSD_A_VERSION_MAX, attr,
1838+
nfsd_version_nl_policy, info->extack) < 0)
1839+
continue;
1840+
1841+
if (!tb[NFSD_A_VERSION_MAJOR])
1842+
continue;
1843+
1844+
major = nla_get_u32(tb[NFSD_A_VERSION_MAJOR]);
1845+
if (tb[NFSD_A_VERSION_MINOR])
1846+
minor = nla_get_u32(tb[NFSD_A_VERSION_MINOR]);
1847+
1848+
enabled = nla_get_flag(tb[NFSD_A_VERSION_ENABLED]);
1849+
1850+
switch (major) {
1851+
case 4:
1852+
nfsd_minorversion(nn, minor, enabled ? NFSD_SET : NFSD_CLEAR);
1853+
break;
1854+
case 3:
1855+
case 2:
1856+
if (!minor)
1857+
nfsd_vers(nn, major, enabled ? NFSD_SET : NFSD_CLEAR);
1858+
break;
1859+
default:
1860+
break;
1861+
}
1862+
}
1863+
1864+
mutex_unlock(&nfsd_mutex);
1865+
1866+
return 0;
1867+
}
1868+
1869+
/**
1870+
* nfsd_nl_version_get_doit - get the enabled status for all supported nfs versions
1871+
* @skb: reply buffer
1872+
* @info: netlink metadata and command arguments
1873+
*
1874+
* Return 0 on success or a negative errno.
1875+
*/
1876+
int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info)
1877+
{
1878+
struct nfsd_net *nn;
1879+
int i, err;
1880+
void *hdr;
1881+
1882+
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1883+
if (!skb)
1884+
return -ENOMEM;
1885+
1886+
hdr = genlmsg_iput(skb, info);
1887+
if (!hdr) {
1888+
err = -EMSGSIZE;
1889+
goto err_free_msg;
1890+
}
1891+
1892+
mutex_lock(&nfsd_mutex);
1893+
nn = net_generic(genl_info_net(info), nfsd_net_id);
1894+
1895+
for (i = 2; i <= 4; i++) {
1896+
int j;
1897+
1898+
for (j = 0; j <= NFSD_SUPPORTED_MINOR_VERSION; j++) {
1899+
struct nlattr *attr;
1900+
1901+
/* Don't record any versions the kernel doesn't have
1902+
* compiled in
1903+
*/
1904+
if (!nfsd_support_version(i))
1905+
continue;
1906+
1907+
/* NFSv{2,3} does not support minor numbers */
1908+
if (i < 4 && j)
1909+
continue;
1910+
1911+
attr = nla_nest_start(skb,
1912+
NFSD_A_SERVER_PROTO_VERSION);
1913+
if (!attr) {
1914+
err = -EINVAL;
1915+
goto err_nfsd_unlock;
1916+
}
1917+
1918+
if (nla_put_u32(skb, NFSD_A_VERSION_MAJOR, i) ||
1919+
nla_put_u32(skb, NFSD_A_VERSION_MINOR, j)) {
1920+
err = -EINVAL;
1921+
goto err_nfsd_unlock;
1922+
}
1923+
1924+
/* Set the enabled flag if the version is enabled */
1925+
if (nfsd_vers(nn, i, NFSD_TEST) &&
1926+
(i < 4 || nfsd_minorversion(nn, j, NFSD_TEST)) &&
1927+
nla_put_flag(skb, NFSD_A_VERSION_ENABLED)) {
1928+
err = -EINVAL;
1929+
goto err_nfsd_unlock;
1930+
}
1931+
1932+
nla_nest_end(skb, attr);
1933+
}
1934+
}
1935+
1936+
mutex_unlock(&nfsd_mutex);
1937+
genlmsg_end(skb, hdr);
1938+
1939+
return genlmsg_reply(skb, info);
1940+
1941+
err_nfsd_unlock:
1942+
mutex_unlock(&nfsd_mutex);
1943+
err_free_msg:
1944+
nlmsg_free(skb);
1945+
1946+
return err;
1947+
}
1948+
17991949
/**
18001950
* nfsd_net_init - Prepare the nfsd_net portion of a new net namespace
18011951
* @net: a freshly-created network namespace

fs/nfsd/nfssvc.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ struct svc_program nfsd_program = {
133133
.pg_rpcbind_set = nfsd_rpcbind_set,
134134
};
135135

136-
static bool
137-
nfsd_support_version(int vers)
136+
bool nfsd_support_version(int vers)
138137
{
139138
if (vers >= NFSD_MINVERS && vers < NFSD_NRVERS)
140139
return nfsd_version[vers] != NULL;

include/uapi/linux/nfsd_netlink.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,28 @@ enum {
3939
NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1)
4040
};
4141

42+
enum {
43+
NFSD_A_VERSION_MAJOR = 1,
44+
NFSD_A_VERSION_MINOR,
45+
NFSD_A_VERSION_ENABLED,
46+
47+
__NFSD_A_VERSION_MAX,
48+
NFSD_A_VERSION_MAX = (__NFSD_A_VERSION_MAX - 1)
49+
};
50+
51+
enum {
52+
NFSD_A_SERVER_PROTO_VERSION = 1,
53+
54+
__NFSD_A_SERVER_PROTO_MAX,
55+
NFSD_A_SERVER_PROTO_MAX = (__NFSD_A_SERVER_PROTO_MAX - 1)
56+
};
57+
4258
enum {
4359
NFSD_CMD_RPC_STATUS_GET = 1,
4460
NFSD_CMD_THREADS_SET,
4561
NFSD_CMD_THREADS_GET,
62+
NFSD_CMD_VERSION_SET,
63+
NFSD_CMD_VERSION_GET,
4664

4765
__NFSD_CMD_MAX,
4866
NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)

0 commit comments

Comments
 (0)