mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] lockd: allow setting ports without setting gracetime
@ 2026-09-23 10:58 Jeff Layton
  2026-09-23 10:58 ` [PATCH 1/2] lockd: allow SERVER_SET without a gracetime attribute Jeff Layton
  2026-09-23 10:58 ` [PATCH 2/2] selftests/nfsd: add lockd netlink configuration tests Jeff Layton
  0 siblings, 2 replies; 3+ messages in thread
From: Jeff Layton @ 2026-09-23 10:58 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker, Chuck Lever, NeilBrown,
	Olga Kornievskaia, Dai Ngo, Tom Talpey, Shuah Khan
  Cc: Scott Mayhew, linux-nfs, linux-kernel, linux-kselftest, Jeff Layton

This fixes a rather silly bug that Scott pointed out to me in a meeting
recently. You currently can't set the ports in lockd via the netlink
interface unless you also set the gracetime. This patch makes them all
properly optional.

We probably want this to go to stable.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
Jeff Layton (2):
      lockd: allow SERVER_SET without a gracetime attribute
      selftests/nfsd: add lockd netlink configuration tests

 fs/lockd/svc.c                                    |  50 ++---
 tools/testing/selftests/nfsd/.gitignore           |   1 +
 tools/testing/selftests/nfsd/Makefile             |   1 +
 tools/testing/selftests/nfsd/nfsd_lockd_netlink.c | 249 ++++++++++++++++++++++
 tools/testing/selftests/nfsd/nfsd_netlink.h       |  90 ++++++--
 5 files changed, 348 insertions(+), 43 deletions(-)
---
base-commit: cab95e6be3ba82bcf4c8be27c2eb20e55238aa41
change-id: 20260922-nfsd-testing-00c12335047d

Best regards,
-- 
Jeff Layton <jlayton@kernel.org>


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/2] lockd: allow SERVER_SET without a gracetime attribute
  2026-09-23 10:58 [PATCH 0/2] lockd: allow setting ports without setting gracetime Jeff Layton
@ 2026-09-23 10:58 ` Jeff Layton
  2026-09-23 10:58 ` [PATCH 2/2] selftests/nfsd: add lockd netlink configuration tests Jeff Layton
  1 sibling, 0 replies; 3+ messages in thread
From: Jeff Layton @ 2026-09-23 10:58 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker, Chuck Lever, NeilBrown,
	Olga Kornievskaia, Dai Ngo, Tom Talpey, Shuah Khan
  Cc: Scott Mayhew, linux-nfs, linux-kernel, linux-kselftest, Jeff Layton

lockd_nl_server_set_doit() required LOCKD_A_SERVER_GRACETIME via
GENL_REQ_ATTR_CHECK(), but all three attributes are optional in
lockd.yaml and each is applied independently below. The effect was that
the tcp and udp ports could not be set on their own.

nfsdctl hits this: with a [lockd] section that sets "port" but no
"grace-time", it sends SERVER_SET with only the two port attributes, and
"nfsdctl autostart" aborts with EINVAL before configuring anything.

Drop the check, along with the now-redundant outer test for "any
attribute present". The gracetime range check is unaffected.

Fixes: 9a28ac1762a7 ("lockd: add netlink control interface")
Assisted-by: LLM
Reported-by: Scott Mayhew <smayhew@redhat.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/lockd/svc.c | 50 ++++++++++++++++++++++----------------------------
 1 file changed, 22 insertions(+), 28 deletions(-)

diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index f0e1a58c9106..8e1b1735acaf 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -704,7 +704,8 @@ static struct svc_program	nlmsvc_program = {
  * @info: netlink metadata and command arguments
  *
  * This updates the per-net values. When updating the values in the init_net
- * namespace, also update the "legacy" global values.
+ * namespace, also update the "legacy" global values. Every attribute is
+ * optional; only the ones present in @info are changed.
  *
  * Return 0 on success or a negative errno.
  */
@@ -714,38 +715,31 @@ int lockd_nl_server_set_doit(struct sk_buff *skb, struct genl_info *info)
 	struct lockd_net *ln = net_generic(net, lockd_net_id);
 	const struct nlattr *attr;
 
-	if (GENL_REQ_ATTR_CHECK(info, LOCKD_A_SERVER_GRACETIME))
-		return -EINVAL;
+	attr = info->attrs[LOCKD_A_SERVER_GRACETIME];
+	if (attr) {
+		u32 gracetime = nla_get_u32(attr);
 
-	if (info->attrs[LOCKD_A_SERVER_GRACETIME] ||
-	    info->attrs[LOCKD_A_SERVER_TCP_PORT] ||
-	    info->attrs[LOCKD_A_SERVER_UDP_PORT]) {
-		attr = info->attrs[LOCKD_A_SERVER_GRACETIME];
-		if (attr) {
-			u32 gracetime = nla_get_u32(attr);
+		if (gracetime > nlm_grace_period_max)
+			return -EINVAL;
 
-			if (gracetime > nlm_grace_period_max)
-				return -EINVAL;
+		ln->gracetime = gracetime;
 
-			ln->gracetime = gracetime;
-
-			if (net == &init_net)
-				nlm_grace_period = gracetime;
-		}
+		if (net == &init_net)
+			nlm_grace_period = gracetime;
+	}
 
-		attr = info->attrs[LOCKD_A_SERVER_TCP_PORT];
-		if (attr) {
-			ln->tcp_port = nla_get_u16(attr);
-			if (net == &init_net)
-				nlm_tcpport = ln->tcp_port;
-		}
+	attr = info->attrs[LOCKD_A_SERVER_TCP_PORT];
+	if (attr) {
+		ln->tcp_port = nla_get_u16(attr);
+		if (net == &init_net)
+			nlm_tcpport = ln->tcp_port;
+	}
 
-		attr = info->attrs[LOCKD_A_SERVER_UDP_PORT];
-		if (attr) {
-			ln->udp_port = nla_get_u16(attr);
-			if (net == &init_net)
-				nlm_udpport = ln->udp_port;
-		}
+	attr = info->attrs[LOCKD_A_SERVER_UDP_PORT];
+	if (attr) {
+		ln->udp_port = nla_get_u16(attr);
+		if (net == &init_net)
+			nlm_udpport = ln->udp_port;
 	}
 	return 0;
 }

-- 
2.55.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 2/2] selftests/nfsd: add lockd netlink configuration tests
  2026-09-23 10:58 [PATCH 0/2] lockd: allow setting ports without setting gracetime Jeff Layton
  2026-09-23 10:58 ` [PATCH 1/2] lockd: allow SERVER_SET without a gracetime attribute Jeff Layton
@ 2026-09-23 10:58 ` Jeff Layton
  1 sibling, 0 replies; 3+ messages in thread
From: Jeff Layton @ 2026-09-23 10:58 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker, Chuck Lever, NeilBrown,
	Olga Kornievskaia, Dai Ngo, Tom Talpey, Shuah Khan
  Cc: Scott Mayhew, linux-nfs, linux-kernel, linux-kselftest, Jeff Layton

Cover LOCKD_CMD_SERVER_SET / SERVER_GET, in particular that each of the
three attributes can be set on its own. Without the preceding fix, four
of the eight tests fail with EINVAL -- every one that omits the grace
time, which is what nfsdctl sends for a [lockd] port with no
grace-time.

Also pinned down here:
- an empty SERVER_SET is a no-op, not an error
- a gracetime over nlm_grace_period_max is still rejected, and the
  rejected request applies none of the ports it came with
- the settings are per-netns

Everything runs under unshare(CLONE_NEWNET): the values are per-netns,
and a SERVER_SET in init_net would overwrite the host's module-wide
nlm_grace_period/nlm_tcpport/nlm_udpport.

nfsd_netlink.h grows genl_resolve() and *_to() request helpers that take
a family id, so the plumbing can drive the lockd family too;
genl_resolve_nfsd() and the existing helpers are thin wrappers and the
other tests are unchanged.

Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 tools/testing/selftests/nfsd/.gitignore           |   1 +
 tools/testing/selftests/nfsd/Makefile             |   1 +
 tools/testing/selftests/nfsd/nfsd_lockd_netlink.c | 249 ++++++++++++++++++++++
 tools/testing/selftests/nfsd/nfsd_netlink.h       |  90 ++++++--
 4 files changed, 326 insertions(+), 15 deletions(-)

diff --git a/tools/testing/selftests/nfsd/.gitignore b/tools/testing/selftests/nfsd/.gitignore
index 2347491c634d..7ac844d0fd57 100644
--- a/tools/testing/selftests/nfsd/.gitignore
+++ b/tools/testing/selftests/nfsd/.gitignore
@@ -1,3 +1,4 @@
+nfsd_lockd_netlink
 nfsd_netlink_listener
 nfsd_netns_isolation
 nfsd_netns_stress
diff --git a/tools/testing/selftests/nfsd/Makefile b/tools/testing/selftests/nfsd/Makefile
index b29bf642c0ad..e74bb3424d45 100644
--- a/tools/testing/selftests/nfsd/Makefile
+++ b/tools/testing/selftests/nfsd/Makefile
@@ -2,6 +2,7 @@
 CFLAGS += $(KHDR_INCLUDES) -Wall
 
 TEST_GEN_PROGS := nfsd_netlink_listener
+TEST_GEN_PROGS += nfsd_lockd_netlink
 TEST_GEN_PROGS += nfsd_netns_isolation
 TEST_GEN_PROGS += nfsd_netns_stress
 
