Skip to content

Commit 8965c16

Browse files
Stanislav Fomichevkuba-moo
authored andcommitted
net: use netif_disable_lro in ipv6_add_dev
ipv6_add_dev might call dev_disable_lro which unconditionally grabs instance lock, so it will deadlock during NETDEV_REGISTER. Switch to netif_disable_lro. Make sure all callers hold the instance lock as well. Cc: Cosmin Ratiu <[email protected]> Fixes: ad7c7b2 ("net: hold netdev instance lock during sysfs operations") Signed-off-by: Stanislav Fomichev <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 4c975fd commit 8965c16

File tree

3 files changed

+22
-10
lines changed

3 files changed

+22
-10
lines changed

include/net/ip.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -667,14 +667,6 @@ static inline void ip_ipgre_mc_map(__be32 naddr, const unsigned char *broadcast,
667667
memcpy(buf, &naddr, sizeof(naddr));
668668
}
669669

670-
#if IS_MODULE(CONFIG_IPV6)
671-
#define EXPORT_IPV6_MOD(X) EXPORT_SYMBOL(X)
672-
#define EXPORT_IPV6_MOD_GPL(X) EXPORT_SYMBOL_GPL(X)
673-
#else
674-
#define EXPORT_IPV6_MOD(X)
675-
#define EXPORT_IPV6_MOD_GPL(X)
676-
#endif
677-
678670
#if IS_ENABLED(CONFIG_IPV6)
679671
#include <linux/ipv6.h>
680672
#endif
@@ -694,6 +686,14 @@ static __inline__ void inet_reset_saddr(struct sock *sk)
694686

695687
#endif
696688

689+
#if IS_MODULE(CONFIG_IPV6)
690+
#define EXPORT_IPV6_MOD(X) EXPORT_SYMBOL(X)
691+
#define EXPORT_IPV6_MOD_GPL(X) EXPORT_SYMBOL_GPL(X)
692+
#else
693+
#define EXPORT_IPV6_MOD(X)
694+
#define EXPORT_IPV6_MOD_GPL(X)
695+
#endif
696+
697697
static inline unsigned int ipv4_addr_hash(__be32 ip)
698698
{
699699
return (__force unsigned int) ip;

net/core/dev.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,7 @@ void netif_disable_lro(struct net_device *dev)
17711771
netdev_unlock_ops(lower_dev);
17721772
}
17731773
}
1774+
EXPORT_IPV6_MOD(netif_disable_lro);
17741775

17751776
/**
17761777
* dev_disable_gro_hw - disable HW Generic Receive Offload on a device

net/ipv6/addrconf.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
#include <net/netlink.h>
8181
#include <net/pkt_sched.h>
8282
#include <net/l3mdev.h>
83+
#include <net/netdev_lock.h>
8384
#include <linux/if_tunnel.h>
8485
#include <linux/rtnetlink.h>
8586
#include <linux/netconf.h>
@@ -377,6 +378,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
377378
int err = -ENOMEM;
378379

379380
ASSERT_RTNL();
381+
netdev_ops_assert_locked(dev);
380382

381383
if (dev->mtu < IPV6_MIN_MTU && dev != blackhole_netdev)
382384
return ERR_PTR(-EINVAL);
@@ -402,7 +404,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
402404
return ERR_PTR(err);
403405
}
404406
if (ndev->cnf.forwarding)
405-
dev_disable_lro(dev);
407+
netif_disable_lro(dev);
406408
/* We refer to the device */
407409
netdev_hold(dev, &ndev->dev_tracker, GFP_KERNEL);
408410

@@ -3152,10 +3154,12 @@ int addrconf_add_ifaddr(struct net *net, void __user *arg)
31523154

31533155
rtnl_net_lock(net);
31543156
dev = __dev_get_by_index(net, ireq.ifr6_ifindex);
3157+
netdev_lock_ops(dev);
31553158
if (dev)
31563159
err = inet6_addr_add(net, dev, &cfg, 0, 0, NULL);
31573160
else
31583161
err = -ENODEV;
3162+
netdev_unlock_ops(dev);
31593163
rtnl_net_unlock(net);
31603164
return err;
31613165
}
@@ -5026,9 +5030,10 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
50265030
if (!dev) {
50275031
NL_SET_ERR_MSG_MOD(extack, "Unable to find the interface");
50285032
err = -ENODEV;
5029-
goto unlock;
5033+
goto unlock_rtnl;
50305034
}
50315035

5036+
netdev_lock_ops(dev);
50325037
idev = ipv6_find_idev(dev);
50335038
if (IS_ERR(idev)) {
50345039
err = PTR_ERR(idev);
@@ -5065,6 +5070,8 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
50655070

50665071
in6_ifa_put(ifa);
50675072
unlock:
5073+
netdev_unlock_ops(dev);
5074+
unlock_rtnl:
50685075
rtnl_net_unlock(net);
50695076

50705077
return err;
@@ -6516,7 +6523,9 @@ static int addrconf_sysctl_addr_gen_mode(const struct ctl_table *ctl, int write,
65166523

65176524
if (idev->cnf.addr_gen_mode != new_val) {
65186525
WRITE_ONCE(idev->cnf.addr_gen_mode, new_val);
6526+
netdev_lock_ops(idev->dev);
65196527
addrconf_init_auto_addrs(idev->dev);
6528+
netdev_unlock_ops(idev->dev);
65206529
}
65216530
} else if (&net->ipv6.devconf_all->addr_gen_mode == ctl->data) {
65226531
struct net_device *dev;
@@ -6528,7 +6537,9 @@ static int addrconf_sysctl_addr_gen_mode(const struct ctl_table *ctl, int write,
65286537
idev->cnf.addr_gen_mode != new_val) {
65296538
WRITE_ONCE(idev->cnf.addr_gen_mode,
65306539
new_val);
6540+
netdev_lock_ops(idev->dev);
65316541
addrconf_init_auto_addrs(idev->dev);
6542+
netdev_unlock_ops(idev->dev);
65326543
}
65336544
}
65346545
}

0 commit comments

Comments
 (0)