Skip to content

Commit 9a28ac1

Browse files
jtlaytonchucklever
authored andcommitted
lockd: add netlink control interface
The legacy rpc.nfsd tool will set the nlm_grace_period if the NFSv4 grace period is set. nfsdctl is missing this functionality, so add a new netlink control interface for lockd that it can use. For now, it only allows setting the grace period, and the tcp and udp listener ports. lockd currently uses module parameters and sysctls for configuration, so all of its settings are global. With this change, lockd now tracks these values on a per-net-ns basis. It will only fall back to using the global values if any of them are 0. Finally, as a backward compatibility measure, if updating the nlm settings in the init_net namespace, also update the legacy global values to match. Link: https://issues.redhat.com/browse/RHEL-71698 Signed-off-by: Jeff Layton <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent fc2a169 commit 9a28ac1

File tree

7 files changed

+253
-7
lines changed

7 files changed

+253
-7
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
2+
3+
name: lockd
4+
protocol: genetlink
5+
uapi-header: linux/lockd_netlink.h
6+
7+
doc: lockd configuration over generic netlink
8+
9+
attribute-sets:
10+
-
11+
name: server
12+
attributes:
13+
-
14+
name: gracetime
15+
type: u32
16+
-
17+
name: tcp-port
18+
type: u16
19+
-
20+
name: udp-port
21+
type: u16
22+
23+
operations:
24+
list:
25+
-
26+
name: server-set
27+
doc: set the lockd server parameters
28+
attribute-set: server
29+
flags: [ admin-perm ]
30+
do:
31+
request:
32+
attributes:
33+
- gracetime
34+
- tcp-port
35+
- udp-port
36+
-
37+
name: server-get
38+
doc: get the lockd server parameters
39+
attribute-set: server
40+
do:
41+
reply:
42+
attributes:
43+
- gracetime
44+
- tcp-port
45+
- udp-port

fs/lockd/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ ccflags-y += -I$(src) # needed for trace events
88
obj-$(CONFIG_LOCKD) += lockd.o
99

1010
lockd-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \
11-
svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o
11+
svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o netlink.o
1212
lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o
1313
lockd-$(CONFIG_PROC_FS) += procfs.o

fs/lockd/netlink.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
2+
/* Do not edit directly, auto-generated from: */
3+
/* Documentation/netlink/specs/lockd.yaml */
4+
/* YNL-GEN kernel source */
5+
6+
#include <net/netlink.h>
7+
#include <net/genetlink.h>
8+
9+
#include "netlink.h"
10+
11+
#include <uapi/linux/lockd_netlink.h>
12+
13+
/* LOCKD_CMD_SERVER_SET - do */
14+
static const struct nla_policy lockd_server_set_nl_policy[LOCKD_A_SERVER_UDP_PORT + 1] = {
15+
[LOCKD_A_SERVER_GRACETIME] = { .type = NLA_U32, },
16+
[LOCKD_A_SERVER_TCP_PORT] = { .type = NLA_U16, },
17+
[LOCKD_A_SERVER_UDP_PORT] = { .type = NLA_U16, },
18+
};
19+
20+
/* Ops table for lockd */
21+
static const struct genl_split_ops lockd_nl_ops[] = {
22+
{
23+
.cmd = LOCKD_CMD_SERVER_SET,
24+
.doit = lockd_nl_server_set_doit,
25+
.policy = lockd_server_set_nl_policy,
26+
.maxattr = LOCKD_A_SERVER_UDP_PORT,
27+
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
28+
},
29+
{
30+
.cmd = LOCKD_CMD_SERVER_GET,
31+
.doit = lockd_nl_server_get_doit,
32+
.flags = GENL_CMD_CAP_DO,
33+
},
34+
};
35+
36+
struct genl_family lockd_nl_family __ro_after_init = {
37+
.name = LOCKD_FAMILY_NAME,
38+
.version = LOCKD_FAMILY_VERSION,
39+
.netnsok = true,
40+
.parallel_ops = true,
41+
.module = THIS_MODULE,
42+
.split_ops = lockd_nl_ops,
43+
.n_split_ops = ARRAY_SIZE(lockd_nl_ops),
44+
};

