[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20061130162322.GA8772@gospo.rdu.redhat.com>
Date: Thu, 30 Nov 2006 11:23:23 -0500
From: Andy Gospodarek <andy@...yhouse.net>
To: netdev@...r.kernel.org
Cc: fubar@...ibm.com
Subject: [PATCH] bonding: change spinlocks and remove timers in favor of workqueues
The main purpose of this patch is to clean-up the bonding code so that
several important operations are not done in the incorrect (softirq)
context. Whenever a kernel is compiled with CONFIG_DEBUG_SPINLOCK_SLEEP
all sorts of backtraces are spewed to the log since might_sleep will
kindly remind us we are doing something in a atomic context when we
probably should not.
In order to resolve this, the spin_[un]lock_bh needed to be converted to
spin_[un]lock and to do that the timers needed to be dropped in favor of
workqueues. Since there isn't the chance that this work will be done in
a softirq context, the bh-locks aren't needed since we should not be
preempted to service the workqueue. Both of those changes are included
in this patch.
I've done a bit of testing switching between modes and changing some of
the important values through sysfs, so I feel that creating and
canceling the work is working fine. This code could use some quick
testing with 802.3ad since I didn't have access to a switch with that
capability, so if someone can verify it I would appreciate it.
Signed-off-by: Andy Gospodarek <andy@...yhouse.net>
---
bond_3ad.c | 9 +-
bond_3ad.h | 2
bond_alb.c | 17 +++-
bond_alb.h | 2
bond_main.c | 215 ++++++++++++++++++++++++++++++++++++++---------------------
bond_sysfs.c | 78 ++++++++++-----------
bonding.h | 21 +++--
7 files changed, 212 insertions(+), 132 deletions(-)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 3fb354d..e65ca19 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2097,8 +2097,10 @@ void bond_3ad_unbind_slave(struct slave
* times out, and it selects an aggregator for the ports that are yet not
* related to any aggregator, and selects the active aggregator for a bond.
*/
-void bond_3ad_state_machine_handler(struct bonding *bond)
+void bond_3ad_state_machine_handler(void *work_data)
{
+ struct net_device *bond_dev = (struct net_device *)work_data;
+ struct bonding *bond = bond_dev->priv;
struct port *port;
struct aggregator *aggregator;
@@ -2149,7 +2151,10 @@ void bond_3ad_state_machine_handler(stru
}
re_arm:
- mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks);
+ bond_work_create(bond_dev,
+ bond_3ad_state_machine_handler,
+ &bond->ad_work,
+ ad_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 6ad5ad6..4fa16a9 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -276,7 +276,7 @@ struct ad_slave_info {
void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast);
int bond_3ad_bind_slave(struct slave *slave);
void bond_3ad_unbind_slave(struct slave *slave);
-void bond_3ad_state_machine_handler(struct bonding *bond);
+void bond_3ad_state_machine_handler(void *work_data);
void bond_3ad_adapter_speed_changed(struct slave *slave);
void bond_3ad_adapter_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 3292316..a163e3d 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1367,8 +1367,10 @@ out:
return 0;
}
-void bond_alb_monitor(struct bonding *bond)
+void bond_alb_monitor(void *work_data)
{
+ struct net_device *bond_dev = (struct net_device *)work_data;
+ struct bonding *bond = bond_dev->priv;
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *slave;
int i;
@@ -1433,7 +1435,7 @@ void bond_alb_monitor(struct bonding *bo
* write lock to protect from other code that also
* sets the promiscuity.
*/
- write_lock_bh(&bond->curr_slave_lock);
+ write_lock(&bond->curr_slave_lock);
if (bond_info->primary_is_promisc &&
(++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) {
@@ -1448,7 +1450,7 @@ void bond_alb_monitor(struct bonding *bo
bond_info->primary_is_promisc = 0;
}
- write_unlock_bh(&bond->curr_slave_lock);
+ write_unlock(&bond->curr_slave_lock);
if (bond_info->rlb_rebalance) {
bond_info->rlb_rebalance = 0;
@@ -1471,7 +1473,10 @@ void bond_alb_monitor(struct bonding *bo
}
re_arm:
- mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks);
+ bond_work_create(bond_dev,
+ bond_alb_monitor,
+ &bond->alb_work,
+ alb_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
@@ -1492,11 +1497,11 @@ int bond_alb_init_slave(struct bonding *
/* caller must hold the bond lock for write since the mac addresses
* are compared and may be swapped.
*/
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
res = alb_handle_addr_collision_on_attach(bond, slave);
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
if (res) {
return res;
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 28f2a2f..7f17492 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -125,7 +125,7 @@ void bond_alb_deinit_slave(struct bondin
void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link);
void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave);
int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
-void bond_alb_monitor(struct bonding *bond);
+void bond_alb_monitor(void *work_data);
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);
#endif /* __BOND_ALB_H__ */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 17a4611..81ca778 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -234,11 +234,11 @@ static int bond_add_vlan(struct bonding
vlan->vlan_id = vlan_id;
vlan->vlan_ip = 0;
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
list_add_tail(&vlan->vlan_list, &bond->vlan_list);
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
dprintk("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name);
@@ -259,7 +259,7 @@ static int bond_del_vlan(struct bonding
dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
list_for_each_entry_safe(vlan, next, &bond->vlan_list, vlan_list) {
if (vlan->vlan_id == vlan_id) {
@@ -294,7 +294,7 @@ static int bond_del_vlan(struct bonding
bond->dev->name);
out:
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
return res;
}
@@ -507,7 +507,7 @@ static void bond_add_vlans_on_slave(stru
{
struct vlan_entry *vlan;
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
if (list_empty(&bond->vlan_list)) {
goto out;
@@ -528,7 +528,7 @@ static void bond_add_vlans_on_slave(stru
}
out:
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
}
static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev)
@@ -536,7 +536,7 @@ static void bond_del_vlans_from_slave(st
struct vlan_entry *vlan;
struct net_device *vlan_dev;
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
if (list_empty(&bond->vlan_list)) {
goto out;
@@ -563,7 +563,7 @@ unreg:
}
out:
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
}
/*------------------------------- Link status -------------------------------*/
@@ -1426,7 +1426,7 @@ int bond_enslave(struct net_device *bond
bond_add_vlans_on_slave(bond, slave_dev);
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
bond_attach_slave(bond, new_slave);
@@ -1568,7 +1568,7 @@ int bond_enslave(struct net_device *bond
bond_set_carrier(bond);
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
res = bond_create_slave_symlinks(bond_dev, slave_dev);
if (res)
@@ -1631,7 +1631,7 @@ int bond_release(struct net_device *bond
return -EINVAL;
}
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
slave = bond_get_slave_by_dev(bond, slave_dev);
if (!slave) {
@@ -1639,7 +1639,7 @@ int bond_release(struct net_device *bond
printk(KERN_INFO DRV_NAME
": %s: %s not enslaved\n",
bond_dev->name, slave_dev->name);
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
return -EINVAL;
}
@@ -1740,7 +1740,7 @@ int bond_release(struct net_device *bond
bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
}
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
/* must do this from outside any spinlocks */
bond_destroy_slave_symlinks(bond_dev, slave_dev);
@@ -1795,7 +1795,7 @@ static int bond_release_all(struct net_d
struct net_device *slave_dev;
struct sockaddr addr;
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
netif_carrier_off(bond_dev);
@@ -1832,7 +1832,7 @@ static int bond_release_all(struct net_d
* all the undo steps that should not be called from
* within a lock.
*/
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
bond_destroy_slave_symlinks(bond_dev, slave_dev);
bond_del_vlans_from_slave(bond, slave_dev);
@@ -1872,7 +1872,7 @@ static int bond_release_all(struct net_d
kfree(slave);
/* re-acquire the lock before getting the next slave */
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
}
/* zero the mac address of the master so it will be
@@ -1894,12 +1894,15 @@ static int bond_release_all(struct net_d
bond_dev->name);
}
+ /* destroy the bonds workqueue */
+ bond_wq_destroy(bond_dev);
+
printk(KERN_INFO DRV_NAME
": %s: released all slaves\n",
bond_dev->name);
out:
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
return 0;
}
@@ -1932,7 +1935,7 @@ static int bond_ioctl_change_active(stru
return -EINVAL;
}
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
old_active = bond->curr_active_slave;
new_active = bond_get_slave_by_dev(bond, slave_dev);
@@ -1941,7 +1944,7 @@ static int bond_ioctl_change_active(stru
* Changing to the current active: do nothing; return success.
*/
if (new_active && (new_active == old_active)) {
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
return 0;
}
@@ -1954,7 +1957,7 @@ static int bond_ioctl_change_active(stru
res = -EINVAL;
}
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
return res;
}
@@ -1966,9 +1969,9 @@ static int bond_info_query(struct net_de
info->bond_mode = bond->params.mode;
info->miimon = bond->params.miimon;
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
info->num_slaves = bond->slave_cnt;
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
return 0;
}
@@ -1983,7 +1986,7 @@ static int bond_slave_info_query(struct
return -ENODEV;
}
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
bond_for_each_slave(bond, slave, i) {
if (i == (int)info->slave_id) {
@@ -1992,7 +1995,7 @@ static int bond_slave_info_query(struct
}
}
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
if (found) {
strcpy(info->slave_name, slave->dev->name);
@@ -2006,11 +2009,56 @@ static int bond_slave_info_query(struct
return 0;
}
+
+/*-------------------------------- Workqueues -------------------------------*/
+
+/* add work to the bonding wq */
+void bond_work_create(struct net_device *bond_dev, void (*fn)(void *),
+ struct work_struct *work, unsigned long delay)
+{
+ struct bonding *bond = bond_dev->priv;
+ INIT_WORK(work, fn, (void *)bond_dev);
+
+ /* here we will kick off any work the bonding driver needs */
+ if (delay) {
+ queue_delayed_work(bond->wq, work, delay);
+ }
+ else {
+ queue_work(bond->wq, work);
+ }
+}
+
+void bond_wq_destroy(struct net_device *bond_dev)
+{
+ struct bonding *bond = bond_dev->priv;
+
+ /* make sure all work is finished */
+ cancel_delayed_work(&bond->mii_work);
+ cancel_delayed_work(&bond->arp_work);
+ cancel_delayed_work(&bond->alb_work);
+ cancel_delayed_work(&bond->ad_work);
+
+ destroy_workqueue(bond->wq);
+}
+
+void bond_work_cancel(struct work_struct *work)
+{
+ struct bonding *bond = ((struct net_device *)work->data)->priv;
+
+ if (work->pending) {
+ write_lock(&bond->lock);
+ cancel_delayed_work(work);
+ write_unlock(&bond->lock);
+ }
+
+}
+
/*-------------------------------- Monitoring -------------------------------*/
/* this function is called regularly to monitor each slave's link. */
-void bond_mii_monitor(struct net_device *bond_dev)
+void bond_mii_monitor(void *work_data)
{
+ struct net_device *bond_dev = (struct net_device *)work_data;
struct bonding *bond = bond_dev->priv;
struct slave *slave, *oldcurrent;
int do_failover = 0;
@@ -2241,7 +2289,10 @@ void bond_mii_monitor(struct net_device
re_arm:
if (bond->params.miimon) {
- mod_timer(&bond->mii_timer, jiffies + delta_in_ticks);
+ bond_work_create(bond_dev,
+ bond_mii_monitor,
+ &bond->mii_work,
+ delta_in_ticks);
}
out:
read_unlock(&bond->lock);
@@ -2542,8 +2593,9 @@ out:
* arp is transmitted to generate traffic. see activebackup_arp_monitor for
* arp monitoring in active backup mode.
*/
-void bond_loadbalance_arp_mon(struct net_device *bond_dev)
+void bond_loadbalance_arp_mon(void *work_data)
{
+ struct net_device *bond_dev = (struct net_device *)work_data;
struct bonding *bond = bond_dev->priv;
struct slave *slave, *oldcurrent;
int do_failover = 0;
@@ -2562,6 +2614,7 @@ void bond_loadbalance_arp_mon(struct net
goto re_arm;
}
+
read_lock(&bond->curr_slave_lock);
oldcurrent = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
@@ -2575,6 +2628,7 @@ void bond_loadbalance_arp_mon(struct net
* so it can wait
*/
bond_for_each_slave(bond, slave, i) {
+
if (slave->link != BOND_LINK_UP) {
if (((jiffies - slave->dev->trans_start) <= delta_in_ticks) &&
((jiffies - slave->dev->last_rx) <= delta_in_ticks)) {
@@ -2652,7 +2706,10 @@ void bond_loadbalance_arp_mon(struct net
re_arm:
if (bond->params.arp_interval) {
- mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
+ bond_work_create(bond_dev,
+ bond_loadbalance_arp_mon,
+ &bond->arp_work,
+ delta_in_ticks);
}
out:
read_unlock(&bond->lock);
@@ -2673,8 +2730,9 @@ out:
* may have received.
* see loadbalance_arp_monitor for arp monitoring in load balancing mode
*/
-void bond_activebackup_arp_mon(struct net_device *bond_dev)
+void bond_activebackup_arp_mon(void *work_data)
{
+ struct net_device *bond_dev = (struct net_device *)work_data;
struct bonding *bond = bond_dev->priv;
struct slave *slave;
int delta_in_ticks;
@@ -2900,7 +2958,10 @@ void bond_activebackup_arp_mon(struct ne
re_arm:
if (bond->params.arp_interval) {
- mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
+ bond_work_create(bond_dev,
+ bond_activebackup_arp_mon,
+ &bond->arp_work,
+ delta_in_ticks);
}
out:
read_unlock(&bond->lock);
@@ -2921,7 +2982,7 @@ static void *bond_info_seq_start(struct
/* make sure the bond won't be taken away */
read_lock(&dev_base_lock);
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
if (*pos == 0) {
return SEQ_START_TOKEN;
@@ -2955,7 +3016,7 @@ static void bond_info_seq_stop(struct se
{
struct bonding *bond = seq->private;
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
read_unlock(&dev_base_lock);
}
@@ -3475,14 +3536,11 @@ static int bond_xmit_hash_policy_l2(stru
static int bond_open(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
- struct timer_list *mii_timer = &bond->mii_timer;
- struct timer_list *arp_timer = &bond->arp_timer;
bond->kill_timers = 0;
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
- struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer);
/* bond_alb_initialize must be called before the timer
* is started.
@@ -3492,43 +3550,42 @@ static int bond_open(struct net_device *
return -1;
}
- init_timer(alb_timer);
- alb_timer->expires = jiffies + 1;
- alb_timer->data = (unsigned long)bond;
- alb_timer->function = (void *)&bond_alb_monitor;
- add_timer(alb_timer);
+ bond_work_create(bond_dev,
+ bond_alb_monitor,
+ &bond->alb_work,
+ 0);
}
if (bond->params.miimon) { /* link check interval, in milliseconds. */
- init_timer(mii_timer);
- mii_timer->expires = jiffies + 1;
- mii_timer->data = (unsigned long)bond_dev;
- mii_timer->function = (void *)&bond_mii_monitor;
- add_timer(mii_timer);
+ bond_work_create(bond_dev,
+ bond_mii_monitor,
+ &bond->mii_work,
+ 0);
}
if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- init_timer(arp_timer);
- arp_timer->expires = jiffies + 1;
- arp_timer->data = (unsigned long)bond_dev;
+
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
- arp_timer->function = (void *)&bond_activebackup_arp_mon;
+ bond_work_create(bond_dev,
+ bond_activebackup_arp_mon,
+ &bond->arp_work,
+ 0);
} else {
- arp_timer->function = (void *)&bond_loadbalance_arp_mon;
+ bond_work_create(bond_dev,
+ bond_loadbalance_arp_mon,
+ &bond->arp_work,
+ 0);
}
if (bond->params.arp_validate)
bond_register_arp(bond);
-
- add_timer(arp_timer);
}
if (bond->params.mode == BOND_MODE_8023AD) {
- struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer);
- init_timer(ad_timer);
- ad_timer->expires = jiffies + 1;
- ad_timer->data = (unsigned long)bond;
- ad_timer->function = (void *)&bond_3ad_state_machine_handler;
- add_timer(ad_timer);
+
+ bond_work_create(bond_dev,
+ bond_3ad_state_machine_handler,
+ &bond->ad_work,
+ 0);
/* register to receive LACPDUs */
bond_register_lacpdu(bond);
@@ -3549,38 +3606,37 @@ static int bond_close(struct net_device
if (bond->params.arp_validate)
bond_unregister_arp(bond);
- write_lock_bh(&bond->lock);
-
+ write_lock(&bond->lock);
/* signal timers not to re-arm */
bond->kill_timers = 1;
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
- /* del_timer_sync must run without holding the bond->lock
- * because a running timer might be trying to hold it too
+ /* Release the lock here since bond_work_cancel will take it
+ * again and releasing it will give scheduled work a change
+ * to run.
*/
if (bond->params.miimon) { /* link check interval, in milliseconds. */
- del_timer_sync(&bond->mii_timer);
+ bond_work_cancel(&bond->mii_work);
}
-
+
if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- del_timer_sync(&bond->arp_timer);
+ bond_work_cancel(&bond->arp_work);
}
switch (bond->params.mode) {
case BOND_MODE_8023AD:
- del_timer_sync(&(BOND_AD_INFO(bond).ad_timer));
+ bond_work_cancel(&bond->ad_work);
break;
case BOND_MODE_TLB:
case BOND_MODE_ALB:
- del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer));
+ bond_work_cancel(&bond->alb_work);
break;
default:
break;
- }
-
+ }
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
@@ -3602,7 +3658,7 @@ static struct net_device_stats *bond_get
memset(stats, 0, sizeof(struct net_device_stats));
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
bond_for_each_slave(bond, slave, i) {
sstats = slave->dev->get_stats(slave->dev);
@@ -3634,7 +3690,7 @@ static struct net_device_stats *bond_get
stats->tx_window_errors += sstats->tx_window_errors;
}
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
return stats;
}
@@ -3673,13 +3729,13 @@ static int bond_do_ioctl(struct net_devi
if (mii->reg_num == 1) {
struct bonding *bond = bond_dev->priv;
mii->val_out = 0;
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
read_lock(&bond->curr_slave_lock);
if (bond->curr_active_slave) {
mii->val_out = BMSR_LSTATUS;
}
read_unlock(&bond->curr_slave_lock);
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
}
return 0;
@@ -3766,7 +3822,7 @@ static void bond_set_multicast_list(stru
struct bonding *bond = bond_dev->priv;
struct dev_mc_list *dmi;
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
/*
* Do promisc before checking multicast_mode
@@ -3808,7 +3864,7 @@ static void bond_set_multicast_list(stru
bond_mc_list_destroy(bond);
bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC);
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
}
/*
@@ -4282,6 +4338,13 @@ static int bond_init(struct net_device *
bond->params = *params; /* copy params struct */
+ /* initialize individual workqueue */
+ bond->wq = create_singlethread_workqueue(bond_dev->name);
+
+ if (!bond->wq) {
+ return -ENOMEM;
+ }
+
/* Initialize pointers */
bond->first_slave = NULL;
bond->curr_active_slave = NULL;
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index ced9ed8..403db7e 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -232,7 +232,7 @@ static ssize_t bonding_show_slaves(struc
int i, res = 0;
struct bonding *bond = to_bond(cd);
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
bond_for_each_slave(bond, slave, i) {
if (res > (PAGE_SIZE - IFNAMSIZ)) {
/* not enough space for another interface name */
@@ -243,7 +243,7 @@ static ssize_t bonding_show_slaves(struc
}
res += sprintf(buf + res, "%s ", slave->dev->name);
}
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
res += sprintf(buf + res, "\n");
res++;
return res;
@@ -284,18 +284,18 @@ static ssize_t bonding_store_slaves(stru
/* Got a slave name in ifname. Is it already in the list? */
found = 0;
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
bond_for_each_slave(bond, slave, i)
if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
printk(KERN_ERR DRV_NAME
": %s: Interface %s is already enslaved!\n",
bond->dev->name, ifname);
ret = -EPERM;
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
goto out;
}
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n",
bond->dev->name, ifname);
dev = dev_get_by_name(ifname);
@@ -594,11 +594,12 @@ static ssize_t bonding_store_arp_interva
bond->dev->name, bond->dev->name);
bond->params.miimon = 0;
/* Kill MII timer, else it brings bond's link down */
- if (bond->arp_timer.function) {
+
+ if (bond->mii_work.pending) {
printk(KERN_INFO DRV_NAME
": %s: Kill MII timer, else it brings bond's link down...\n",
bond->dev->name);
- del_timer_sync(&bond->mii_timer);
+ bond_work_cancel(&bond->mii_work);
}
}
if (!bond->params.arp_targets[0]) {
@@ -613,25 +614,25 @@ static ssize_t bonding_store_arp_interva
* timer will get fired off when the open function
* is called.
*/
- if (bond->arp_timer.function) {
- /* The timer's already set up, so fire it off */
- mod_timer(&bond->arp_timer, jiffies + 1);
+ if (bond->arp_work.pending) {
+ bond_work_cancel(&bond->arp_work);
+ bond_work_create(bond->dev,
+ bond->arp_work.func,
+ &bond->arp_work,
+ (bond->params.arp_interval * HZ) / 1000);
+
} else {
- /* Set up the timer. */
- init_timer(&bond->arp_timer);
- bond->arp_timer.expires = jiffies + 1;
- bond->arp_timer.data =
- (unsigned long) bond->dev;
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
- bond->arp_timer.function =
- (void *)
- &bond_activebackup_arp_mon;
+ bond_work_create(bond->dev,
+ bond_activebackup_arp_mon,
+ &bond->arp_work,
+ 0);
} else {
- bond->arp_timer.function =
- (void *)
- &bond_loadbalance_arp_mon;
+ bond_work_create(bond->dev,
+ bond_loadbalance_arp_mon,
+ &bond->arp_work,
+ 0);
}
- add_timer(&bond->arp_timer);
}
}
@@ -968,11 +969,11 @@ static ssize_t bonding_store_miimon(stru
BOND_ARP_VALIDATE_NONE;
}
/* Kill ARP timer, else it brings bond's link down */
- if (bond->mii_timer.function) {
+ if (bond->arp_work.pending) {
printk(KERN_INFO DRV_NAME
": %s: Kill ARP timer, else it brings bond's link down...\n",
bond->dev->name);
- del_timer_sync(&bond->arp_timer);
+ bond_work_cancel(&bond->arp_work);
}
}
@@ -982,18 +983,17 @@ static ssize_t bonding_store_miimon(stru
* timer will get fired off when the open function
* is called.
*/
- if (bond->mii_timer.function) {
- /* The timer's already set up, so fire it off */
- mod_timer(&bond->mii_timer, jiffies + 1);
+ if (bond->mii_work.pending) {
+ bond_work_cancel(&bond->mii_work);
+ bond_work_create(bond->dev,
+ bond_mii_monitor,
+ &bond->mii_work,
+ (bond->params.miimon * HZ) / 1000);
} else {
- /* Set up the timer. */
- init_timer(&bond->mii_timer);
- bond->mii_timer.expires = jiffies + 1;
- bond->mii_timer.data =
- (unsigned long) bond->dev;
- bond->mii_timer.function =
- (void *) &bond_mii_monitor;
- add_timer(&bond->mii_timer);
+ bond_work_create(bond->dev,
+ bond_mii_monitor,
+ &bond->mii_work,
+ 0);
}
}
}
@@ -1028,7 +1028,7 @@ static ssize_t bonding_store_primary(str
struct slave *slave;
struct bonding *bond = to_bond(cd);
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
printk(KERN_INFO DRV_NAME
": %s: Unable to set primary slave; %s is in mode %d\n",
@@ -1062,7 +1062,7 @@ static ssize_t bonding_store_primary(str
}
}
out:
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
return count;
}
static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
@@ -1134,7 +1134,7 @@ static ssize_t bonding_store_active_slav
struct slave *new_active = NULL;
struct bonding *bond = to_bond(cd);
- write_lock_bh(&bond->lock);
+ write_lock(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
printk(KERN_INFO DRV_NAME
": %s: Unable to change active slave; %s is in mode %d\n",
@@ -1190,7 +1190,7 @@ static ssize_t bonding_store_active_slav
}
}
out:
- write_unlock_bh(&bond->lock);
+ write_unlock(&bond->lock);
return count;
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index dc434fb..11e9a07 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@ #include <linux/kobject.h>
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.1.1"
-#define DRV_RELDATE "September 26, 2006"
+#define DRV_VERSION "3.2.0"
+#define DRV_RELDATE "November 21, 2006"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -182,8 +182,6 @@ struct bonding {
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
rwlock_t lock;
rwlock_t curr_slave_lock;
- struct timer_list mii_timer;
- struct timer_list arp_timer;
s8 kill_timers;
struct net_device_stats stats;
#ifdef CONFIG_PROC_FS
@@ -201,6 +199,11 @@ #endif /* CONFIG_PROC_FS */
struct list_head vlan_list;
struct vlan_group *vlgrp;
struct packet_type arp_mon_pt;
+ struct workqueue_struct *wq;
+ struct work_struct mii_work;
+ struct work_struct arp_work;
+ struct work_struct alb_work;
+ struct work_struct ad_work;
};
/**
@@ -300,9 +303,9 @@ void bond_destroy_slave_symlinks(struct
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev);
-void bond_mii_monitor(struct net_device *bond_dev);
-void bond_loadbalance_arp_mon(struct net_device *bond_dev);
-void bond_activebackup_arp_mon(struct net_device *bond_dev);
+void bond_mii_monitor(void *work_data);
+void bond_loadbalance_arp_mon(void *work_data);
+void bond_activebackup_arp_mon(void *work_data);
void bond_set_mode_ops(struct bonding *bond, int mode);
int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl);
const char *bond_mode_name(int mode);
@@ -310,6 +313,10 @@ void bond_select_active_slave(struct bon
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
void bond_register_arp(struct bonding *);
void bond_unregister_arp(struct bonding *);
+void bond_work_create(struct net_device *bond_dev, void (*fn)(void *), struct work_struct *work, unsigned long delay);
+void bond_work_cancel(struct work_struct *work);
+void bond_work_reschedule(struct bonding *bond, struct work_struct *work);
+void bond_wq_destroy(struct net_device *bond_dev);
#endif /* _LINUX_BONDING_H */
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists