Re: [PATCH v2 3/3] nfsdctl: add necessary bits to configure lockd

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2025-01-10 at 10:05 -0500, Tom Talpey wrote:
> On 1/10/2025 8:46 AM, Jeff Layton wrote:
> > The legacy rpc.nfsd program would configure the nlm_grace_period to
> > match the NFSv4 grace period when starting the server. This adds similar
> > functionality to the autostart subcommand using the new lockd netlink
> > configuration interfaces. In addition, if lockd's udp or tcp listener
> > ports are specified, also configure them before starting the server.
> > 
> > A "nlm" subcommand is also added that will display the current lockd
> > config settings in the current net ns. In the future, we could add the
> > ability to set these values using the "nlm" subcommand, but for now I
> > didn't see a real use-case for that, so I left it out.
> 
> It seems unnatural that the nlm_grace_period is tied to the netns.
>
> It seems to me it's more dependent on the network and its likely
> failure modes, the backend storage/filesystem, and perhaps the
> scale of clients performing possibly-conflicting locks. Oh, and
> also perhaps the minor version, since 4.1+ have the RECLAIM_COMPLETE
> termination event.
> 
> Food for thought, perhaps.
> 
> Tom.
> 

Fair point. More food:

My guess is that nlm_grace_period handling is likely horribly broken in
multi-container scenarios anyway. If you have multiple nfs server
containers with different grace period settings, then they will all be
competing to set the global nlm_grace_period.

Most clients end up reclaiming quickly enough that we don't hit major
problems here, but it would be good to make this more "airtight".

