mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 00:40:03 +00: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
1 changed files with 6 additions and 4 deletions
|
@ -4771,21 +4771,23 @@ static void net_set_todo(struct net_device *dev)
|
|||
|
||||
static void rollback_registered_many(struct list_head *head)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct net_device *dev, *tmp;
|
||||
|
||||
BUG_ON(dev_boot_phase);
|
||||
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
|
||||
* for initialization unwind.
|
||||
* for initialization unwind. Remove those
|
||||
* devices and proceed with the remaining.
|
||||
*/
|
||||
if (dev->reg_state == NETREG_UNINITIALIZED) {
|
||||
pr_debug("unregister_netdevice: device %s/%p never "
|
||||
"was registered\n", dev->name, dev);
|
||||
|
||||
WARN_ON(1);
|
||||
return;
|
||||
list_del(&dev->unreg_list);
|
||||
continue;
|
||||
}
|
||||
|
||||
BUG_ON(dev->reg_state != NETREG_REGISTERED);
|
||||
|
|
Loading…
Reference in a new issue