[NET]: Fix race condition about network device name allocation.

Kenji Kaneshige found this race between device removal and
registration. On unregister it is possible for the old device to
exist, because sysfs file is still open. A new device with 'eth%d'
will select the same name, but sysfs kobject register will fial.

The following changes the shutdown order slightly. It hold a removes
the sysfs entries earlier (on unregister_netdevice), but holds a
kobject reference. Then when todo runs the actual last put free
happens.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Stephen Hemminger and committed by David S. Miller 9093bbb2 d8cf2728

+13 -5
+6 -4
net/core/dev.c
··· 3314 3314 continue; 3315 3315 } 3316 3316 3317 - netdev_unregister_sysfs(dev); 3318 3317 dev->reg_state = NETREG_UNREGISTERED; 3319 3318 3320 3319 netdev_wait_allrefs(dev); ··· 3324 3325 BUG_TRAP(!dev->ip6_ptr); 3325 3326 BUG_TRAP(!dev->dn_ptr); 3326 3327 3327 - /* It must be the very last action, 3328 - * after this 'dev' may point to freed up memory. 3329 - */ 3330 3328 if (dev->destructor) 3331 3329 dev->destructor(dev); 3330 + 3331 + /* Free network device */ 3332 + kobject_put(&dev->dev.kobj); 3332 3333 } 3333 3334 3334 3335 out: ··· 3478 3479 3479 3480 /* Notifier chain MUST detach us from master device. */ 3480 3481 BUG_TRAP(!dev->master); 3482 + 3483 + /* Remove entries from sysfs */ 3484 + netdev_unregister_sysfs(dev); 3481 3485 3482 3486 /* Finish processing unregister after unlock */ 3483 3487 net_set_todo(dev);
+7 -1
net/core/net-sysfs.c
··· 456 456 #endif 457 457 }; 458 458 459 + /* Delete sysfs entries but hold kobject reference until after all 460 + * netdev references are gone. 461 + */ 459 462 void netdev_unregister_sysfs(struct net_device * net) 460 463 { 461 - device_del(&(net->dev)); 464 + struct device *dev = &(net->dev); 465 + 466 + kobject_get(&dev->kobj); 467 + device_del(dev); 462 468 } 463 469 464 470 /* Create sysfs entries for network device. */