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().
Unified · Split
| @@ -0,0 +1,40 @@ | |||
| 1 | # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) | ||
| 2 | --- | ||
| 3 | name: sunrpc | ||
| 4 | protocol: genetlink | ||
| 5 | uapi-header: linux/sunrpc_netlink.h | ||
| 6 | |||
| 7 | doc: SUNRPC cache upcall support over generic netlink. | ||
| 8 | |||
| 9 | definitions: | ||
| 10 | - | ||
| 11 | type: flags | ||
| 12 | name: cache-type | ||
| 13 | entries: [ip_map, unix_gid] | ||
| 14 | |||
| 15 | attribute-sets: | ||
| 16 | - | ||
| 17 | name: cache-notify | ||
| 18 | attributes: | ||
| 19 | - | ||
| 20 | name: cache-type | ||
| 21 | type: u32 | ||
| 22 | enum: cache-type | ||
| 23 | |||
| 24 | operations: | ||
| 25 | list: | ||
| 26 | - | ||
| 27 | name: cache-notify | ||
| 28 | doc: Notification that there are cache requests that need servicing | ||
| 29 | attribute-set: cache-notify | ||
| 30 | mcgrp: exportd | ||
| 31 | event: | ||
| 32 | attributes: | ||
| 33 | - cache-type | ||
| 34 | |||
| 35 | mcast-groups: | ||
| 36 | list: | ||
| 37 | - | ||
| 38 | name: none | ||
| 39 | - | ||
| 40 | name: exportd | ||
| @@ -256,6 +256,8 @@ int sunrpc_cache_requests_snapshot(struct cache_detail *cd, · 255 unmodified lines | |||
| 256 | struct cache_head **items, | 256 | struct cache_head **items, |
| 257 | u64 *seqnos, int max, | 257 | u64 *seqnos, int max, |
| 258 | u64 min_seqno); | 258 | u64 min_seqno); |
| 259 | int sunrpc_cache_notify(struct cache_detail *cd, struct cache_head *h, | ||
| 260 | u32 cache_type); | ||
| 259 | 261 | ||
| 260 | /* Must store cache_detail in seq_file->private if using next three functions */ | 262 | /* Must store cache_detail in seq_file->private if using next three functions */ |
| 261 | extern void *cache_seq_start_rcu(struct seq_file *file, loff_t *pos); | 263 | extern void *cache_seq_start_rcu(struct seq_file *file, loff_t *pos); |
| @@ -0,0 +1,35 @@ | |||
| 1 | /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ | ||
| 2 | /* Do not edit directly, auto-generated from: */ | ||
| 3 | /* Documentation/netlink/specs/sunrpc_cache.yaml */ | ||
| 4 | /* YNL-GEN uapi header */ | ||
| 5 | /* To regenerate run: tools/net/ynl/ynl-regen.sh */ | ||
| 6 | |||
| 7 | #ifndef _UAPI_LINUX_SUNRPC_NETLINK_H | ||
| 8 | #define _UAPI_LINUX_SUNRPC_NETLINK_H | ||
| 9 | |||
| 10 | #define SUNRPC_FAMILY_NAME "sunrpc" | ||
| 11 | #define SUNRPC_FAMILY_VERSION 1 | ||
| 12 | |||
| 13 | enum sunrpc_cache_type { | ||
| 14 | SUNRPC_CACHE_TYPE_IP_MAP = 1, | ||
| 15 | SUNRPC_CACHE_TYPE_UNIX_GID = 2, | ||
| 16 | }; | ||
| 17 | |||
| 18 | enum { | ||
| 19 | SUNRPC_A_CACHE_NOTIFY_CACHE_TYPE = 1, | ||
| 20 | |||
| 21 | __SUNRPC_A_CACHE_NOTIFY_MAX, | ||
| 22 | SUNRPC_A_CACHE_NOTIFY_MAX = (__SUNRPC_A_CACHE_NOTIFY_MAX - 1) | ||
| 23 | }; | ||
| 24 | |||
| 25 | enum { | ||
| 26 | SUNRPC_CMD_CACHE_NOTIFY = 1, | ||
| 27 | |||
| 28 | __SUNRPC_CMD_MAX, | ||
| 29 | SUNRPC_CMD_MAX = (__SUNRPC_CMD_MAX - 1) | ||
| 30 | }; | ||
| 31 | |||
| 32 | #define SUNRPC_MCGRP_NONE "none" | ||
| 33 | #define SUNRPC_MCGRP_EXPORTD "exportd" | ||
| 34 | |||
| 35 | #endif /* _UAPI_LINUX_SUNRPC_NETLINK_H */ | ||
| @@ -14,7 +14,7 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ · 13 unmodified lines | |||
| 14 | addr.o rpcb_clnt.o timer.o xdr.o \ | 14 | addr.o rpcb_clnt.o timer.o xdr.o \ |
| 15 | sunrpc_syms.o cache.o rpc_pipe.o sysfs.o \ | 15 | sunrpc_syms.o cache.o rpc_pipe.o sysfs.o \ |
| 16 | svc_xprt.o \ | 16 | svc_xprt.o \ |
| 17 | xprtmultipath.o | 17 | xprtmultipath.o netlink.o |
| 18 | sunrpc-$(CONFIG_SUNRPC_DEBUG) += debugfs.o | 18 | sunrpc-$(CONFIG_SUNRPC_DEBUG) += debugfs.o |
| 19 | sunrpc-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel_rqst.o | 19 | sunrpc-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel_rqst.o |
| 20 | sunrpc-$(CONFIG_PROC_FS) += stats.o | 20 | sunrpc-$(CONFIG_PROC_FS) += stats.o |
| @@ -33,9 +33,11 @@ · 32 unmodified lines | |||
| 33 | #include <linux/sunrpc/cache.h> | 33 | #include <linux/sunrpc/cache.h> |
| 34 | #include <linux/sunrpc/stats.h> | 34 | #include <linux/sunrpc/stats.h> |
| 35 | #include <linux/sunrpc/rpc_pipe_fs.h> | 35 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 36 | #include <net/genetlink.h> | ||
| 36 | #include <trace/events/sunrpc.h> | 37 | #include <trace/events/sunrpc.h> |
| 37 | 38 | ||
| 38 | #include "netns.h" | 39 | #include "netns.h" |
| 40 | #include "netlink.h" | ||
| 39 | #include "fail.h" | 41 | #include "fail.h" |
| 40 | 42 | ||
| 41 | #define RPCDBG_FACILITY RPCDBG_CACHE | 43 | #define RPCDBG_FACILITY RPCDBG_CACHE |
| @@ -1963,3 +1965,45 @@ int sunrpc_cache_requests_snapshot(struct cache_detail *cd, · 1921 unmodified lines | |||
| 1963 | return i; | 1965 | return i; |
| 1964 | } | 1966 | } |
| 1965 | EXPORT_SYMBOL_GPL(sunrpc_cache_requests_snapshot); | 1967 | EXPORT_SYMBOL_GPL(sunrpc_cache_requests_snapshot); |
| 1968 | |||
| 1969 | /** | ||
| 1970 | * sunrpc_cache_notify - send a netlink notification for a cache event | ||
| 1971 | * @cd: cache_detail for the cache | ||
| 1972 | * @h: cache_head entry (unused, reserved for future use) | ||
| 1973 | * @cache_type: cache type identifier (e.g. SUNRPC_CACHE_TYPE_UNIX_GID) | ||
| 1974 | * | ||
| 1975 | * Sends a SUNRPC_CMD_CACHE_NOTIFY multicast message on the "exportd" | ||
| 1976 | * group if any listeners are present. Returns 0 on success or a | ||
| 1977 | * negative errno. | ||
| 1978 | */ | ||
| 1979 | int sunrpc_cache_notify(struct cache_detail *cd, struct cache_head *h, | ||
| 1980 | u32 cache_type) | ||
| 1981 | { | ||
| 1982 | struct genlmsghdr *hdr; | ||
| 1983 | struct sk_buff *msg; | ||
| 1984 | |||
| 1985 | if (!genl_has_listeners(&sunrpc_nl_family, cd->net, | ||
| 1986 | SUNRPC_NLGRP_EXPORTD)) | ||
| 1987 | return -ENOLINK; | ||
| 1988 | |||
| 1989 | msg = genlmsg_new(nla_total_size(sizeof(u32)), GFP_KERNEL); | ||
| 1990 | if (!msg) | ||
| 1991 | return -ENOMEM; | ||
| 1992 | |||
| 1993 | hdr = genlmsg_put(msg, 0, 0, &sunrpc_nl_family, 0, | ||
| 1994 | SUNRPC_CMD_CACHE_NOTIFY); | ||
| 1995 | if (!hdr) { | ||
| 1996 | nlmsg_free(msg); | ||
| 1997 | return -ENOMEM; | ||
| 1998 | } | ||
| 1999 | |||
| 2000 | if (nla_put_u32(msg, SUNRPC_A_CACHE_NOTIFY_CACHE_TYPE, cache_type)) { | ||
| 2001 | nlmsg_free(msg); | ||
| 2002 | return -ENOMEM; | ||
| 2003 | } | ||
| 2004 | |||
| 2005 | genlmsg_end(msg, hdr); | ||
| 2006 | return genlmsg_multicast_netns(&sunrpc_nl_family, cd->net, msg, 0, | ||
| 2007 | SUNRPC_NLGRP_EXPORTD, GFP_KERNEL); | ||
| 2008 | } | ||
| 2009 | EXPORT_SYMBOL_GPL(sunrpc_cache_notify); | ||
| @@ -0,0 +1,34 @@ | |||
| 1 | // SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) | ||
| 2 | /* Do not edit directly, auto-generated from: */ | ||
| 3 | /* Documentation/netlink/specs/sunrpc_cache.yaml */ | ||
| 4 | /* YNL-GEN kernel source */ | ||
| 5 | /* To regenerate run: tools/net/ynl/ynl-regen.sh */ | ||
| 6 | |||
| 7 | #include <net/netlink.h> | ||
| 8 | #include <net/genetlink.h> | ||
| 9 | #include <linux/sunrpc/cache.h> | ||
| 10 | |||
| 11 | #include "netlink.h" | ||
| 12 | |||
| 13 | #include <uapi/linux/sunrpc_netlink.h> | ||
| 14 | |||
| 15 | /* Ops table for sunrpc */ | ||
| 16 | static const struct genl_split_ops sunrpc_nl_ops[] = { | ||
| 17 | }; | ||
| 18 | |||
| 19 | static const struct genl_multicast_group sunrpc_nl_mcgrps[] = { | ||
| 20 | [SUNRPC_NLGRP_NONE] = { "none", }, | ||
| 21 | [SUNRPC_NLGRP_EXPORTD] = { "exportd", }, | ||
| 22 | }; | ||
| 23 | |||
| 24 | struct genl_family sunrpc_nl_family __ro_after_init = { | ||
| 25 | .name = SUNRPC_FAMILY_NAME, | ||
| 26 | .version = SUNRPC_FAMILY_VERSION, | ||
| 27 | .netnsok = true, | ||
| 28 | .parallel_ops = true, | ||
| 29 | .module = THIS_MODULE, | ||
| 30 | .split_ops = sunrpc_nl_ops, | ||
| 31 | .n_split_ops = ARRAY_SIZE(sunrpc_nl_ops), | ||
| 32 | .mcgrps = sunrpc_nl_mcgrps, | ||
| 33 | .n_mcgrps = ARRAY_SIZE(sunrpc_nl_mcgrps), | ||
| 34 | }; | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ | ||
| 2 | /* Do not edit directly, auto-generated from: */ | ||
| 3 | /* Documentation/netlink/specs/sunrpc_cache.yaml */ | ||
| 4 | /* YNL-GEN kernel header */ | ||
| 5 | /* To regenerate run: tools/net/ynl/ynl-regen.sh */ | ||
| 6 | |||
| 7 | #ifndef _LINUX_SUNRPC_GEN_H | ||
| 8 | #define _LINUX_SUNRPC_GEN_H | ||
| 9 | |||
| 10 | #include <net/netlink.h> | ||
| 11 | #include <net/genetlink.h> | ||
| 12 | |||
| 13 | #include <uapi/linux/sunrpc_netlink.h> | ||
| 14 | |||
| 15 | enum { | ||
| 16 | SUNRPC_NLGRP_NONE, | ||
| 17 | SUNRPC_NLGRP_EXPORTD, | ||
| 18 | }; | ||
| 19 | |||
| 20 | extern struct genl_family sunrpc_nl_family; | ||
| 21 | |||
| 22 | #endif /* _LINUX_SUNRPC_GEN_H */ | ||
| @@ -23,9 +23,12 @@ · 22 unmodified lines | |||
| 23 | #include <linux/sunrpc/rpc_pipe_fs.h> | 23 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 24 | #include <linux/sunrpc/xprtsock.h> | 24 | #include <linux/sunrpc/xprtsock.h> |
| 25 | 25 | ||
| 26 | #include <net/genetlink.h> | ||
| 27 | |||
| 26 | #include "sunrpc.h" | 28 | #include "sunrpc.h" |
| 27 | #include "sysfs.h" | 29 | #include "sysfs.h" |
| 28 | #include "netns.h" | 30 | #include "netns.h" |
| 31 | #include "netlink.h" | ||
| 29 | 32 | ||
| 30 | unsigned int sunrpc_net_id; | 33 | unsigned int sunrpc_net_id; |
| 31 | EXPORT_SYMBOL_GPL(sunrpc_net_id); | 34 | EXPORT_SYMBOL_GPL(sunrpc_net_id); |
| @@ -108,6 +111,10 @@ init_sunrpc(void) · 76 unmodified lines | |||
| 108 | if (err) | 111 | if (err) |
| 109 | goto out5; | 112 | goto out5; |
| 110 | 113 | ||
| 114 | err = genl_register_family(&sunrpc_nl_family); | ||
| 115 | if (err) | ||
| 116 | goto out6; | ||
| 117 | |||
| 111 | sunrpc_debugfs_init(); | 118 | sunrpc_debugfs_init(); |
| 112 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) | 119 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
| 113 | rpc_register_sysctl(); | 120 | rpc_register_sysctl(); |
| @@ -116,6 +123,8 @@ init_sunrpc(void) · 2 unmodified lines | |||
| 116 | init_socket_xprt(); /* clnt sock transport */ | 123 | init_socket_xprt(); /* clnt sock transport */ |
| 117 | return 0; | 124 | return 0; |
| 118 | 125 | ||
| 126 | out6: | ||
| 127 | rpc_sysfs_exit(); | ||
| 119 | out5: | 128 | out5: |
| 120 | unregister_rpc_pipefs(); | 129 | unregister_rpc_pipefs(); |
| 121 | out4: | 130 | out4: |
| @@ -131,6 +140,7 @@ out: · 9 unmodified lines | |||
| 131 | static void __exit | 140 | static void __exit |
| 132 | cleanup_sunrpc(void) | 141 | cleanup_sunrpc(void) |
| 133 | { | 142 | { |
| 143 | genl_unregister_family(&sunrpc_nl_family); | ||
| 134 | rpc_sysfs_exit(); | 144 | rpc_sysfs_exit(); |
| 135 | rpc_cleanup_clids(); | 145 | rpc_cleanup_clids(); |
| 136 | xprt_cleanup_ids(); | 146 | xprt_cleanup_ids(); |