diff --git a/tools/testing/selftests/nfsd/nfsd_lockd_netlink.c b/tools/testing/selftests/nfsd/nfsd_lockd_netlink.c
new file mode 100644
index 000000000000..89f68c5708ad
--- /dev/null
+++ b/tools/testing/selftests/nfsd/nfsd_lockd_netlink.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Regression tests for lockd's generic-netlink configuration interface
+ * (LOCKD_CMD_SERVER_SET / LOCKD_CMD_SERVER_GET).
+ *
+ * All three attributes are optional in the spec and each is applied on its
+ * own by the kernel, but SERVER_SET used to demand a grace time and reject
+ * anything else with -EINVAL. That made the tcp and udp ports unsettable by
+ * themselves, which is exactly what nfsdctl asks for when /etc/nfs.conf has
+ * a [lockd] port but no grace-time -- "nfsdctl autostart" then failed before
+ * it had configured anything.
+ *
+ * Every test runs in a private network namespace. The settings are per-netns,
+ * and a SERVER_SET in init_net would also overwrite the host's module-wide
+ * nlm_grace_period/nlm_tcpport/nlm_udpport.
+ */
+#define _GNU_SOURCE
+#include <errno.h>
+#include <sched.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/lockd_netlink.h>
+
+#include "../kselftest_harness.h"
+#include "nfsd_netlink.h"
+
+/* fs/lockd/svc.c: nlm_grace_period_max */
+#define GRACE_MAX		240
+
+#define TEST_TCP_PORT		32531
+#define TEST_UDP_PORT		32532
+
+struct lockd_cfg {
+	uint32_t gracetime;
+	uint16_t tcp_port;
+	uint16_t udp_port;
+};
+
+static int lockd_family = -1;
+
+static int lockd_set(const char *attrs, int len)
+{
+	return genl_request_to(lockd_family, LOCKD_CMD_SERVER_SET, attrs, len);
+}
+
+static int lockd_get(struct lockd_cfg *cfg)
+{
+	const struct nlattr *grace, *tcp, *udp;
+	char rbuf[4096];
+	int n;
+
+	n = genl_request_reply_attrs_to(lockd_family, LOCKD_CMD_SERVER_GET,
+					NULL, 0, rbuf, sizeof(rbuf));
+	if (n < 0)
+		return n;
+
+	grace = genl_find_attr(rbuf, n, LOCKD_A_SERVER_GRACETIME);
+	tcp = genl_find_attr(rbuf, n, LOCKD_A_SERVER_TCP_PORT);
+	udp = genl_find_attr(rbuf, n, LOCKD_A_SERVER_UDP_PORT);
+	if (!grace || !tcp || !udp)
+		return -ENOENT;
+
+	cfg->gracetime = nla_u32(grace);
+	cfg->tcp_port = nla_u16(tcp);
+	cfg->udp_port = nla_u16(udp);
+	return 0;
+}
+
+/* ------------------- SERVER_SET request builders ------------------- */
+
+static int put_gracetime(char *buf, int off, uint32_t grace)
+{
+	return put_attr(buf, off, LOCKD_A_SERVER_GRACETIME, &grace,
+			sizeof(grace));
+}
+
+static int put_ports(char *buf, int off, uint16_t tcp, uint16_t udp)
+{
+	off = put_attr(buf, off, LOCKD_A_SERVER_TCP_PORT, &tcp, sizeof(tcp));
+	return put_attr(buf, off, LOCKD_A_SERVER_UDP_PORT, &udp, sizeof(udp));
+}
+
+FIXTURE(lockd_netlink) {
+};
+
+FIXTURE_SETUP(lockd_netlink)
+{
+	if (geteuid() != 0)
+		SKIP(return, "must be run as root");
+	if (unshare(CLONE_NEWNET) < 0)
+		SKIP(return, "unshare(NEWNET): %s", strerror(errno));
+
+	lockd_family = genl_resolve(LOCKD_FAMILY_NAME, sizeof(LOCKD_FAMILY_NAME));
+	if (lockd_family < 0)
+		SKIP(return, "lockd netlink family not registered");
+}
+
+FIXTURE_TEARDOWN(lockd_netlink)
+{
+	/* Nothing to undo: the settings die with the namespace. */
+}
+
+/* A fresh namespace starts out with everything at zero. */
+TEST_F(lockd_netlink, defaults_are_zero)
+{
+	struct lockd_cfg cfg;
+
+	ASSERT_EQ(0, lockd_get(&cfg));
+	EXPECT_EQ(0, cfg.gracetime);
+	EXPECT_EQ(0, cfg.tcp_port);
+	EXPECT_EQ(0, cfg.udp_port);
+}
+
+/*
+ * The regression: ports on their own, no grace time. This is the request
+ * nfsdctl builds from a [lockd] section that only sets the ports.
+ */
+TEST_F(lockd_netlink, set_ports_without_gracetime)
+{
+	struct lockd_cfg cfg;
+	char attrs[64];
+	int off;
+
+	off = put_ports(attrs, 0, TEST_TCP_PORT, TEST_UDP_PORT);
+
+	ASSERT_EQ(0, lockd_set(attrs, off))
+		TH_LOG("SERVER_SET rejected a request with no gracetime");
+
+	ASSERT_EQ(0, lockd_get(&cfg));
+	EXPECT_EQ(TEST_TCP_PORT, cfg.tcp_port);
+	EXPECT_EQ(TEST_UDP_PORT, cfg.udp_port);
+	EXPECT_EQ(0, cfg.gracetime);
+}
+
+/* The mirror image: a grace time with no ports. */
+TEST_F(lockd_netlink, set_gracetime_without_ports)
+{
+	struct lockd_cfg cfg;
+	char attrs[64];
+	int off;
+
+	off = put_gracetime(attrs, 0, 90);
+
+	ASSERT_EQ(0, lockd_set(attrs, off));
+
+	ASSERT_EQ(0, lockd_get(&cfg));
+	EXPECT_EQ(90, cfg.gracetime);
+	EXPECT_EQ(0, cfg.tcp_port);
+	EXPECT_EQ(0, cfg.udp_port);
+}
+
+/* One attribute at a time leaves the others alone. */
+TEST_F(lockd_netlink, attributes_are_set_independently)
+{
+	struct lockd_cfg cfg;
+	char attrs[64];
+	uint16_t tcp = TEST_TCP_PORT;
+	int off;
+
+	off = put_attr(attrs, 0, LOCKD_A_SERVER_TCP_PORT, &tcp, sizeof(tcp));
+	ASSERT_EQ(0, lockd_set(attrs, off));
+
+	off = put_gracetime(attrs, 0, 30);
+	ASSERT_EQ(0, lockd_set(attrs, off));
+
+	ASSERT_EQ(0, lockd_get(&cfg));
+	EXPECT_EQ(30, cfg.gracetime);
+	EXPECT_EQ(TEST_TCP_PORT, cfg.tcp_port)
+		TH_LOG("a gracetime-only SET clobbered the tcp port");
+	EXPECT_EQ(0, cfg.udp_port);
+}
+
+TEST_F(lockd_netlink, set_all_three)
+{
+	struct lockd_cfg cfg;
+	char attrs[64];
+	int off;
+
+	off = put_gracetime(attrs, 0, GRACE_MAX);
+	off = put_ports(attrs, off, TEST_TCP_PORT, TEST_UDP_PORT);
+
+	ASSERT_EQ(0, lockd_set(attrs, off));
+
+	ASSERT_EQ(0, lockd_get(&cfg));
+	EXPECT_EQ(GRACE_MAX, cfg.gracetime);
+	EXPECT_EQ(TEST_TCP_PORT, cfg.tcp_port);
+	EXPECT_EQ(TEST_UDP_PORT, cfg.udp_port);
+}
+
+/* An empty SERVER_SET has nothing to do, but is not an error. */
+TEST_F(lockd_netlink, empty_set_is_a_noop)
+{
+	struct lockd_cfg cfg;
+	char attrs[64];
+	int off;
+
+	off = put_ports(attrs, 0, TEST_TCP_PORT, TEST_UDP_PORT);
+	ASSERT_EQ(0, lockd_set(attrs, off));
+
+	ASSERT_EQ(0, lockd_set(NULL, 0));
+
+	ASSERT_EQ(0, lockd_get(&cfg));
+	EXPECT_EQ(TEST_TCP_PORT, cfg.tcp_port);
+	EXPECT_EQ(TEST_UDP_PORT, cfg.udp_port);
+}
+
+/*
+ * The grace time is still range-checked, and the check runs before anything
+ * is stored: a rejected request must not apply the ports it came with.
+ */
+TEST_F(lockd_netlink, gracetime_above_max_rejected)
+{
+	struct lockd_cfg cfg;
+	char attrs[64];
+	int off;
+
+	off = put_gracetime(attrs, 0, GRACE_MAX + 1);
+	off = put_ports(attrs, off, TEST_TCP_PORT, TEST_UDP_PORT);
+
+	EXPECT_EQ(-EINVAL, lockd_set(attrs, off));
+
+	ASSERT_EQ(0, lockd_get(&cfg));
+	EXPECT_EQ(0, cfg.gracetime);
+	EXPECT_EQ(0, cfg.tcp_port)
+		TH_LOG("a rejected SERVER_SET applied the tcp port anyway");
+	EXPECT_EQ(0, cfg.udp_port);
+}
+
+/* Settings belong to the namespace that made them. */
+TEST_F(lockd_netlink, settings_are_per_netns)
+{
+	struct lockd_cfg cfg;
+	char attrs[64];
+	int off;
+
+	off = put_ports(attrs, 0, TEST_TCP_PORT, TEST_UDP_PORT);
+	ASSERT_EQ(0, lockd_set(attrs, off));
+
+	if (unshare(CLONE_NEWNET) < 0)
+		SKIP(return, "second unshare(NEWNET): %s", strerror(errno));
+
+	ASSERT_EQ(0, lockd_get(&cfg));
+	EXPECT_EQ(0, cfg.tcp_port)
+		TH_LOG("tcp port leaked out of the namespace that set it");
+	EXPECT_EQ(0, cfg.udp_port);
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/nfsd/nfsd_netlink.h b/tools/testing/selftests/nfsd/nfsd_netlink.h
index c66a980bfc01..bb9327109e8f 100644
--- a/tools/testing/selftests/nfsd/nfsd_netlink.h
+++ b/tools/testing/selftests/nfsd/nfsd_netlink.h
@@ -4,7 +4,9 @@
  *
  * Header-only: every helper is static inline, so each test binary gets its
  * own copy and there is nothing extra to link. nfsd_family must be set by
- * calling genl_resolve_nfsd() before any of the request helpers are used.
+ * calling genl_resolve_nfsd() before any of the request helpers are used;
+ * the *_to() variants take a family id instead, for the other families in
+ * the NFS server stack.
  */
 #ifndef __SELFTESTS_NFSD_NETLINK_H__
 #define __SELFTESTS_NFSD_NETLINK_H__
@@ -100,6 +102,45 @@ static inline int put_attr(char *buf, int off, uint16_t type,
 	return off + NLA_ALIGN4(NLA_HDRLEN + len);
 }
 
+/* Payload accessors; the payload is only 4-byte aligned, so no direct load. */
+static inline uint32_t nla_u32(const struct nlattr *na)
+{
+	uint32_t v;
+
+	memcpy(&v, (const char *)na + NLA_HDRLEN, sizeof(v));
+	return v;
+}
+
+static inline uint16_t nla_u16(const struct nlattr *na)
+{
+	uint16_t v;
+
+	memcpy(&v, (const char *)na + NLA_HDRLEN, sizeof(v));
+	return v;
+}
+
+/* Find top-level attribute @type in a genl reply of @len bytes; NULL if absent. */
+static inline const struct nlattr *genl_find_attr(const char *rbuf, int len,
+						  uint16_t type)
+{
+	const struct nlmsghdr *nlh = (const void *)rbuf;
+	const struct nlattr *na;
+	int left;
+
+	if (len < (int)(NLMSG_HDRLEN + GENL_HDRLEN))
+		return NULL;
+	na = (const void *)(rbuf + NLMSG_HDRLEN + GENL_HDRLEN);
+	left = nlh->nlmsg_len - NLMSG_HDRLEN - GENL_HDRLEN;
+
+	while (left >= (int)NLA_HDRLEN) {
+		if ((na->nla_type & NLA_TYPE_MASK) == type)
+			return na;
+		left -= NLA_ALIGN4(na->nla_len);
+		na = (const void *)((const char *)na + NLA_ALIGN4(na->nla_len));
+	}
+	return NULL;
+}
+
 /* Build a genl message header into @buf; return the offset past it. */
 static inline int genl_hdr(char *buf, uint16_t type, uint16_t flags, uint8_t cmd)
 {
@@ -115,15 +156,16 @@ static inline int genl_hdr(char *buf, uint16_t type, uint16_t flags, uint8_t cmd
 	return NLMSG_HDRLEN + GENL_HDRLEN;
 }
 
-/* Send an nfsd command with an ACK; return the ACK errno (<= 0). */
-static inline int genl_request(uint8_t cmd, const char *attrs, int attrs_len)
+/* Send a command to @family with an ACK; return the ACK errno (<= 0). */
+static inline int genl_request_to(uint16_t family, uint8_t cmd,
+				  const char *attrs, int attrs_len)
 {
 	char buf[1 << 20], rbuf[4096];
 	struct nlmsghdr *nlh = (void *)buf;
 	int fd = genl_open();
 	int off, n, ret;
 
-	off = genl_hdr(buf, nfsd_family, NLM_F_REQUEST | NLM_F_ACK, cmd);
+	off = genl_hdr(buf, family, NLM_F_REQUEST | NLM_F_ACK, cmd);
 	if (attrs_len) {
 		memcpy(buf + off, attrs, attrs_len);
 		off += attrs_len;
@@ -147,21 +189,27 @@ static inline int genl_request(uint8_t cmd, const char *attrs, int attrs_len)
 	return ret;
 }
 
+static inline int genl_request(uint8_t cmd, const char *attrs, int attrs_len)
+{
+	return genl_request_to(nfsd_family, cmd, attrs, attrs_len);
+}
+
 /*
- * Send a command with attributes and return the full reply message; -errno
- * on failure. NLM_F_ACK is left off: the kernel reports an error either way,
- * so the first message back is the reply whenever there is one.
+ * Send a command to @family with attributes and return the full reply
+ * message; -errno on failure. NLM_F_ACK is left off: the kernel reports an
+ * error either way, so the first message back is the reply whenever there
+ * is one.
  */
-static inline int genl_request_reply_attrs(uint8_t cmd, const char *attrs,
-					   int attrs_len, char *rbuf,
-					   size_t rlen)
+static inline int genl_request_reply_attrs_to(uint16_t family, uint8_t cmd,
+					      const char *attrs, int attrs_len,
+					      char *rbuf, size_t rlen)
 {
 	char buf[1 << 20];
 	struct nlmsghdr *nlh = (void *)buf;
 	int fd = genl_open();
 	int off, n, ret;
 
-	off = genl_hdr(buf, nfsd_family, NLM_F_REQUEST, cmd);
+	off = genl_hdr(buf, family, NLM_F_REQUEST, cmd);
 	if (attrs_len) {
 		memcpy(buf + off, attrs, attrs_len);
 		off += attrs_len;
@@ -182,13 +230,21 @@ static inline int genl_request_reply_attrs(uint8_t cmd, const char *attrs,
 	return ret;
 }
 
+static inline int genl_request_reply_attrs(uint8_t cmd, const char *attrs,
+					   int attrs_len, char *rbuf,
+					   size_t rlen)
+{
+	return genl_request_reply_attrs_to(nfsd_family, cmd, attrs, attrs_len,
+					   rbuf, rlen);
+}
+
 static inline int genl_request_reply(uint8_t cmd, char *rbuf, size_t rlen)
 {
 	return genl_request_reply_attrs(cmd, NULL, 0, rbuf, rlen);
 }
 
-/* Resolve the "nfsd" genl family id; -1 if not registered. */
-static inline int genl_resolve_nfsd(void)
+/* Resolve a genl family id by name; -1 if not registered. */
+static inline int genl_resolve(const char *name, size_t namelen)
 {
 	char buf[1024], rbuf[4096];
 	struct nlmsghdr *nlh = (void *)buf;
@@ -198,8 +254,7 @@ static inline int genl_resolve_nfsd(void)
 
 	fd = genl_open();
 	off = genl_hdr(buf, GENL_ID_CTRL, NLM_F_REQUEST, CTRL_CMD_GETFAMILY);
-	off = put_attr(buf, off, CTRL_ATTR_FAMILY_NAME,
-		       NFSD_FAMILY_NAME, sizeof(NFSD_FAMILY_NAME));
+	off = put_attr(buf, off, CTRL_ATTR_FAMILY_NAME, name, namelen);
 	nlh->nlmsg_len = off;
 
 	if (send(fd, buf, off, 0) < 0)
@@ -224,6 +279,11 @@ static inline int genl_resolve_nfsd(void)
 	return id;
 }
 
+static inline int genl_resolve_nfsd(void)
+{
+	return genl_resolve(NFSD_FAMILY_NAME, sizeof(NFSD_FAMILY_NAME));
+}
+
 /* ------------------- listener request builders ------------------- */
 
 /* Fine-grained control for negative tests: any field can be omitted/malformed. */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-23 10:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 10:58 [PATCH 0/2] lockd: allow setting ports without setting gracetime Jeff Layton
2026-09-23 10:58 ` [PATCH 1/2] lockd: allow SERVER_SET without a gracetime attribute Jeff Layton
2026-09-23 10:58 ` [PATCH 2/2] selftests/nfsd: add lockd netlink configuration tests Jeff Layton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®