mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-18 01:34:14 +08:00
net: Handle NETREG_UNINITIALIZED devices correctly
Fix two problems: 1. If unregister_netdevice_many() is called with both registered and unregistered devices, rollback_registered_many() bails out when it reaches the first unregistered device. The processing of the prior registered devices is unfinished, and the remaining devices are skipped, and possible registered netdev's are leaked/unregistered. 2. System hangs or panics depending on how the devices are passed, since when netdev_run_todo() runs, some devices were not fully processed. Tested by passing intermingled unregistered and registered vlan devices to unregister_netdevice_many() as follows: 1. dev, fake_dev1, fake_dev2: hangs in run_todo ("unregister_netdevice: waiting for eth1.100 to become free. Usage count = 1") 2. fake_dev1, dev, fake_dev2: failure during de-registration and next registration, followed by a vlan driver Oops during subsequent registration. Confirmed that the patch fixes both cases. Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bbb84619c3
commit
e93737b0f0
@ -4771,21 +4771,23 @@ static void net_set_todo(struct net_device *dev)
|
|||||||
|
|
||||||
static void rollback_registered_many(struct list_head *head)
|
static void rollback_registered_many(struct list_head *head)
|
||||||
{
|
{
|
||||||
struct net_device *dev;
|
struct net_device *dev, *tmp;
|
||||||
|
|
||||||
BUG_ON(dev_boot_phase);
|
BUG_ON(dev_boot_phase);
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
|
||||||
list_for_each_entry(dev, head, unreg_list) {
|
list_for_each_entry_safe(dev, tmp, head, unreg_list) {
|
||||||
/* Some devices call without registering
|
/* Some devices call without registering
|
||||||
* for initialization unwind.
|
* for initialization unwind. Remove those
|
||||||
|
* devices and proceed with the remaining.
|
||||||
*/
|
*/
|
||||||
if (dev->reg_state == NETREG_UNINITIALIZED) {
|
if (dev->reg_state == NETREG_UNINITIALIZED) {
|
||||||
pr_debug("unregister_netdevice: device %s/%p never "
|
pr_debug("unregister_netdevice: device %s/%p never "
|
||||||
"was registered\n", dev->name, dev);
|
"was registered\n", dev->name, dev);
|
||||||
|
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
return;
|
list_del(&dev->unreg_list);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(dev->reg_state != NETREG_REGISTERED);
|
BUG_ON(dev->reg_state != NETREG_REGISTERED);
|
||||||
|
Loading…
Reference in New Issue
Block a user