summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-06-06 22:47:07 -0700
committerChris Wright <chrisw@sous-sol.org>2007-06-11 11:37:14 -0700
commit0a0b0c6034b4cbffad5ea4cac33c683bd6c04777 (patch)
tree6d8ef3daf057055877539aef25965cbc26e3a701
parent9d8be79d913f3e13cc8074f02e999b860ce06862 (diff)
[PATCH] 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> [chrisw: backport to 2.6.20] Signed-off-by: Chris Wright <chrisw@sous-sol.org>
-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 2a587b861620..3c3d383d24c2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3138,7 +3138,6 @@ void netdev_run_todo(void)
continue;
}
- netdev_unregister_sysfs(dev);
dev->reg_state = NETREG_UNREGISTERED;
netdev_wait_allrefs(dev);
@@ -3149,11 +3148,11 @@ void netdev_run_todo(void)
BUG_TRAP(!dev->ip6_ptr);
BUG_TRAP(!dev->dn_ptr);
- /* It must be the very last action,
- * after this 'dev' may point to freed up memory.
- */
if (dev->destructor)
dev->destructor(dev);
+
+ /* Free network device */
+ kobject_put(&dev->class_dev.kobj);
}
out:
@@ -3310,6 +3309,9 @@ int unregister_netdevice(struct net_device *dev)
/* Notifier chain MUST detach us from master device. */
BUG_TRAP(!dev->master);
+ /* Remove entries from sysfs */
+ netdev_unregister_sysfs(dev);
+
/* Finish processing unregister after unlock */
net_set_todo(dev);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index f47f319bb7dc..c60fe3b86bb6 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -440,9 +440,15 @@ static struct class net_class = {
#endif
};
+/* Delete sysfs entries but hold kobject reference until after all
+ * netdev references are gone.
+ */
void netdev_unregister_sysfs(struct net_device * net)
{
- class_device_del(&(net->class_dev));
+ struct class_device *dev = &(net->class_dev);
+
+ kobject_get(&dev->kobj);
+ class_device_del(dev);
}
/* Create sysfs entries for network device. */