From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D98263ABD96; Wed, 23 Sep 2026 10:59:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790161174; cv=none; b=VlDaX2FxwIWRxRi0imZWkTCbfMb97n03ND6Qyl4UmGMHYgOi9g8oNwcsu+z569oZbU8A4B4+PFe2rLayy4kqWInjzBlYVssLu3trji/P0eAoyaUZR50UnAdkCmb9iIoGKYEDwsg92fkPn9PBpJkR6Q4lmfQQRoU+/xrs5JdKyDk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790161174; c=relaxed/simple; bh=bUuROzvXcDkngHGoRBQICkN0XWJTKHexA+VAlehfV7k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Qppd+kt3B1cPOKlI4yrBNmyjNYbGigo5CTaslEUov2+FdFw91MyFODW2SkYkuIXyt9ioXC4atK2wdqXwsIQcjgJJofytW7aIT5W7KxNznO3bHfEbkgs96f1ag8EkxuNE/53ceDkAwA6CLAeHUu0Giq2Xh4ghhTqcZHbaQ7ozxvw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RsxobbSz; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RsxobbSz" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0D1741F00898; Wed, 23 Sep 2026 10:59:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790161165; bh=eh7rXcTWSEGJmhEfykuN2Z5llFna/N+5pi0haT7Dgts=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=RsxobbSzw+GW4WdfVQQR+ZBCfo8s3lA2sKJGS+acnAqgqp8vxPaUR2fpnWi1NhXO8 M+UYD8uFFqjUIshmVT9Ur7YyCnLdaeuCsgnXys7viu21S5ihM8137qthoQfNjbOSdu ZwP4x/e+Xq/3NWb42tKT89GjZtl63yOqcavBca8NL3faV4D29b4IzhaJ9HxKL9DnUP HSplUacgNegtvShtTxtyR33jTLFLPr9PXC7Tbyyrh+C/Cy2PL0fiVLc8T12n08+QR/ PTa32kf1zVB7kW3JnOOREYOY6vRisZgLFkuw9/OkQVRW0Tz3V9vkTWW9aEmLhPbhJF TavKD6tabe2Zg== From: Jeff Layton Date: Wed, 23 Sep 2026 06:58:57 -0400 Subject: [PATCH 2/2] selftests/nfsd: add lockd netlink configuration tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260923-nfsd-testing-v1-2-a793f54a4dd1@kernel.org> References: <20260923-nfsd-testing-v1-0-a793f54a4dd1@kernel.org> In-Reply-To: <20260923-nfsd-testing-v1-0-a793f54a4dd1@kernel.org> To: Trond Myklebust , Anna Schumaker , Chuck Lever , NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Shuah Khan Cc: Scott Mayhew , linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=15342; i=jlayton@kernel.org; h=from:subject:message-id; bh=bUuROzvXcDkngHGoRBQICkN0XWJTKHexA+VAlehfV7k=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqs7EJyf19CXjFHXbTSX1pNm6GNwBQZ8/bIfznp oiglJpssJ2JAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCarOxCQAKCRAADmhBGVaC FfaKD/4jsBqKQBLjMs7ItlpJ6H9FoWanHJ/jxyYM7cl5Ap52Pmh14ochOm/UMsyOE3p9qAMV3Xh 9ojuXjXxX6kOH3KAkb3ayyl+fhiXXftgDqMYkehVmusVUOw7DaqkzK/RuZmi+bbaW19pyxO8ylh kiUzsjpuSTpsSI6EvWaY0CXYd21PXZpH1QLsKjNoriUHwx5i65VV+2p+Eq1VTBY6jTTSYXQv4g7 usrUgPen+Ff53QSoLwqf9Gn+uZLgXn7SxDMtOEnIlGEg4K52e30K5gqRwTQFxsKBOpZ18ulcFOr QgB+c+YPFCXQHsACH4CGqRarqqw6gAzjAQ/dhodNDnTsp29lLxiKwBBn+MkSPANm0bm7fCMQtOP qDvyTnoVKpqElWC1daA5ySGazQ/KaXmUUKfL8HDydHlQuFoIH6+lfxqt8ouxGMjiZrFgAHyXL+S KksL7EDIYq8XSWM2/TKfLe81/dqQMHYo9ODsK+UAQGunlBsbVl3K9d+hHOUZAKKsrQO0gtGmUUH PdEucUJeISibE0YK28KBXpIZVq7jGc+Uy4vbIVr1driREZzw9ai9hSUFBrZJr08j0C3Cf+JTQ6b sqHZwlPk9Ovctcu+WOYUDH1vpe/MhG/i+uaegmrcDv0Apu3hEaPHDpe0ltqKuwowza8TXZzpafJ ctLtT6UYgP9rniQ== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 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 --- 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 +#include +#include +#include +#include +#include + +#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