aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
authorJeff Layton <jlayton@kernel.org>2026-03-25 10:40:28 -0400
committerChuck Lever <chuck.lever@oracle.com>2026-05-28 11:31:26 -0400
commit1ca10c4eb275e90a487106fdc3cc9f59a43754c4 (patch)
treec67e5322f914819448e8758a994e72e7737ac6c9 /net
parentf64c462a041c5b87c1945eb3f3f6e4fc8035c594 (diff)
downloadlinux-next-history-1ca10c4eb275e90a487106fdc3cc9f59a43754c4.tar.gz
sunrpc: add a generic netlink family for cache upcalls
The auth.unix.ip and auth.unix.gid caches live in the sunrpc module, so they cannot use the nfsd generic netlink family. Create a new "sunrpc" generic netlink family with its own "exportd" multicast group to support cache upcall notifications for sunrpc-resident caches. Define a YAML spec (sunrpc_cache.yaml) with a cache-type enum (ip_map, unix_gid), a cache-notify multicast event, and the corresponding uapi header. Implement sunrpc_cache_notify() in cache.c, which checks for listeners on the exportd multicast group, builds and sends a SUNRPC_CMD_CACHE_NOTIFY message with the cache-type attribute. Register/unregister the sunrpc_nl_family in init_sunrpc() and cleanup_sunrpc(). Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/Makefile2
-rw-r--r--net/sunrpc/cache.c44
-rw-r--r--net/sunrpc/netlink.c34
-rw-r--r--net/sunrpc/netlink.h22
-rw-r--r--net/sunrpc/sunrpc_syms.c10
5 files changed, 111 insertions, 1 deletions
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
index f89c10fe7e6ac..96727df3aa854 100644
--- a/net/sunrpc/Makefile
+++ b/net/sunrpc/Makefile
@@ -14,7 +14,7 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
addr.o rpcb_clnt.o timer.o xdr.o \
sunrpc_syms.o cache.o rpc_pipe.o sysfs.o \
svc_xprt.o \
- xprtmultipath.o
+ xprtmultipath.o netlink.o
sunrpc-$(CONFIG_SUNRPC_DEBUG) += debugfs.o
sunrpc-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel_rqst.o
sunrpc-$(CONFIG_PROC_FS) += stats.o
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 1ae5469ffe506..305c6e67f0527 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -33,9 +33,11 @@
#include <linux/sunrpc/cache.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
+#include <net/genetlink.h>
#include <trace/events/sunrpc.h>
#include "netns.h"
+#include "netlink.h"
#include "fail.h"
#define RPCDBG_FACILITY RPCDBG_CACHE
@@ -1960,3 +1962,45 @@ int sunrpc_cache_requests_snapshot(struct cache_detail *cd,
return i;
}
EXPORT_SYMBOL_GPL(sunrpc_cache_requests_snapshot);
+
+/**
+ * sunrpc_cache_notify - send a netlink notification for a cache event
+ * @cd: cache_detail for the cache
+ * @h: cache_head entry (unused, reserved for future use)
+ * @cache_type: cache type identifier (e.g. SUNRPC_CACHE_TYPE_UNIX_GID)
+ *
+ * Sends a SUNRPC_CMD_CACHE_NOTIFY multicast message on the "exportd"
+ * group if any listeners are present. Returns 0 on success or a
+ * negative errno.
+ */
+int sunrpc_cache_notify(struct cache_detail *cd, struct cache_head *h,
+ u32 cache_type)
+{
+ struct genlmsghdr *hdr;
+ struct sk_buff *msg;
+
+ if (!genl_has_listeners(&sunrpc_nl_family, cd->net,
+ SUNRPC_NLGRP_EXPORTD))
+ return -ENOLINK;
+
+ msg = genlmsg_new(nla_total_size(sizeof(u32)), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put(msg, 0, 0, &sunrpc_nl_family, 0,
+ SUNRPC_CMD_CACHE_NOTIFY);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
+
+ if (nla_put_u32(msg, SUNRPC_A_CACHE_NOTIFY_CACHE_TYPE, cache_type)) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
+
+ genlmsg_end(msg, hdr);
+ return genlmsg_multicast_netns(&sunrpc_nl_family, cd->net, msg, 0,
+ SUNRPC_NLGRP_EXPORTD, GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(sunrpc_cache_notify);
diff --git a/net/sunrpc/netlink.c b/net/sunrpc/netlink.c
new file mode 100644
index 0000000000000..952de6de85e3f
--- /dev/null
+++ b/net/sunrpc/netlink.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+/* Do not edit directly, auto-generated from: */
+/* Documentation/netlink/specs/sunrpc_cache.yaml */
+/* YNL-GEN kernel source */
+/* To regenerate run: tools/net/ynl/ynl-regen.sh */
+
+#include <net/netlink.h>
+#include <net/genetlink.h>
+#include <linux/sunrpc/cache.h>
+
+#include "netlink.h"
+
+#include <uapi/linux/sunrpc_netlink.h>
+
+/* Ops table for sunrpc */
+static const struct genl_split_ops sunrpc_nl_ops[] = {
+};
+
+static const struct genl_multicast_group sunrpc_nl_mcgrps[] = {
+ [SUNRPC_NLGRP_NONE] = { "none", },
+ [SUNRPC_NLGRP_EXPORTD] = { "exportd", },
+};
+
+struct genl_family sunrpc_nl_family __ro_after_init = {
+ .name = SUNRPC_FAMILY_NAME,
+ .version = SUNRPC_FAMILY_VERSION,
+ .netnsok = true,
+ .parallel_ops = true,
+ .module = THIS_MODULE,
+ .split_ops = sunrpc_nl_ops,
+ .n_split_ops = ARRAY_SIZE(sunrpc_nl_ops),
+ .mcgrps = sunrpc_nl_mcgrps,
+ .n_mcgrps = ARRAY_SIZE(sunrpc_nl_mcgrps),
+};
diff --git a/net/sunrpc/netlink.h b/net/sunrpc/netlink.h
new file mode 100644
index 0000000000000..74cf5183d745d
--- /dev/null
+++ b/net/sunrpc/netlink.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit directly, auto-generated from: */
+/* Documentation/netlink/specs/sunrpc_cache.yaml */
+/* YNL-GEN kernel header */
+/* To regenerate run: tools/net/ynl/ynl-regen.sh */
+
+#ifndef _LINUX_SUNRPC_GEN_H
+#define _LINUX_SUNRPC_GEN_H
+
+#include <net/netlink.h>
+#include <net/genetlink.h>
+
+#include <uapi/linux/sunrpc_netlink.h>
+
+enum {
+ SUNRPC_NLGRP_NONE,
+ SUNRPC_NLGRP_EXPORTD,
+};
+
+extern struct genl_family sunrpc_nl_family;
+
+#endif /* _LINUX_SUNRPC_GEN_H */
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index bab6cab294052..ab88ce46afb55 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -23,9 +23,12 @@
#include <linux/sunrpc/rpc_pipe_fs.h>
#include <linux/sunrpc/xprtsock.h>
+#include <net/genetlink.h>
+
#include "sunrpc.h"
#include "sysfs.h"
#include "netns.h"
+#include "netlink.h"
unsigned int sunrpc_net_id;
EXPORT_SYMBOL_GPL(sunrpc_net_id);
@@ -108,6 +111,10 @@ init_sunrpc(void)
if (err)
goto out5;
+ err = genl_register_family(&sunrpc_nl_family);
+ if (err)
+ goto out6;
+
sunrpc_debugfs_init();
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
rpc_register_sysctl();
@@ -116,6 +123,8 @@ init_sunrpc(void)
init_socket_xprt(); /* clnt sock transport */
return 0;
+out6:
+ rpc_sysfs_exit();
out5:
unregister_rpc_pipefs();
out4:
@@ -131,6 +140,7 @@ out:
static void __exit
cleanup_sunrpc(void)
{
+ genl_unregister_family(&sunrpc_nl_family);
rpc_sysfs_exit();
rpc_cleanup_clids();
xprt_cleanup_ids();