aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-05-19 18:39:25 -0400
committerDavid S. Miller <davem@davemloft.net>2007-05-19 18:39:25 -0400
commit9093bbb2d96d0184f037cea9b4e952a44ebe7c32 (patch)
treeac2db6fbe7ead1f6f8ef200068c0db24576bcab9 /net
parentd8cf27287ac7fb5cbfcc4139917a997c39d841ca (diff)
[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>
Diffstat (limited to 'net')
-rw-r--r--net/core/dev.c10
-rw-r--r--net/core/net-sysfs.c8
2 files changed, 13 insertions, 5 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index f2b61111e26d..5a7f20f78574 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3314,7 +3314,6 @@ void netdev_run_todo(void)
3314 continue; 3314 continue;
3315 } 3315 }
3316 3316
3317 netdev_unregister_sysfs(dev);
3318 dev->reg_state = NETREG_UNREGISTERED; 3317 dev->reg_state = NETREG_UNREGISTERED;
3319 3318
3320 netdev_wait_allrefs(dev); 3319 netdev_wait_allrefs(dev);
@@ -3325,11 +3324,11 @@ void netdev_run_todo(void)
3325 BUG_TRAP(!dev->ip6_ptr); 3324 BUG_TRAP(!dev->ip6_ptr);
3326 BUG_TRAP(!dev->dn_ptr); 3325 BUG_TRAP(!dev->dn_ptr);
3327 3326
3328 /* It must be the very last action,
3329 * after this 'dev' may point to freed up memory.
3330 */
3331 if (dev->destructor) 3327 if (dev->destructor)
3332 dev->destructor(dev); 3328 dev->destructor(dev);
3329
3330 /* Free network device */
3331 kobject_put(&dev->dev.kobj);
3333 } 3332 }
3334 3333
3335out: 3334out:
@@ -3480,6 +3479,9 @@ void unregister_netdevice(struct net_device *dev)
3480 /* Notifier chain MUST detach us from master device. */ 3479 /* Notifier chain MUST detach us from master device. */
3481 BUG_TRAP(!dev->master); 3480 BUG_TRAP(!dev->master);
3482 3481
3482 /* Remove entries from sysfs */
3483 netdev_unregister_sysfs(dev);
3484
3483 /* Finish processing unregister after unlock */ 3485 /* Finish processing unregister after unlock */
3484 net_set_todo(dev); 3486 net_set_todo(dev);
3485 3487
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index b21307b15b82..5c19b0646d7a 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -456,9 +456,15 @@ static struct class net_class = {
456#endif 456#endif
457}; 457};
458 458
459/* Delete sysfs entries but hold kobject reference until after all
460 * netdev references are gone.
461 */
459void netdev_unregister_sysfs(struct net_device * net) 462void 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/* Create sysfs entries for network device. */ 470/* Create sysfs entries for network device. */