From: Jeff Layton Date: Wed, 25 Mar 2026 14:40:33 +0000 (-0400) Subject: sunrpc: add SUNRPC_CMD_CACHE_FLUSH netlink command X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=565ee23ea2374a0ec42bb70227447baa81fcd196;p=thirdparty%2Flinux.git sunrpc: add SUNRPC_CMD_CACHE_FLUSH netlink command Add a new SUNRPC_CMD_CACHE_FLUSH generic netlink command that allows userspace to flush the sunrpc auth caches (ip_map and unix_gid) without writing to /proc/net/rpc/*/flush. An optional SUNRPC_A_CACHE_FLUSH_MASK u32 attribute selects which caches to flush (bit 1 = ip_map, bit 2 = unix_gid). If the attribute is omitted, all sunrpc caches are flushed. This is used by exportfs to replace its /proc-based cache_flush() with a netlink equivalent, with /proc fallback for older kernels. Signed-off-by: Jeff Layton Signed-off-by: Chuck Lever --- diff --git a/Documentation/netlink/specs/sunrpc_cache.yaml b/Documentation/netlink/specs/sunrpc_cache.yaml index ed0ddb61ebcf2..55dabc914dbc8 100644 --- a/Documentation/netlink/specs/sunrpc_cache.yaml +++ b/Documentation/netlink/specs/sunrpc_cache.yaml @@ -76,6 +76,14 @@ attribute-sets: type: nest nested-attributes: unix-gid multi-attr: true + - + name: cache-flush + attributes: + - + name: mask + type: u32 + enum: cache-type + enum-as-flags: true operations: list: @@ -123,6 +131,15 @@ operations: request: attributes: - requests + - + name: cache-flush + doc: Flush sunrpc caches (ip_map and/or unix_gid) + attribute-set: cache-flush + flags: [admin-perm] + do: + request: + attributes: + - mask mcast-groups: list: diff --git a/include/uapi/linux/sunrpc_netlink.h b/include/uapi/linux/sunrpc_netlink.h index d71c623e92aba..34677f0ec2f95 100644 --- a/include/uapi/linux/sunrpc_netlink.h +++ b/include/uapi/linux/sunrpc_netlink.h @@ -59,12 +59,20 @@ enum { SUNRPC_A_UNIX_GID_REQS_MAX = (__SUNRPC_A_UNIX_GID_REQS_MAX - 1) }; +enum { + SUNRPC_A_CACHE_FLUSH_MASK = 1, + + __SUNRPC_A_CACHE_FLUSH_MAX, + SUNRPC_A_CACHE_FLUSH_MAX = (__SUNRPC_A_CACHE_FLUSH_MAX - 1) +}; + enum { SUNRPC_CMD_CACHE_NOTIFY = 1, SUNRPC_CMD_IP_MAP_GET_REQS, SUNRPC_CMD_IP_MAP_SET_REQS, SUNRPC_CMD_UNIX_GID_GET_REQS, SUNRPC_CMD_UNIX_GID_SET_REQS, + SUNRPC_CMD_CACHE_FLUSH, __SUNRPC_CMD_MAX, SUNRPC_CMD_MAX = (__SUNRPC_CMD_MAX - 1) diff --git a/net/sunrpc/netlink.c b/net/sunrpc/netlink.c index 3ac6b0cac5fec..5ccf0967809c4 100644 --- a/net/sunrpc/netlink.c +++ b/net/sunrpc/netlink.c @@ -49,6 +49,11 @@ static const struct nla_policy sunrpc_unix_gid_set_reqs_nl_policy[SUNRPC_A_UNIX_ [SUNRPC_A_UNIX_GID_REQS_REQUESTS] = NLA_POLICY_NESTED(sunrpc_unix_gid_nl_policy), }; +/* SUNRPC_CMD_CACHE_FLUSH - do */ +static const struct nla_policy sunrpc_cache_flush_nl_policy[SUNRPC_A_CACHE_FLUSH_MASK + 1] = { + [SUNRPC_A_CACHE_FLUSH_MASK] = NLA_POLICY_MASK(NLA_U32, 0x3), +}; + /* Ops table for sunrpc */ static const struct genl_split_ops sunrpc_nl_ops[] = { { @@ -79,6 +84,13 @@ static const struct genl_split_ops sunrpc_nl_ops[] = { .maxattr = SUNRPC_A_UNIX_GID_REQS_REQUESTS, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, + { + .cmd = SUNRPC_CMD_CACHE_FLUSH, + .doit = sunrpc_nl_cache_flush_doit, + .policy = sunrpc_cache_flush_nl_policy, + .maxattr = SUNRPC_A_CACHE_FLUSH_MASK, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, }; static const struct genl_multicast_group sunrpc_nl_mcgrps[] = { diff --git a/net/sunrpc/netlink.h b/net/sunrpc/netlink.h index 2aec57d27a586..2c1012303d48b 100644 --- a/net/sunrpc/netlink.h +++ b/net/sunrpc/netlink.h @@ -23,6 +23,7 @@ int sunrpc_nl_unix_gid_get_reqs_dumpit(struct sk_buff *skb, struct netlink_callback *cb); int sunrpc_nl_unix_gid_set_reqs_doit(struct sk_buff *skb, struct genl_info *info); +int sunrpc_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info); enum { SUNRPC_NLGRP_NONE, diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 7703523d42461..64a2658faddbe 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -818,6 +818,38 @@ int sunrpc_nl_unix_gid_set_reqs_doit(struct sk_buff *skb, return ret; } +/** + * sunrpc_nl_cache_flush_doit - flush sunrpc caches via netlink + * @skb: reply buffer + * @info: netlink metadata and command arguments + * + * Flush the ip_map and/or unix_gid caches. If SUNRPC_A_CACHE_FLUSH_MASK + * is provided, only flush the caches indicated by the bitmask (bit 1 = + * ip_map, bit 2 = unix_gid). If omitted, flush both. + * + * Return 0 on success or a negative errno. + */ +int sunrpc_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct sunrpc_net *sn; + u32 mask = ~0U; + + sn = net_generic(genl_info_net(info), sunrpc_net_id); + + if (info->attrs[SUNRPC_A_CACHE_FLUSH_MASK]) + mask = nla_get_u32(info->attrs[SUNRPC_A_CACHE_FLUSH_MASK]); + + if ((mask & SUNRPC_CACHE_TYPE_IP_MAP) && + sn->ip_map_cache) + cache_purge(sn->ip_map_cache); + + if ((mask & SUNRPC_CACHE_TYPE_UNIX_GID) && + sn->unix_gid_cache) + cache_purge(sn->unix_gid_cache); + + return 0; +} + static const struct cache_detail unix_gid_cache_template = { .owner = THIS_MODULE, .hash_size = GID_HASHMAX,