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 <[EMAIL PROTECTED]> --- 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 [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html