There is no destroy_workqueue() in bond device destroying process, therefore
worker thread will remain even if bond device is destroyed. So add
destroy_workqueue(), and also, ensure all works are canceled before
destroy_workqueue() is called.
Signed-off-by: Makito SHIOKAWA <[EMAIL PROTECTED]>
---
drivers/net/bonding/bond_main.c | 72 +++++++++++++++++++-------------------
drivers/net/bonding/bond_sysfs.c | 9 ++++
drivers/net/bonding/bonding.h | 5 ++
3 files changed, 48 insertions(+), 38 deletions(-)
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -190,7 +190,6 @@ struct bond_parm_tbl arp_validate_tbl[]
/*-------------------------- Forward declarations ---------------------------*/
static void bond_send_gratuitous_arp(struct bonding *bond);
-static void bond_deinit(struct net_device *bond_dev);
/*---------------------------- General routines -----------------------------*/
@@ -862,7 +861,7 @@ static void bond_resend_igmp_join_reques
/*
* Totally destroys the mc_list in bond
*/
-static void bond_mc_list_destroy(struct bonding *bond)
+void bond_mc_list_destroy(struct bonding *bond)
{
struct dev_mc_list *dmi;
@@ -1875,7 +1874,7 @@ int bond_release_and_destroy(struct net
/*
* This function releases all slaves.
*/
-static int bond_release_all(struct net_device *bond_dev)
+int bond_release_all(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
struct slave *slave;
@@ -4392,6 +4391,25 @@ static const struct ethtool_ops bond_eth
.get_drvinfo = bond_ethtool_get_drvinfo,
};
+/* Caller must not hold rtnl_lock */
+void bond_work_cancel_all(struct bonding *bond)
+{
+ /* ensure all works are stopped */
+ cancel_delayed_work_sync(&bond->alb_work);
+ cancel_delayed_work_sync(&bond->mii_work);
+ cancel_delayed_work_sync(&bond->ab_arp_work);
+ cancel_delayed_work_sync(&bond->lb_arp_work);
+ cancel_delayed_work_sync(&bond->ad_work);
+}
+
+static void bond_free_netdev(struct net_device *dev)
+{
+ struct bonding *bond = netdev_priv(dev);
+
+ destroy_workqueue(bond->wq);
+ free_netdev(dev);
+}
+
/*
* Does not allocate but creates a /proc entry.
* Allowed to fail.
@@ -4441,7 +4459,7 @@ static int bond_init(struct net_device *
bond_set_mode_ops(bond, bond->params.mode);
- bond_dev->destructor = free_netdev;
+ bond_dev->destructor = bond_free_netdev;
/* Initialize the device options */
bond_dev->tx_queue_len = 0;
@@ -4483,7 +4501,7 @@ static int bond_init(struct net_device *
/* De-initialize device specific data.
* Caller must hold rtnl_lock.
*/
-static void bond_deinit(struct net_device *bond_dev)
+void bond_deinit(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
@@ -4494,29 +4512,6 @@ static void bond_deinit(struct net_devic
#endif
}
-static void bond_work_cancel_all(struct bonding *bond)
-{
- write_lock_bh(&bond->lock);
- bond->kill_timers = 1;
- write_unlock_bh(&bond->lock);
-
- if (bond->params.miimon)
- cancel_delayed_work(&bond->mii_work);
-
- if (bond->params.arp_interval) {
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
- cancel_delayed_work(&bond->ab_arp_work);
- else
- cancel_delayed_work(&bond->lb_arp_work);
- }
-
- if (bond->params.mode == BOND_MODE_ALB)
- cancel_delayed_work(&bond->alb_work);
-
- if (bond->params.mode == BOND_MODE_8023AD)
- cancel_delayed_work(&bond->ad_work);
-}
-
/* Unregister and free all bond devices.
* Caller must hold rtnl_lock.
*/
@@ -4527,11 +4522,14 @@ static void bond_free_all(void)
list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
struct net_device *bond_dev = bond->dev;
+ bond_deinit(bond_dev);
+ rtnl_unlock();
bond_work_cancel_all(bond);
+ rtnl_lock();
bond_mc_list_destroy(bond);
/* Release the bonded slaves */
bond_release_all(bond_dev);
- bond_deinit(bond_dev);
+ bond_destroy_sysfs_entry(bond);
unregister_netdevice(bond_dev);
}
@@ -4921,8 +4919,16 @@ int bond_create(char *name, struct bond_
out_bond:
bond_deinit(bond_dev);
+ if (*newbond)
+ unregister_netdevice(bond_dev);
+ else {
+ rtnl_unlock();
+ bond_work_cancel_all(netdev_priv(bond_dev));
+ rtnl_lock();
+ destroy_workqueue(((struct bonding
*)netdev_priv(bond_dev))->wq);
out_netdev:
- free_netdev(bond_dev);
+ free_netdev(bond_dev);
+ }
out_rtnl:
rtnl_unlock();
return res;
@@ -4932,7 +4938,6 @@ static int __init bonding_init(void)
{
int i;
int res;
- struct bonding *bond, *nxt;
printk(KERN_INFO "%s", version);
@@ -4959,11 +4964,6 @@ static int __init bonding_init(void)
goto out;
err:
- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
- bond_work_cancel_all(bond);
- destroy_workqueue(bond->wq);
- }
-
rtnl_lock();
bond_free_all();
bond_destroy_sysfs();
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -163,7 +163,14 @@ static ssize_t bonding_store_bonds(struc
printk(KERN_INFO DRV_NAME
": %s is being deleted...\n",
bond->dev->name);
- bond_destroy(bond);
+ bond_deinit(bond->dev);
+ rtnl_unlock();
+ bond_work_cancel_all(bond);
+ rtnl_lock();
+ bond_mc_list_destroy(bond);
+ bond_release_all(bond->dev);
+ bond_destroy_sysfs_entry(bond);
+ unregister_netdevice(bond->dev);
rtnl_unlock();
goto out;
}
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -301,7 +301,10 @@ static inline void bond_unset_master_alb
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry
*curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct
net_device *slave_dev);
int bond_create(char *name, struct bond_params *params, struct bonding
**newbond);
-void bond_destroy(struct bonding *bond);
+void bond_deinit(struct net_device *bond_dev);
+void bond_work_cancel_all(struct bonding *bond);
+void bond_mc_list_destroy(struct bonding *bond);
+int bond_release_all(struct net_device *bond_dev);
int bond_release_and_destroy(struct net_device *bond_dev, struct net_device
*slave_dev);
int bond_create_sysfs(void);
void bond_destroy_sysfs(void);
--
Makito SHIOKAWA
MIRACLE LINUX CORPORATION
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html