> > 
> > Link: https://issues.redhat.com/browse/RHEL-71698
> > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> > ---
> >   configure.ac                  |   4 +
> >   utils/nfsdctl/lockd_netlink.h |  29 ++++++
> >   utils/nfsdctl/nfsdctl.8       |   6 ++
> >   utils/nfsdctl/nfsdctl.adoc    |   5 +
> >   utils/nfsdctl/nfsdctl.c       | 218 +++++++++++++++++++++++++++++++++++++++---
> >   5 files changed, 249 insertions(+), 13 deletions(-)
> > 
> > diff --git a/configure.ac b/configure.ac
> > index 561e894dc46f48997df4ba6dc3e7691876589fdb..1d865fbc1c7f79e3ac6152bc59995e99fe10a38e 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -268,6 +268,10 @@ AC_ARG_ENABLE(nfsdctl,
> >   				                   [[int foo = NFSD_CMD_POOL_MODE_GET;]])],
> >   				   [AC_DEFINE([USE_SYSTEM_NFSD_NETLINK_H], 1,
> >   					      ["Use system's linux/nfsd_netlink.h"])])
> > +		AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <linux/lockd_netlink.h>]],
> > +				                   [[int foo = LOCKD_CMD_SERVER_GET;]])],
> > +				   [AC_DEFINE([USE_SYSTEM_LOCKD_NETLINK_H], 1,
> > +					      ["Use system's linux/lockd_netlink.h"])])
> >   	fi
> >   
> >   AC_ARG_ENABLE(nfsv4server,
> > diff --git a/utils/nfsdctl/lockd_netlink.h b/utils/nfsdctl/lockd_netlink.h
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..21c65aec3bc6d1839961937081e6d16540332179
> > --- /dev/null
> > +++ b/utils/nfsdctl/lockd_netlink.h
> > @@ -0,0 +1,29 @@
> > +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
> > +/* Do not edit directly, auto-generated from: */
> > +/*	Documentation/netlink/specs/lockd.yaml */
> > +/* YNL-GEN uapi header */
> > +
> > +#ifndef _UAPI_LINUX_LOCKD_NETLINK_H
> > +#define _UAPI_LINUX_LOCKD_NETLINK_H
> > +
> > +#define LOCKD_FAMILY_NAME	"lockd"
> > +#define LOCKD_FAMILY_VERSION	1
> > +
> > +enum {
> > +	LOCKD_A_SERVER_GRACETIME = 1,
> > +	LOCKD_A_SERVER_TCP_PORT,
> > +	LOCKD_A_SERVER_UDP_PORT,
> > +
> > +	__LOCKD_A_SERVER_MAX,
> > +	LOCKD_A_SERVER_MAX = (__LOCKD_A_SERVER_MAX - 1)
> > +};
> > +
> > +enum {
> > +	LOCKD_CMD_SERVER_SET = 1,
> > +	LOCKD_CMD_SERVER_GET,
> > +
> > +	__LOCKD_CMD_MAX,
> > +	LOCKD_CMD_MAX = (__LOCKD_CMD_MAX - 1)
> > +};
> > +
> > +#endif /* _UAPI_LINUX_LOCKD_NETLINK_H */
> > diff --git a/utils/nfsdctl/nfsdctl.8 b/utils/nfsdctl/nfsdctl.8
> > index 39ae1855ae50e94da113981d5e8cf8ac14440c3a..d69922448eb17fb155f05dc4ddc9aefffbf966e4 100644
> > --- a/utils/nfsdctl/nfsdctl.8
> > +++ b/utils/nfsdctl/nfsdctl.8
> > @@ -127,6 +127,12 @@ colon separated form, and must be enclosed in square brackets.
> >   .if n .RE
> >   .RE
> >   .sp
> > +\fBnlm\fP
> > +.RS 4
> > +Get information about NLM (lockd) settings in the current net namespace. This
> > +subcommand takes no arguments.
> > +.RE
> > +.sp
> >   \fBstatus\fP
> >   .RS 4
> >   Get information about RPCs currently executing in the server. This subcommand
> > diff --git a/utils/nfsdctl/nfsdctl.adoc b/utils/nfsdctl/nfsdctl.adoc
> > index 2114693042594297b7c5d8600ca16813a0f2356c..0207eff6118d2dcc5a794d2013c039d9beb11ddc 100644
> > --- a/utils/nfsdctl/nfsdctl.adoc
> > +++ b/utils/nfsdctl/nfsdctl.adoc
> > @@ -67,6 +67,11 @@ Each subcommand can also accept its own set of options and arguments. The
> >     addresses must be in dotted-quad form. IPv6 addresses should be in standard
> >     colon separated form, and must be enclosed in square brackets.
> >   
> > +*nlm*::
> > +
> > +  Get information about NLM (lockd) settings in the current net namespace. This
> > +  subcommand takes no arguments.
> > +
> >   *status*::
> >   
> >     Get information about RPCs currently executing in the server. This subcommand
> > diff --git a/utils/nfsdctl/nfsdctl.c b/utils/nfsdctl/nfsdctl.c
> > index 5c319a74273fd2bbe84003c1261043c4b2f1ff29..003daba5f30a403eb4168f6103e5a496d96968a4 100644
> > --- a/utils/nfsdctl/nfsdctl.c
> > +++ b/utils/nfsdctl/nfsdctl.c
> > @@ -35,6 +35,12 @@
> >   #include "nfsd_netlink.h"
> >   #endif
> >   
> > +#ifdef USE_SYSTEM_LOCKD_NETLINK_H
> > +#include <linux/lockd_netlink.h>
> > +#else
> > +#include "lockd_netlink.h"
> > +#endif
> > +
> >   #include "nfsdctl.h"
> >   #include "conffile.h"
> >   #include "xlog.h"
> > @@ -348,6 +354,28 @@ static void parse_pool_mode_get(struct genlmsghdr *gnlh)
> >   	}
> >   }
> >   
> > +static void parse_lockd_get(struct genlmsghdr *gnlh)
> > +{
> > +	struct nlattr *attr;
> > +	int rem;
> > +
> > +	nla_for_each_attr(attr, genlmsg_attrdata(gnlh, 0),
> > +			  genlmsg_attrlen(gnlh, 0), rem) {
> > +		switch (nla_type(attr)) {
> > +		case LOCKD_A_SERVER_GRACETIME:
> > +			printf("gracetime: %u\n", nla_get_u32(attr));
> > +			break;
> > +		case LOCKD_A_SERVER_TCP_PORT:
> > +			printf("tcp_port: %hu\n", nla_get_u16(attr));
> > +			break;
> > +		case LOCKD_A_SERVER_UDP_PORT:
> > +			printf("udp_port: %hu\n", nla_get_u16(attr));
> > +			break;
> > +		default:
> > +			break;
> > +		}
> > +	}
> > +}
> >   static int recv_handler(struct nl_msg *msg, void *arg)
> >   {
> >   	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
> > @@ -368,6 +396,9 @@ static int recv_handler(struct nl_msg *msg, void *arg)
> >   	case NFSD_CMD_POOL_MODE_GET:
> >   		parse_pool_mode_get(gnlh);
> >   		break;
> > +	case LOCKD_CMD_SERVER_GET:
> > +		parse_lockd_get(gnlh);
> > +		break;
> >   	default:
> >   		break;
> >   	}
> > @@ -398,12 +429,12 @@ static struct nl_sock *netlink_sock_alloc(void)
> >   	return sock;
> >   }
> >   
> > -static struct nl_msg *netlink_msg_alloc(struct nl_sock *sock)
> > +static struct nl_msg *netlink_msg_alloc(struct nl_sock *sock, const char *family)
> >   {
> >   	struct nl_msg *msg;
> >   	int id;
> >   
> > -	id = genl_ctrl_resolve(sock, NFSD_FAMILY_NAME);
> > +	id = genl_ctrl_resolve(sock, family);
> >   	if (id < 0) {
> >   		xlog(L_ERROR, "%s not found", NFSD_FAMILY_NAME);
> >   		return NULL;
> > @@ -447,7 +478,7 @@ static int status_func(struct nl_sock *sock, int argc, char ** argv)
> >   		}
> >   	}
> >   
> > -	msg = netlink_msg_alloc(sock);
> > +	msg = netlink_msg_alloc(sock, NFSD_FAMILY_NAME);
> >   	if (!msg)
> >   		return 1;
> >   
> > @@ -495,7 +526,7 @@ static int threads_doit(struct nl_sock *sock, int cmd, int grace, int lease,
> >   	struct nl_cb *cb;
> >   	int ret;
> >   
> > -	msg = netlink_msg_alloc(sock);
> > +	msg = netlink_msg_alloc(sock, NFSD_FAMILY_NAME);
> >   	if (!msg)
> >   		return 1;
> >   
> > @@ -607,7 +638,7 @@ static int fetch_nfsd_versions(struct nl_sock *sock)
> >   	struct nl_cb *cb;
> >   	int ret;
> >   
> > -	msg = netlink_msg_alloc(sock);
> > +	msg = netlink_msg_alloc(sock, NFSD_FAMILY_NAME);
> >   	if (!msg)
> >   		return 1;
> >   
> > @@ -672,7 +703,7 @@ static int set_nfsd_versions(struct nl_sock *sock)
> >   	struct nl_cb *cb;
> >   	int i, ret;
> >   
> > -	msg = netlink_msg_alloc(sock);
> > +	msg = netlink_msg_alloc(sock, NFSD_FAMILY_NAME);
> >   	if (!msg)
> >   		return 1;
> >   
> > @@ -825,7 +856,7 @@ static int fetch_current_listeners(struct nl_sock *sock)
> >   	struct nl_cb *cb;
> >   	int ret;
> >   
> > -	msg = netlink_msg_alloc(sock);
> > +	msg = netlink_msg_alloc(sock, NFSD_FAMILY_NAME);
> >   	if (!msg)
> >   		return 1;
> >   
> > @@ -1054,7 +1085,7 @@ static int set_listeners(struct nl_sock *sock)
> >   	struct nl_cb *cb;
> >   	int i, ret;
> >   
> > -	msg = netlink_msg_alloc(sock);
> > +	msg = netlink_msg_alloc(sock, NFSD_FAMILY_NAME);
> >   	if (!msg)
> >   		return 1;
> >   
> > @@ -1170,7 +1201,7 @@ static int pool_mode_doit(struct nl_sock *sock, int cmd, const char *pool_mode)
> >   	struct nl_cb *cb;
> >   	int ret;
> >   
> > -	msg = netlink_msg_alloc(sock);
> > +	msg = netlink_msg_alloc(sock, NFSD_FAMILY_NAME);
> >   	if (!msg)
> >   		return 1;
> >   
> > @@ -1249,6 +1280,131 @@ static int pool_mode_func(struct nl_sock *sock, int argc, char **argv)
> >   	return pool_mode_doit(sock, cmd, pool_mode);
> >   }
> >   
> > +static int lockd_config_doit(struct nl_sock *sock, int cmd, int grace, int tcpport, int udpport)
> > +{
> > +	struct genlmsghdr *ghdr;
> > +	struct nlmsghdr *nlh;
> > +	struct nl_msg *msg;
> > +	struct nl_cb *cb;
> > +	int ret;
> > +
> > +	if (cmd == LOCKD_CMD_SERVER_SET) {
> > +		/* Do nothing if there is nothing to set */
> > +		if (!grace && !tcpport && !udpport)
> > +			return 0;
> > +	}
> > +
> > +	msg = netlink_msg_alloc(sock, LOCKD_FAMILY_NAME);
> > +	if (!msg)
> > +		return 1;
> > +
> > +	nlh = nlmsg_hdr(msg);
> > +	if (cmd == LOCKD_CMD_SERVER_SET) {
> > +		if (grace)
> > +			nla_put_u32(msg, LOCKD_A_SERVER_GRACETIME, grace);
> > +		if (tcpport)
> > +			nla_put_u16(msg, LOCKD_A_SERVER_TCP_PORT, tcpport);
> > +		if (udpport)
> > +			nla_put_u16(msg, LOCKD_A_SERVER_UDP_PORT, udpport);
> > +	}
> > +
> > +	ghdr = nlmsg_data(nlh);
> > +	ghdr->cmd = cmd;
> > +
> > +	cb = nl_cb_alloc(NL_CB_CUSTOM);
> > +	if (!cb) {
> > +		xlog(L_ERROR, "failed to allocate netlink callbacks\n");
> > +		ret = 1;
> > +		goto out;
> > +	}
> > +
> > +	ret = nl_send_auto(sock, msg);
> > +	if (ret < 0) {
> > +		xlog(L_ERROR, "send failed (%d)!\n", ret);
> > +		goto out_cb;
> > +	}
> > +
> > +	ret = 1;
> > +	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
> > +	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &ret);
> > +	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
> > +	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, recv_handler, NULL);
> > +
> > +	while (ret > 0)
> > +		nl_recvmsgs(sock, cb);
> > +	if (ret < 0) {
> > +		xlog(L_ERROR, "Error: %s\n", strerror(-ret));
> > +		ret = 1;
> > +	}
> > +out_cb:
> > +	nl_cb_put(cb);
> > +out:
> > +	nlmsg_free(msg);
> > +	return ret;
> > +}
> > +
> > +static int get_service(const char *svc)
> > +{
> > +	struct addrinfo *res, hints = { .ai_flags = AI_PASSIVE };
> > +	int ret, port;
> > +
> > +	if (!svc)
> > +		return 0;
> > +
> > +	ret = getaddrinfo(NULL, svc, &hints, &res);
> > +	if (ret) {
> > +		xlog(L_ERROR, "getaddrinfo of \"%s\" failed: %s\n",
> > +			svc, gai_strerror(ret));
> > +		return -1;
> > +	}
> > +
> > +	switch (res->ai_family) {
> > +	case AF_INET:
> > +		{
> > +			struct sockaddr_in *sin = (struct sockaddr_in *)res->ai_addr;
> > +
> > +			port = ntohs(sin->sin_port);
> > +		}
> > +		break;
> > +	case AF_INET6:
> > +		{
> > +			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
> > +
> > +			port = ntohs(sin6->sin6_port);
> > +		}
> > +		break;
> > +	default:
> > +		xlog(L_ERROR, "Bad address family: %d\n", res->ai_family);
> > +		port = -1;
> > +	}
> > +	freeaddrinfo(res);
> > +	return port;
> > +}
> > +
> > +static int lockd_configure(struct nl_sock *sock, int grace)
> > +{
> > +	char *tcp_svc, *udp_svc;
> > +	int tcpport = 0, udpport = 0;
> > +	int ret;
> > +
> > +	tcp_svc = conf_get_str("lockd", "port");
> > +	if (tcp_svc) {
> > +		tcpport = get_service(tcp_svc);
> > +		if (tcpport < 0)
> > +			return 1;
> > +	}
> > +
> > +	udp_svc = conf_get_str("lockd", "udp-port");
> > +	if (udp_svc) {
> > +		udpport = get_service(udp_svc);
> > +		if (udpport < 0)
> > +			return 1;
> > +	}
> > +
> > +	return lockd_config_doit(sock, LOCKD_CMD_SERVER_SET, grace, tcpport, udpport);
> > +}
> > +
> > +
> >   #define MAX_LISTENER_LEN (64 * 2 + 16)
> >   
> >   static void
> > @@ -1355,6 +1511,13 @@ static int autostart_func(struct nl_sock *sock, int argc, char ** argv)
> >   
> >   	read_nfsd_conf();
> >   
> > +	grace = conf_get_num("nfsd", "grace-time", 0);
> > +	ret = lockd_configure(sock, grace);
> > +	if (ret) {
> > +		xlog(L_ERROR, "lockd configuration failure");
> > +		return ret;
> > +	}
> > +
> >   	pool_mode = conf_get_str("nfsd", "pool-mode");
> >   	if (pool_mode) {
> >   		ret = pool_mode_doit(sock, NFSD_CMD_POOL_MODE_SET, pool_mode);
> > @@ -1370,15 +1533,12 @@ static int autostart_func(struct nl_sock *sock, int argc, char ** argv)
> >   	if (ret)
> >   		return ret;
> >   
> > +	xlog(D_GENERAL, "configuring listeners");
> >   	configure_listeners();
> >   	ret = set_listeners(sock);
> >   	if (ret)
> >   		return ret;
> >   
> > -	grace = conf_get_num("nfsd", "grace-time", 0);
> > -	lease = conf_get_num("nfsd", "lease-time", 0);
> > -	scope = conf_get_str("nfsd", "scope");
> > -
> >   	thread_str = conf_get_list("nfsd", "threads");
> >   	pools = thread_str ? thread_str->cnt : 1;
> >   
> > @@ -1402,6 +1562,9 @@ static int autostart_func(struct nl_sock *sock, int argc, char ** argv)
> >   		threads[0] = DEFAULT_AUTOSTART_THREADS;
> >   	}
> >   
> > +	lease = conf_get_num("nfsd", "lease-time", 0);
> > +	scope = conf_get_str("nfsd", "scope");
> > +
> >   	ret = threads_doit(sock, NFSD_CMD_THREADS_SET, grace, lease, pools,
> >   			   threads, scope);
> >   out:
> > @@ -1409,6 +1572,30 @@ out:
> >   	return ret;
> >   }
> >   
> > +static void nlm_usage(void)
> > +{
> > +	printf("Usage: %s nlm\n", taskname);
> > +	printf("    Get the current settings for the NLM (lockd) server.\n");
> > +}
> > +
> > +static int nlm_func(struct nl_sock *sock, int argc, char ** argv)
> > +{
> > +	int *threads, grace, lease, idx, ret, opt, pools;
> > +	struct conf_list *thread_str;
> > +	struct conf_list_node *n;
> > +	char *scope, *pool_mode;
> > +
> > +	optind = 1;
> > +	while ((opt = getopt_long(argc, argv, "h", help_only_options, NULL)) != -1) {
> > +		switch (opt) {
> > +		case 'h':
> > +			nlm_usage();
> > +			return 0;
> > +		}
> > +	}
> > +	return lockd_config_doit(sock, LOCKD_CMD_SERVER_GET, 0, 0, 0);
> > +}
> > +
> >   enum nfsdctl_commands {
> >   	NFSDCTL_STATUS,
> >   	NFSDCTL_THREADS,
> > @@ -1416,6 +1603,7 @@ enum nfsdctl_commands {
> >   	NFSDCTL_LISTENER,
> >   	NFSDCTL_AUTOSTART,
> >   	NFSDCTL_POOL_MODE,
> > +	NFSDCTL_NLM,
> >   };
> >   
> >   static int parse_command(char *str)
> > @@ -1432,6 +1620,8 @@ static int parse_command(char *str)
> >   		return NFSDCTL_AUTOSTART;
> >   	if (!strcmp(str, "pool-mode"))
> >   		return NFSDCTL_POOL_MODE;
> > +	if (!strcmp(str, "nlm"))
> > +		return NFSDCTL_NLM;
> >   	return -1;
> >   }
> >   
> > @@ -1444,6 +1634,7 @@ static nfsdctl_func func[] = {
> >   	[NFSDCTL_LISTENER] = listener_func,
> >   	[NFSDCTL_AUTOSTART] = autostart_func,
> >   	[NFSDCTL_POOL_MODE] = pool_mode_func,
> > +	[NFSDCTL_NLM] = nlm_func,
> >   };
> >   
> >   static void usage(void)
> > @@ -1460,6 +1651,7 @@ static void usage(void)
> >   	printf("    listener             get/set listener info\n");
> >   	printf("    version              get/set supported NFS versions\n");
> >   	printf("    threads              get/set nfsd thread settings\n");
> > +	printf("    nlm                  get current nlm settings\n");
> >   	printf("    status               get current RPC processing info\n");
> >   	printf("    autostart            start server with settings from /etc/nfs.conf\n");
> >   }
> > 
> 

-- 
Jeff Layton <jlayton@xxxxxxxxxx>





[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux