Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mpls: Convert mpls_dump_routes() to RCU.

mpls_dump_routes() sets fib_dump_filter.rtnl_held to true and
calls __dev_get_by_index() in mpls_valid_fib_dump_req().

This is the only RTNL dependant in mpls_dump_routes().

Also, synchronize_rcu() in resize_platform_label_table()
guarantees that net->mpls.platform_label is alive under RCU.

Let's convert mpls_dump_routes() to RCU and use dev_get_by_index_rcu().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/20251029173344.2934622-11-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Kuniyuki Iwashima and committed by
Jakub Kicinski
dde1b38e 3a496293

+16 -10
+16 -10
net/mpls/af_mpls.c
··· 2153 2153 2154 2154 if (i == RTA_OIF) { 2155 2155 ifindex = nla_get_u32(tb[i]); 2156 - filter->dev = __dev_get_by_index(net, ifindex); 2156 + filter->dev = dev_get_by_index_rcu(net, ifindex); 2157 2157 if (!filter->dev) 2158 2158 return -ENODEV; 2159 2159 filter->filter_set = 1; ··· 2191 2191 struct net *net = sock_net(skb->sk); 2192 2192 struct mpls_route __rcu **platform_label; 2193 2193 struct fib_dump_filter filter = { 2194 - .rtnl_held = true, 2194 + .rtnl_held = false, 2195 2195 }; 2196 2196 unsigned int flags = NLM_F_MULTI; 2197 2197 size_t platform_labels; 2198 2198 unsigned int index; 2199 + int err; 2199 2200 2200 - ASSERT_RTNL(); 2201 + rcu_read_lock(); 2201 2202 2202 2203 if (cb->strict_check) { 2203 - int err; 2204 - 2205 2204 err = mpls_valid_fib_dump_req(net, nlh, &filter, cb); 2206 2205 if (err < 0) 2207 - return err; 2206 + goto err; 2208 2207 2209 2208 /* for MPLS, there is only 1 table with fixed type and flags. 2210 2209 * If either are set in the filter then return nothing. ··· 2211 2212 if ((filter.table_id && filter.table_id != RT_TABLE_MAIN) || 2212 2213 (filter.rt_type && filter.rt_type != RTN_UNICAST) || 2213 2214 filter.flags) 2214 - return skb->len; 2215 + goto unlock; 2215 2216 } 2216 2217 2217 2218 index = cb->args[0]; 2218 2219 if (index < MPLS_LABEL_FIRST_UNRESERVED) 2219 2220 index = MPLS_LABEL_FIRST_UNRESERVED; 2220 2221 2221 - platform_label = rtnl_dereference(net->mpls.platform_label); 2222 + platform_label = rcu_dereference(net->mpls.platform_label); 2222 2223 platform_labels = net->mpls.platform_labels; 2223 2224 2224 2225 if (filter.filter_set) ··· 2227 2228 for (; index < platform_labels; index++) { 2228 2229 struct mpls_route *rt; 2229 2230 2230 - rt = rtnl_dereference(platform_label[index]); 2231 + rt = rcu_dereference(platform_label[index]); 2231 2232 if (!rt) 2232 2233 continue; 2233 2234 ··· 2242 2243 } 2243 2244 cb->args[0] = index; 2244 2245 2246 + unlock: 2247 + rcu_read_unlock(); 2245 2248 return skb->len; 2249 + 2250 + err: 2251 + rcu_read_unlock(); 2252 + return err; 2246 2253 } 2247 2254 2248 2255 static inline size_t lfib_nlmsg_size(struct mpls_route *rt) ··· 2772 2767 static const struct rtnl_msg_handler mpls_rtnl_msg_handlers[] __initdata_or_module = { 2773 2768 {THIS_MODULE, PF_MPLS, RTM_NEWROUTE, mpls_rtm_newroute, NULL, 0}, 2774 2769 {THIS_MODULE, PF_MPLS, RTM_DELROUTE, mpls_rtm_delroute, NULL, 0}, 2775 - {THIS_MODULE, PF_MPLS, RTM_GETROUTE, mpls_getroute, mpls_dump_routes, 0}, 2770 + {THIS_MODULE, PF_MPLS, RTM_GETROUTE, mpls_getroute, mpls_dump_routes, 2771 + RTNL_FLAG_DUMP_UNLOCKED}, 2776 2772 {THIS_MODULE, PF_MPLS, RTM_GETNETCONF, 2777 2773 mpls_netconf_get_devconf, mpls_netconf_dump_devconf, 2778 2774 RTNL_FLAG_DUMP_UNLOCKED},