From: Masahiro Matsuya <mmatsuya@redhat.com> Date: Tue, 14 Apr 2009 13:51:49 +0900 Subject: [net] bonding: clean up resources upon removing a bond Message-id: 49E41665.2090206@redhat.com O-Subject: [RHEL5.4 PATCH] BZ463244 bonding: clean up the resources upon removing a bond - REPOST Bugzilla: 463244 RH-Acked-by: Jiri Pirko <jpirko@redhat.com> RH-Acked-by: Neil Horman <nhorman@redhat.com> BZ#463244 https://bugzilla.redhat.com/show_bug.cgi?id=463244 [PATCH] Removing bond interfaces causes workqueue thread leak Description: The workqueue thread for the bond remained, after a bond was removed. Some customer have already seen this issues. This is a patch to clean up the workqueue thread and multicast lists when a bond is removed. Upstream patch http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=a434e43f3d844192bc23bd7b408bac979c40efe7 Test Status A simple reproducer is provided in the bugzilla. The attachment is a patch which was backported for -138. I tested this patch with the reproducer and the fix was confirmed. Thanks, Masahiro Matsuya diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 8fa2ebb..4426166 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1865,6 +1865,20 @@ void bond_destroy(struct bonding *bond) unregister_netdevice(bond->dev); } +static void bond_destructor(struct net_device *bond_dev) +{ + struct bonding *bond = netdev_priv(bond_dev); + + if (bond->wq) + destroy_workqueue(bond->wq); + + netif_tx_lock_bh(bond_dev); + bond_mc_list_destroy(bond); + netif_tx_unlock_bh(bond_dev); + + free_netdev(bond_dev); +} + /* * First release a slave and than destroy the bond if no more slaves iare left. * Must be under rtnl_lock when this function is called. @@ -4449,7 +4463,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) bond_set_mode_ops(bond, bond->params.mode); - bond_dev->destructor = free_netdev; + bond_dev->destructor = bond_destructor; /* Initialize the device options */ bond_dev->tx_queue_len = 0; @@ -4488,20 +4502,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) return 0; } -/* De-initialize device specific data. - * Caller must hold rtnl_lock. - */ -static void bond_deinit(struct net_device *bond_dev) -{ - struct bonding *bond = bond_dev->priv; - - list_del(&bond->bond_list); - -#ifdef CONFIG_PROC_FS - bond_remove_proc_entry(bond); -#endif -} - static void bond_work_cancel_all(struct bonding *bond) { write_lock_bh(&bond->lock); @@ -4523,6 +4523,22 @@ static void bond_work_cancel_all(struct bonding *bond) cancel_delayed_work(&bond->ad_work); } +/* De-initialize device specific data. + * Caller must hold rtnl_lock. + */ +static void bond_deinit(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + + list_del(&bond->bond_list); + + bond_work_cancel_all(bond); + +#ifdef CONFIG_PROC_FS + bond_remove_proc_entry(bond); +#endif +} + /* Unregister and free all bond devices. * Caller must hold rtnl_lock. */ @@ -4534,9 +4550,6 @@ static void bond_free_all(void) struct net_device *bond_dev = bond->dev; bond_work_cancel_all(bond); - netif_tx_lock_bh(bond_dev); - bond_mc_list_destroy(bond); - netif_tx_unlock_bh(bond_dev); /* Release the bonded slaves */ bond_release_all(bond_dev); bond_deinit(bond_dev);