summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2003-08-19 06:51:39 -0700
committerStephen Hemminger <shemminger@osdl.org>2003-08-19 06:51:39 -0700
commit322de39f2a5f723615ea24d6035fbeaffa5465d4 (patch)
treed580cf1957e7029cee29c223cab0a815f2f768a3
parentae41b279b70bd2acf43ac682d3124b76e05063e8 (diff)
[NET]: free_netdev - free network device on last class_device_usage
This patch adds the free_netdev function and associated changes so that net_device structures are not freed until last reference to the network device class is released.
-rw-r--r--include/linux/netdevice.h2
-rw-r--r--net/core/dev.c29
-rw-r--r--net/core/net-sysfs.c15
-rw-r--r--net/netsyms.c1
4 files changed, 45 insertions, 2 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7b39dbf331d3..54769afbd2fb 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -384,6 +384,7 @@ struct net_device
NETREG_REGISTERED, /* completed register todo */
NETREG_UNREGISTERING, /* called unregister_netdevice */
NETREG_UNREGISTERED, /* completed unregister todo */
+ NETREG_RELEASED, /* called free_netdev */
} reg_state;
/* Net device features */
@@ -516,6 +517,7 @@ extern int dev_close(struct net_device *dev);
extern int dev_queue_xmit(struct sk_buff *skb);
extern int register_netdevice(struct net_device *dev);
extern int unregister_netdevice(struct net_device *dev);
+extern void free_netdev(struct net_device *dev);
extern void synchronize_net(void);
extern int register_netdevice_notifier(struct notifier_block *nb);
extern int unregister_netdevice_notifier(struct notifier_block *nb);
diff --git a/net/core/dev.c b/net/core/dev.c
index 6b184e9a90ea..d2ae7cbe37f5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2643,7 +2643,7 @@ int register_netdevice(struct net_device *dev)
ASSERT_RTNL();
/* When net_device's are persistent, this will be fatal. */
- WARN_ON(dev->reg_state != NETREG_UNINITIALIZED);
+ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
spin_lock_init(&dev->queue_lock);
spin_lock_init(&dev->xmit_lock);
@@ -2788,6 +2788,8 @@ static void netdev_wait_allrefs(struct net_device *dev)
* unregister_netdevice(y2);
* ...
* rtnl_unlock();
+ * free_netdev(y1);
+ * free_netdev(y2);
*
* We are invoked by rtnl_unlock() after it drops the semaphore.
* This allows us to deal with problems:
@@ -2827,7 +2829,7 @@ void netdev_run_todo(void)
break;
case NETREG_UNREGISTERING:
- class_device_unregister(&dev->class_dev);
+ class_device_del(&dev->class_dev);
dev->reg_state = NETREG_UNREGISTERED;
netdev_wait_allrefs(dev);
@@ -2856,6 +2858,29 @@ void netdev_run_todo(void)
up(&net_todo_run_mutex);
}
+/**
+ * free_netdev - free network device
+ * @dev: device
+ *
+ * This function does the last stage of destroying an allocated device
+ * interface. The reference to the device object is released.
+ * If this is the last reference then it will be freed.
+ */
+void free_netdev(struct net_device *dev)
+{
+ /* Compatiablity with error handling in drivers */
+ if (dev->reg_state == NETREG_UNINITIALIZED) {
+ kfree(dev);
+ return;
+ }
+
+ BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
+ dev->reg_state = NETREG_RELEASED;
+
+ /* will free via class release */
+ class_device_put(&dev->class_dev);
+}
+
/* Synchronize with packet receive processing. */
void synchronize_net(void)
{
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 3e3c7c524f2f..3ff9e58a06c8 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -361,8 +361,23 @@ static int netdev_hotplug(struct class_device *cd, char **envp,
}
#endif
+/*
+ * netdev_release -- destroy and free a dead device.
+ * Called when last reference to class_device kobject is gone.
+ */
+static void netdev_release(struct class_device *cd)
+{
+ struct net_device *dev
+ = container_of(cd, struct net_device, class_dev);
+
+ BUG_ON(dev->reg_state != NETREG_RELEASED);
+
+ kfree(dev);
+}
+
static struct class net_class = {
.name = "net",
+ .release = netdev_release,
#ifdef CONFIG_HOTPLUG
.hotplug = netdev_hotplug,
#endif
diff --git a/net/netsyms.c b/net/netsyms.c
index a1b61a2af1c9..660fe34f9e68 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -480,6 +480,7 @@ EXPORT_SYMBOL(call_netdevice_notifiers);
EXPORT_SYMBOL(loopback_dev);
EXPORT_SYMBOL(register_netdevice);
EXPORT_SYMBOL(unregister_netdevice);
+EXPORT_SYMBOL(free_netdev);
EXPORT_SYMBOL(synchronize_net);
EXPORT_SYMBOL(netdev_state_change);
EXPORT_SYMBOL(netdev_boot_setup_check);