Re: [PATCH 07/14] sunrpc: add a generic netlink family for cache upcalls

From: Chuck Lever

Date: Thu Mar 19 2026 - 14:45:48 EST


On 3/16/26 11:14 AM, Jeff Layton wrote:
> 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() which mirrors the nfsd_cache_notify()
> pattern: check for listeners on the exportd multicast group, build
> and send SUNRPC_CMD_CACHE_NOTIFY with the cache-type attribute.
>
> Register/unregister the sunrpc_nl_family in init_sunrpc() and
> cleanup_sunrpc().
>
> Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> ---
> Documentation/netlink/specs/sunrpc_cache.yaml | 40 ++++++++++++++++
> fs/nfsd/netlink.c | 2 +-
> include/uapi/linux/sunrpc_netlink.h | 35 ++++++++++++++
> net/sunrpc/Makefile | 2 +-
> net/sunrpc/netlink.c | 66 +++++++++++++++++++++++++++
> net/sunrpc/netlink.h | 25 ++++++++++
> net/sunrpc/sunrpc_syms.c | 10 ++++
> 7 files changed, 178 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/netlink/specs/sunrpc_cache.yaml b/Documentation/netlink/specs/sunrpc_cache.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..f4aa699598bca9ce0215bbc418d9ddcae25c0110
> --- /dev/null
> +++ b/Documentation/netlink/specs/sunrpc_cache.yaml
> @@ -0,0 +1,40 @@
> +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
> +---
> +name: sunrpc
> +protocol: genetlink
> +uapi-header: linux/sunrpc_netlink.h
> +
> +doc: SUNRPC cache upcall support over generic netlink.
> +
> +definitions:
> + -
> + type: flags
> + name: cache-type
> + entries: [ip_map, unix_gid]
> +
> +attribute-sets:
> + -
> + name: cache-notify
> + attributes:
> + -
> + name: cache-type
> + type: u32
> + enum: cache-type
> +
> +operations:
> + list:
> + -
> + name: cache-notify
> + doc: Notification that there are cache requests that need servicing
> + attribute-set: cache-notify
> + mcgrp: exportd
> + event:
> + attributes:
> + - cache-type
> +
> +mcast-groups:
> + list:
> + -
> + name: none
> + -
> + name: exportd
> diff --git a/fs/nfsd/netlink.c b/fs/nfsd/netlink.c
> index 4e08c1a6b3943cda5b44c2b64bcf3a00173a08db..81c943345d13db849483bf0d6773458115ff0134 100644
> --- a/fs/nfsd/netlink.c
> +++ b/fs/nfsd/netlink.c
> @@ -59,7 +59,7 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
> .cmd = NFSD_CMD_THREADS_SET,
> .doit = nfsd_nl_threads_set_doit,
> .policy = nfsd_threads_set_nl_policy,
> - .maxattr = NFSD_A_SERVER_MAX,
> + .maxattr = NFSD_A_SERVER_FH_KEY,
> .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> },
> {
> diff --git a/include/uapi/linux/sunrpc_netlink.h b/include/uapi/linux/sunrpc_netlink.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..6135d9b3eef155a9192d9710c8c690283ec49073
> --- /dev/null
> +++ b/include/uapi/linux/sunrpc_netlink.h
> @@ -0,0 +1,35 @@
> +/* 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 uapi header */
> +/* To regenerate run: tools/net/ynl/ynl-regen.sh */
> +
> +#ifndef _UAPI_LINUX_SUNRPC_NETLINK_H
> +#define _UAPI_LINUX_SUNRPC_NETLINK_H
> +
> +#define SUNRPC_FAMILY_NAME "sunrpc"
> +#define SUNRPC_FAMILY_VERSION 1
> +
> +enum sunrpc_cache_type {
> + SUNRPC_CACHE_TYPE_IP_MAP = 1,
> + SUNRPC_CACHE_TYPE_UNIX_GID = 2,
> +};
> +
> +enum {
> + SUNRPC_A_CACHE_NOTIFY_CACHE_TYPE = 1,
> +
> + __SUNRPC_A_CACHE_NOTIFY_MAX,
> + SUNRPC_A_CACHE_NOTIFY_MAX = (__SUNRPC_A_CACHE_NOTIFY_MAX - 1)
> +};
> +
> +enum {
> + SUNRPC_CMD_CACHE_NOTIFY = 1,
> +
> + __SUNRPC_CMD_MAX,
> + SUNRPC_CMD_MAX = (__SUNRPC_CMD_MAX - 1)
> +};
> +
> +#define SUNRPC_MCGRP_NONE "none"
> +#define SUNRPC_MCGRP_EXPORTD "exportd"
> +
> +#endif /* _UAPI_LINUX_SUNRPC_NETLINK_H */
> diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
> index f89c10fe7e6acc71d47273200d85425a2891a08a..96727df3aa85435a2de63a8483eab9d75d5b3495 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/netlink.c b/net/sunrpc/netlink.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..e59ee82dfab358fc367045d9f04c394000c812ec
> --- /dev/null
> +++ b/net/sunrpc/netlink.c
> @@ -0,0 +1,66 @@
> +// 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),
> +};
> +
> +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(GENLMSG_DEFAULT_SIZE, 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);

Is sunrpc_cache_notify() hand-written? If it is, can you find another
initial landing place for it (I think it is moved out in a later patch)?


> diff --git a/net/sunrpc/netlink.h b/net/sunrpc/netlink.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..efb05f87b89513fe738964a1b27637a09f9b88a9
> --- /dev/null
> +++ b/net/sunrpc/netlink.h
> @@ -0,0 +1,25 @@
> +/* 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;
> +
> +int sunrpc_cache_notify(struct cache_detail *cd, struct cache_head *h,
> + u32 cache_type);

Ditto...


> +
> +#endif /* _LINUX_SUNRPC_GEN_H */
> diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
> index bab6cab2940524a970422b62b3fa4212c61c4f43..ab88ce46afb556cb0a397fe5c9df3901813ad01e 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 @@ init_sunrpc(void)
> static void __exit
> cleanup_sunrpc(void)
> {
> + genl_unregister_family(&sunrpc_nl_family);
> rpc_sysfs_exit();
> rpc_cleanup_clids();
> xprt_cleanup_ids();
>


--
Chuck Lever