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.
Unified · Split
| @@ -76,6 +76,14 @@ attribute-sets: · 75 unmodified lines | |||
| 76 | type: nest | 76 | type: nest |
| 77 | nested-attributes: unix-gid | 77 | nested-attributes: unix-gid |
| 78 | multi-attr: true | 78 | multi-attr: true |
| 79 | - | ||
| 80 | name: cache-flush | ||
| 81 | attributes: | ||
| 82 | - | ||
| 83 | name: mask | ||
| 84 | type: u32 | ||
| 85 | enum: cache-type | ||
| 86 | enum-as-flags: true | ||
| 79 | 87 | ||
| 80 | operations: | 88 | operations: |
| 81 | list: | 89 | list: |
| @@ -123,6 +131,15 @@ operations: · 41 unmodified lines | |||
| 123 | request: | 131 | request: |
| 124 | attributes: | 132 | attributes: |
| 125 | - requests | 133 | - requests |
| 134 | - | ||
| 135 | name: cache-flush | ||
| 136 | doc: Flush sunrpc caches (ip_map and/or unix_gid) | ||
| 137 | attribute-set: cache-flush | ||
| 138 | flags: [admin-perm] | ||
| 139 | do: | ||
| 140 | request: | ||
| 141 | attributes: | ||
| 142 | - mask | ||
| 126 | 143 | ||
| 127 | mcast-groups: | 144 | mcast-groups: |
| 128 | list: | 145 | list: |
| @@ -59,12 +59,20 @@ enum { · 58 unmodified lines | |||
| 59 | SUNRPC_A_UNIX_GID_REQS_MAX = (__SUNRPC_A_UNIX_GID_REQS_MAX - 1) | 59 | SUNRPC_A_UNIX_GID_REQS_MAX = (__SUNRPC_A_UNIX_GID_REQS_MAX - 1) |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | enum { | ||
| 63 | SUNRPC_A_CACHE_FLUSH_MASK = 1, | ||
| 64 | |||
| 65 | __SUNRPC_A_CACHE_FLUSH_MAX, | ||
| 66 | SUNRPC_A_CACHE_FLUSH_MAX = (__SUNRPC_A_CACHE_FLUSH_MAX - 1) | ||
| 67 | }; | ||
| 68 | |||
| 62 | enum { | 69 | enum { |
| 63 | SUNRPC_CMD_CACHE_NOTIFY = 1, | 70 | SUNRPC_CMD_CACHE_NOTIFY = 1, |
| 64 | SUNRPC_CMD_IP_MAP_GET_REQS, | 71 | SUNRPC_CMD_IP_MAP_GET_REQS, |
| 65 | SUNRPC_CMD_IP_MAP_SET_REQS, | 72 | SUNRPC_CMD_IP_MAP_SET_REQS, |
| 66 | SUNRPC_CMD_UNIX_GID_GET_REQS, | 73 | SUNRPC_CMD_UNIX_GID_GET_REQS, |
| 67 | SUNRPC_CMD_UNIX_GID_SET_REQS, | 74 | SUNRPC_CMD_UNIX_GID_SET_REQS, |
| 75 | SUNRPC_CMD_CACHE_FLUSH, | ||
| 68 | 76 | ||
| 69 | __SUNRPC_CMD_MAX, | 77 | __SUNRPC_CMD_MAX, |
| 70 | SUNRPC_CMD_MAX = (__SUNRPC_CMD_MAX - 1) | 78 | SUNRPC_CMD_MAX = (__SUNRPC_CMD_MAX - 1) |
| @@ -49,6 +49,11 @@ static const struct nla_policy sunrpc_unix_gid_set_reqs_nl_policy[SUNRPC_A_UNIX_ · 48 unmodified lines | |||
| 49 | [SUNRPC_A_UNIX_GID_REQS_REQUESTS] = NLA_POLICY_NESTED(sunrpc_unix_gid_nl_policy), | 49 | [SUNRPC_A_UNIX_GID_REQS_REQUESTS] = NLA_POLICY_NESTED(sunrpc_unix_gid_nl_policy), |
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | /* SUNRPC_CMD_CACHE_FLUSH - do */ | ||
| 53 | static const struct nla_policy sunrpc_cache_flush_nl_policy[SUNRPC_A_CACHE_FLUSH_MASK + 1] = { | ||
| 54 | [SUNRPC_A_CACHE_FLUSH_MASK] = NLA_POLICY_MASK(NLA_U32, 0x3), | ||
| 55 | }; | ||
| 56 | |||
| 52 | /* Ops table for sunrpc */ | 57 | /* Ops table for sunrpc */ |
| 53 | static const struct genl_split_ops sunrpc_nl_ops[] = { | 58 | static const struct genl_split_ops sunrpc_nl_ops[] = { |
| 54 | { | 59 | { |
| @@ -79,6 +84,13 @@ static const struct genl_split_ops sunrpc_nl_ops[] = { · 24 unmodified lines | |||
| 79 | .maxattr = SUNRPC_A_UNIX_GID_REQS_REQUESTS, | 84 | .maxattr = SUNRPC_A_UNIX_GID_REQS_REQUESTS, |
| 80 | .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, | 85 | .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, |
| 81 | }, | 86 | }, |
| 87 | { | ||
| 88 | .cmd = SUNRPC_CMD_CACHE_FLUSH, | ||
| 89 | .doit = sunrpc_nl_cache_flush_doit, | ||
| 90 | .policy = sunrpc_cache_flush_nl_policy, | ||
| 91 | .maxattr = SUNRPC_A_CACHE_FLUSH_MASK, | ||
| 92 | .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, | ||
| 93 | }, | ||
| 82 | }; | 94 | }; |
| 83 | 95 | ||
| 84 | static const struct genl_multicast_group sunrpc_nl_mcgrps[] = { | 96 | static const struct genl_multicast_group sunrpc_nl_mcgrps[] = { |
| @@ -23,6 +23,7 @@ int sunrpc_nl_unix_gid_get_reqs_dumpit(struct sk_buff *skb, · 22 unmodified lines | |||
| 23 | struct netlink_callback *cb); | 23 | struct netlink_callback *cb); |
| 24 | int sunrpc_nl_unix_gid_set_reqs_doit(struct sk_buff *skb, | 24 | int sunrpc_nl_unix_gid_set_reqs_doit(struct sk_buff *skb, |
| 25 | struct genl_info *info); | 25 | struct genl_info *info); |
| 26 | int sunrpc_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info); | ||
| 26 | 27 | ||
| 27 | enum { | 28 | enum { |
| 28 | SUNRPC_NLGRP_NONE, | 29 | SUNRPC_NLGRP_NONE, |
| @@ -818,6 +818,38 @@ int sunrpc_nl_unix_gid_set_reqs_doit(struct sk_buff *skb, · 817 unmodified lines | |||
| 818 | return ret; | 818 | return ret; |
| 819 | } | 819 | } |
| 820 | 820 | ||
| 821 | /** | ||
| 822 | * sunrpc_nl_cache_flush_doit - flush sunrpc caches via netlink | ||
| 823 | * @skb: reply buffer | ||
| 824 | * @info: netlink metadata and command arguments | ||
| 825 | * | ||
| 826 | * Flush the ip_map and/or unix_gid caches. If SUNRPC_A_CACHE_FLUSH_MASK | ||
| 827 | * is provided, only flush the caches indicated by the bitmask (bit 1 = | ||
| 828 | * ip_map, bit 2 = unix_gid). If omitted, flush both. | ||
| 829 | * | ||
| 830 | * Return 0 on success or a negative errno. | ||
| 831 | */ | ||
| 832 | int sunrpc_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info) | ||
| 833 | { | ||
| 834 | struct sunrpc_net *sn; | ||
| 835 | u32 mask = ~0U; | ||
| 836 | |||
| 837 | sn = net_generic(genl_info_net(info), sunrpc_net_id); | ||
| 838 | |||
| 839 | if (info->attrs[SUNRPC_A_CACHE_FLUSH_MASK]) | ||
| 840 | mask = nla_get_u32(info->attrs[SUNRPC_A_CACHE_FLUSH_MASK]); | ||
| 841 | |||
| 842 | if ((mask & SUNRPC_CACHE_TYPE_IP_MAP) && | ||
| 843 | sn->ip_map_cache) | ||
| 844 | cache_purge(sn->ip_map_cache); | ||
| 845 | |||
| 846 | if ((mask & SUNRPC_CACHE_TYPE_UNIX_GID) && | ||
| 847 | sn->unix_gid_cache) | ||
| 848 | cache_purge(sn->unix_gid_cache); | ||
| 849 | |||
| 850 | return 0; | ||
| 851 | } | ||
| 852 | |||
| 821 | static const struct cache_detail unix_gid_cache_template = { | 853 | static const struct cache_detail unix_gid_cache_template = { |
| 822 | .owner = THIS_MODULE, | 854 | .owner = THIS_MODULE, |
| 823 | .hash_size = GID_HASHMAX, | 855 | .hash_size = GID_HASHMAX, |