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

dev: Pass netdevice_tracker to dev_get_by_flags_rcu().

This is a follow-up for commit eb1ac9ff6c4a5 ("ipv6: anycast: Don't
hold RTNL for IPV6_JOIN_ANYCAST.").

We should not add a new device lookup API without netdevice_tracker.

Let's pass netdevice_tracker to dev_get_by_flags_rcu() and rename it
with netdev_ prefix to match other newer APIs.

Note that we always use GFP_ATOMIC for netdev_hold() as it's expected
to be called under RCU.

Suggested-by: Jakub Kicinski <kuba@kernel.org>
Link: https://lore.kernel.org/netdev/20250708184053.102109f6@kernel.org/
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250711051120.2866855-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Kuniyuki Iwashima and committed by
Jakub Kicinski
2a683d00 f25a7eaa

+14 -12
+2 -2
include/linux/netdevice.h
··· 3332 3332 int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb); 3333 3333 int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr, 3334 3334 struct net_device_path_stack *stack); 3335 - struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short flags, 3336 - unsigned short mask); 3337 3335 struct net_device *dev_get_by_name(struct net *net, const char *name); 3338 3336 struct net_device *dev_get_by_name_rcu(struct net *net, const char *name); 3339 3337 struct net_device *__dev_get_by_name(struct net *net, const char *name); ··· 3394 3396 netdevice_tracker *tracker, gfp_t gfp); 3395 3397 struct net_device *netdev_get_by_name(struct net *net, const char *name, 3396 3398 netdevice_tracker *tracker, gfp_t gfp); 3399 + struct net_device *netdev_get_by_flags_rcu(struct net *net, netdevice_tracker *tracker, 3400 + unsigned short flags, unsigned short mask); 3397 3401 struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex); 3398 3402 void netdev_copy_name(struct net_device *dev, char *name); 3399 3403
+6 -5
net/core/dev.c
··· 1267 1267 EXPORT_SYMBOL(dev_getfirstbyhwtype); 1268 1268 1269 1269 /** 1270 - * dev_get_by_flags_rcu - find any device with given flags 1270 + * netdev_get_by_flags_rcu - find any device with given flags 1271 1271 * @net: the applicable net namespace 1272 + * @tracker: tracking object for the acquired reference 1272 1273 * @if_flags: IFF_* values 1273 1274 * @mask: bitmask of bits in if_flags to check 1274 1275 * ··· 1278 1277 * Context: rcu_read_lock() must be held. 1279 1278 * Returns: NULL if a device is not found or a pointer to the device. 1280 1279 */ 1281 - struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags, 1282 - unsigned short mask) 1280 + struct net_device *netdev_get_by_flags_rcu(struct net *net, netdevice_tracker *tracker, 1281 + unsigned short if_flags, unsigned short mask) 1283 1282 { 1284 1283 struct net_device *dev; 1285 1284 1286 1285 for_each_netdev_rcu(net, dev) { 1287 1286 if (((READ_ONCE(dev->flags) ^ if_flags) & mask) == 0) { 1288 - dev_hold(dev); 1287 + netdev_hold(dev, tracker, GFP_ATOMIC); 1289 1288 return dev; 1290 1289 } 1291 1290 } 1292 1291 1293 1292 return NULL; 1294 1293 } 1295 - EXPORT_IPV6_MOD(dev_get_by_flags_rcu); 1294 + EXPORT_IPV6_MOD(netdev_get_by_flags_rcu); 1296 1295 1297 1296 /** 1298 1297 * dev_valid_name - check if name is okay for network device
+6 -5
net/ipv6/anycast.c
··· 69 69 struct ipv6_pinfo *np = inet6_sk(sk); 70 70 struct ipv6_ac_socklist *pac = NULL; 71 71 struct net *net = sock_net(sk); 72 + netdevice_tracker dev_tracker; 72 73 struct net_device *dev = NULL; 73 74 struct inet6_dev *idev; 74 75 int err = 0, ishost; ··· 80 79 return -EINVAL; 81 80 82 81 if (ifindex) 83 - dev = dev_get_by_index(net, ifindex); 82 + dev = netdev_get_by_index(net, ifindex, &dev_tracker, GFP_KERNEL); 84 83 85 84 if (ipv6_chk_addr_and_flags(net, addr, dev, true, 0, IFA_F_TENTATIVE)) { 86 85 err = -EINVAL; ··· 105 104 rt = rt6_lookup(net, addr, NULL, 0, NULL, 0); 106 105 if (rt) { 107 106 dev = dst_dev(&rt->dst); 108 - dev_hold(dev); 107 + netdev_hold(dev, &dev_tracker, GFP_ATOMIC); 109 108 ip6_rt_put(rt); 110 109 } else if (ishost) { 111 110 rcu_read_unlock(); ··· 113 112 goto error; 114 113 } else { 115 114 /* router, no matching interface: just pick one */ 116 - dev = dev_get_by_flags_rcu(net, IFF_UP, 117 - IFF_UP | IFF_LOOPBACK); 115 + dev = netdev_get_by_flags_rcu(net, &dev_tracker, IFF_UP, 116 + IFF_UP | IFF_LOOPBACK); 118 117 } 119 118 rcu_read_unlock(); 120 119 } ··· 160 159 error_idev: 161 160 in6_dev_put(idev); 162 161 error: 163 - dev_put(dev); 162 + netdev_put(dev, &dev_tracker); 164 163 165 164 if (pac) 166 165 sock_kfree_s(sk, pac, sizeof(*pac));