diff options
| author | Stephen Hemminger <shemminger@osdl.org> | 2003-08-19 06:51:39 -0700 |
|---|---|---|
| committer | Stephen Hemminger <shemminger@osdl.org> | 2003-08-19 06:51:39 -0700 |
| commit | 322de39f2a5f723615ea24d6035fbeaffa5465d4 (patch) | |
| tree | d580cf1957e7029cee29c223cab0a815f2f768a3 | |
| parent | ae41b279b70bd2acf43ac682d3124b76e05063e8 (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.h | 2 | ||||
| -rw-r--r-- | net/core/dev.c | 29 | ||||
| -rw-r--r-- | net/core/net-sysfs.c | 15 | ||||
| -rw-r--r-- | net/netsyms.c | 1 |
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); |