fs/lockd/netlink.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2+
/* Do not edit directly, auto-generated from: */
3+
/* Documentation/netlink/specs/lockd.yaml */
4+
/* YNL-GEN kernel header */
5+
6+
#ifndef _LINUX_LOCKD_GEN_H
7+
#define _LINUX_LOCKD_GEN_H
8+
9+
#include <net/netlink.h>
10+
#include <net/genetlink.h>
11+
12+
#include <uapi/linux/lockd_netlink.h>
13+
14+
int lockd_nl_server_set_doit(struct sk_buff *skb, struct genl_info *info);
15+
int lockd_nl_server_get_doit(struct sk_buff *skb, struct genl_info *info);
16+
17+
extern struct genl_family lockd_nl_family;
18+
19+
#endif /* _LINUX_LOCKD_GEN_H */

fs/lockd/netns.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ struct lockd_net {
1010
unsigned int nlmsvc_users;
1111
unsigned long next_gc;
1212
unsigned long nrhosts;
13+
u32 gracetime;
14+
u16 tcp_port;
15+
u16 udp_port;
1316

1417
struct delayed_work grace_period_end;
1518
struct lock_manager lockd_manager;

fs/lockd/svc.c

Lines changed: 112 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
#include "netns.h"
4343
#include "procfs.h"
44+
#include "netlink.h"
4445

4546
#define NLMDBG_FACILITY NLMDBG_SVC
4647
#define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE)
@@ -83,8 +84,14 @@ static const int nlm_port_min = 0, nlm_port_max = 65535;
8384
static struct ctl_table_header * nlm_sysctl_table;
8485
#endif
8586

86-
static unsigned long get_lockd_grace_period(void)
87+
static unsigned long get_lockd_grace_period(struct net *net)
8788
{
89+
struct lockd_net *ln = net_generic(net, lockd_net_id);
90+
91+
/* Return the net-ns specific grace period, if there is one */
92+
if (ln->gracetime)
93+
return ln->gracetime * HZ;
94+
8895
/* Note: nlm_timeout should always be nonzero */
8996
if (nlm_grace_period)
9097
return roundup(nlm_grace_period, nlm_timeout) * HZ;
@@ -103,7 +110,7 @@ static void grace_ender(struct work_struct *grace)
103110

104111
static void set_grace_period(struct net *net)
105112
{
106-
unsigned long grace_period = get_lockd_grace_period();
113+
unsigned long grace_period = get_lockd_grace_period(net);
107114
struct lockd_net *ln = net_generic(net, lockd_net_id);
108115

109116
locks_start_grace(net, &ln->lockd_manager);
@@ -166,15 +173,16 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name,
166173
static int create_lockd_family(struct svc_serv *serv, struct net *net,
167174
const int family, const struct cred *cred)
168175
{
176+
struct lockd_net *ln = net_generic(net, lockd_net_id);
169177
int err;
170178

171-
err = create_lockd_listener(serv, "udp", net, family, nlm_udpport,
172-
cred);
179+
err = create_lockd_listener(serv, "udp", net, family,
180+
ln->udp_port ? ln->udp_port : nlm_udpport, cred);
173181
if (err < 0)
174182
return err;
175183

176-
return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport,
177-
cred);
184+
return create_lockd_listener(serv, "tcp", net, family,
185+
ln->tcp_port ? ln->tcp_port : nlm_tcpport, cred);
178186
}
179187

180188
/*
@@ -588,13 +596,19 @@ static int __init init_nlm(void)
588596
if (err)
589597
goto err_pernet;
590598

599+
err = genl_register_family(&lockd_nl_family);
600+
if (err)
601+
goto err_netlink;
602+
591603
err = lockd_create_procfs();
592604
if (err)
593605
goto err_procfs;
594606

595607
return 0;
596608

597609
err_procfs:
610+
genl_unregister_family(&lockd_nl_family);
611+
err_netlink:
598612
unregister_pernet_subsys(&lockd_net_ops);
599613
err_pernet:
600614
#ifdef CONFIG_SYSCTL
@@ -608,6 +622,7 @@ static void __exit exit_nlm(void)
608622
{
609623
/* FIXME: delete all NLM clients */
610624
nlm_shutdown_hosts();
625+
genl_unregister_family(&lockd_nl_family);
611626
lockd_remove_procfs();
612627
unregister_pernet_subsys(&lockd_net_ops);
613628
#ifdef CONFIG_SYSCTL
@@ -710,3 +725,94 @@ static struct svc_program nlmsvc_program = {
710725
.pg_init_request = svc_generic_init_request,
711726
.pg_rpcbind_set = svc_generic_rpcbind_set,
712727
};
728+
729+
/**
730+
* lockd_nl_server_set_doit - set the lockd server parameters via netlink
731+
* @skb: reply buffer
732+
* @info: netlink metadata and command arguments
733+
*
734+
* This updates the per-net values. When updating the values in the init_net
735+
* namespace, also update the "legacy" global values.
736+
*
737+
* Return 0 on success or a negative errno.
738+
*/
739+
int lockd_nl_server_set_doit(struct sk_buff *skb, struct genl_info *info)
740+
{
741+
struct net *net = genl_info_net(info);
742+
struct lockd_net *ln = net_generic(net, lockd_net_id);
743+
const struct nlattr *attr;
744+
745+
if (GENL_REQ_ATTR_CHECK(info, LOCKD_A_SERVER_GRACETIME))
746+
return -EINVAL;
747+
748+
if (info->attrs[LOCKD_A_SERVER_GRACETIME] ||
749+
info->attrs[LOCKD_A_SERVER_TCP_PORT] ||
750+
info->attrs[LOCKD_A_SERVER_UDP_PORT]) {
751+
attr = info->attrs[LOCKD_A_SERVER_GRACETIME];
752+
if (attr) {
753+
u32 gracetime = nla_get_u32(attr);
754+
755+
if (gracetime > nlm_grace_period_max)
756+
return -EINVAL;
757+
758+
ln->gracetime = gracetime;
759+
760+
if (net == &init_net)
761+
nlm_grace_period = gracetime;
762+
}
763+
764+
attr = info->attrs[LOCKD_A_SERVER_TCP_PORT];
765+
if (attr) {
766+
ln->tcp_port = nla_get_u16(attr);
767+
if (net == &init_net)
768+
nlm_tcpport = ln->tcp_port;
769+
}
770+
771+
attr = info->attrs[LOCKD_A_SERVER_UDP_PORT];
772+
if (attr) {
773+
ln->udp_port = nla_get_u16(attr);
774+
if (net == &init_net)
775+
nlm_udpport = ln->udp_port;
776+
}
777+
}
778+
return 0;
779+
}
780+
781+
/**
782+
* lockd_nl_server_get_doit - get lockd server parameters via netlink
783+
* @skb: reply buffer
784+
* @info: netlink metadata and command arguments
785+
*
786+
* Return 0 on success or a negative errno.
787+
*/
788+
int lockd_nl_server_get_doit(struct sk_buff *skb, struct genl_info *info)
789+
{
790+
struct net *net = genl_info_net(info);
791+
struct lockd_net *ln = net_generic(net, lockd_net_id);
792+
void *hdr;
793+
int err;
794+
795+
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
796+
if (!skb)
797+
return -ENOMEM;
798+
799+
hdr = genlmsg_iput(skb, info);
800+
if (!hdr) {
801+
err = -EMSGSIZE;
802+
goto err_free_msg;
803+
}
804+
805+
err = nla_put_u32(skb, LOCKD_A_SERVER_GRACETIME, ln->gracetime) ||
806+
nla_put_u16(skb, LOCKD_A_SERVER_TCP_PORT, ln->tcp_port) ||
807+
nla_put_u16(skb, LOCKD_A_SERVER_UDP_PORT, ln->udp_port);
808+
if (err)
809+
goto err_free_msg;
810+
811+
genlmsg_end(skb, hdr);
812+
813+
return genlmsg_reply(skb, info);
814+
err_free_msg:
815+
nlmsg_free(skb);
816+
817+
return err;
818+
}

include/uapi/linux/lockd_netlink.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2+
/* Do not edit directly, auto-generated from: */
3+
/* Documentation/netlink/specs/lockd.yaml */
4+
/* YNL-GEN uapi header */
5+
6+
#ifndef _UAPI_LINUX_LOCKD_NETLINK_H
7+
#define _UAPI_LINUX_LOCKD_NETLINK_H
8+
9+
#define LOCKD_FAMILY_NAME "lockd"
10+
#define LOCKD_FAMILY_VERSION 1
11+
12+
enum {
13+
LOCKD_A_SERVER_GRACETIME = 1,
14+
LOCKD_A_SERVER_TCP_PORT,
15+
LOCKD_A_SERVER_UDP_PORT,
16+
17+
__LOCKD_A_SERVER_MAX,
18+
LOCKD_A_SERVER_MAX = (__LOCKD_A_SERVER_MAX - 1)
19+
};
20+
21+
enum {
22+
LOCKD_CMD_SERVER_SET = 1,
23+
LOCKD_CMD_SERVER_GET,
24+
25+
__LOCKD_CMD_MAX,
26+
LOCKD_CMD_MAX = (__LOCKD_CMD_MAX - 1)
27+
};
28+
29+
#endif /* _UAPI_LINUX_LOCKD_NETLINK_H */

0 commit comments

Comments
 (0)