diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-23 18:56:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-23 18:56:54 -0700 |
commit | 5a0e554b62dc77709ceebb6326b292bdd8d2c342 (patch) | |
tree | e3c960a526b13a27b6de33a5bc3be580ac0fa231 /drivers | |
parent | c09b360a2b0779e08bacb88d3fcd8458ebc49658 (diff) | |
parent | 2c800093c7375e358f28eeb132512eb57b6389e3 (diff) |
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (39 commits)
Remove Andrew Morton from list of net driver maintainers.
bonding: Acquire correct locks in alb for promisc change
bonding: Convert more locks to _bh, acquire rtnl, for new locking
bonding: Convert locks to _bh, rework alb locking for new locking
bonding: Convert miimon to new locking
bonding: Convert balance-rr transmit to new locking
Convert bonding timers to workqueues
Update MAINTAINERS to reflect my (jgarzik's) current efforts.
pasemi_mac: fix typo
defxx.c: dfx_bus_init() is __devexit not __devinit
s390 MAINTAINERS
remove header_ops bug in qeth driver
sky2: crash on remove
MIPSnet: Delete all the useless debugging printks.
AR7 ethernet: small post-merge cleanups and fixes
mv643xx_eth: Hook up mv643xx_get_sset_count
mv643xx_eth: Remove obsolete checksum offload comment
mv643xx_eth: Merge drivers/net/mv643xx_eth.h into mv643xx_eth.c
mv643xx_eth: Remove unused register defines
mv643xx_eth: Clean up mv643xx_eth.h
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/Kconfig | 13 | ||||
-rw-r--r-- | drivers/net/bonding/bond_3ad.c | 6 | ||||
-rw-r--r-- | drivers/net/bonding/bond_3ad.h | 2 | ||||
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 110 | ||||
-rw-r--r-- | drivers/net/bonding/bond_alb.h | 2 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 330 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 79 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 14 | ||||
-rw-r--r-- | drivers/net/cpmac.c | 31 | ||||
-rw-r--r-- | drivers/net/defxx.c | 2 | ||||
-rw-r--r-- | drivers/net/mipsnet.c | 44 | ||||
-rw-r--r-- | drivers/net/mv643xx_eth.c | 807 | ||||
-rw-r--r-- | drivers/net/mv643xx_eth.h | 370 | ||||
-rw-r--r-- | drivers/net/pasemi_mac.c | 2 | ||||
-rw-r--r-- | drivers/net/r8169.c | 406 | ||||
-rw-r--r-- | drivers/net/sky2.c | 4 |
16 files changed, 1295 insertions, 927 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2538816817a..86b8641b466 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2371,13 +2371,16 @@ config UGETH_TX_ON_DEMAND depends on UCC_GETH config MV643XX_ETH - tristate "MV-643XX Ethernet support" - depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) + tristate "Marvell Discovery (643XX) and Orion ethernet support" + depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || ARCH_ORION select MII help - This driver supports the gigabit Ethernet on the Marvell MV643XX - chipset which is used in the Momenco Ocelot C and Jaguar ATX and - Pegasos II, amongst other PPC and MIPS boards. + This driver supports the gigabit ethernet MACs in the + Marvell Discovery PPC/MIPS chipset family (MV643XX) and + in the Marvell Orion ARM SoC family. + + Some boards that use the Discovery chipset are the Momenco + Ocelot C and Jaguar ATX and Pegasos II. config QLA3XXX tristate "QLogic QLA3XXX Network Driver Support" diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 084f0292ea6..cb3c6faa788 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2076,8 +2076,10 @@ void bond_3ad_unbind_slave(struct slave *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(struct work_struct *work) { + struct bonding *bond = container_of(work, struct bonding, + ad_work.work); struct port *port; struct aggregator *aggregator; @@ -2128,7 +2130,7 @@ void bond_3ad_state_machine_handler(struct bonding *bond) } re_arm: - mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks); + queue_delayed_work(bond->wq, &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 f1655726494..b5ee45f6d55 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(struct work_struct *); 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 aea2217c56e..25b8dbf6cfd 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -128,12 +128,12 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size) static inline void _lock_tx_hashtbl(struct bonding *bond) { - spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); + spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } static inline void _unlock_tx_hashtbl(struct bonding *bond) { - spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); + spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } /* Caller must hold tx_hashtbl lock */ @@ -305,12 +305,12 @@ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u3 /*********************** rlb specific functions ***************************/ static inline void _lock_rx_hashtbl(struct bonding *bond) { - spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); + spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } static inline void _unlock_rx_hashtbl(struct bonding *bond) { - spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); + spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } /* when an ARP REPLY is received from a client update its info @@ -472,13 +472,13 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) _unlock_rx_hashtbl(bond); - write_lock(&bond->curr_slave_lock); + write_lock_bh(&bond->curr_slave_lock); if (slave != bond->curr_active_slave) { rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); } - write_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); } static void rlb_update_client(struct rlb_client_info *client_info) @@ -959,19 +959,34 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) return 0; } -/* Caller must hold bond lock for write or curr_slave_lock for write*/ +/* + * Swap MAC addresses between two slaves. + * + * Called with RTNL held, and no other locks. + * + */ + static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2) { - struct slave *disabled_slave = NULL; u8 tmp_mac_addr[ETH_ALEN]; - int slaves_state_differ; - - slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN); alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled); alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled); +} + +/* + * Send learning packets after MAC address swap. + * + * Called with RTNL and bond->lock held for read. + */ +static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1, + struct slave *slave2) +{ + int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); + struct slave *disabled_slave = NULL; + /* fasten the change in the switch */ if (SLAVE_IS_OK(slave1)) { alb_send_learning_packets(slave1, slave1->dev->dev_addr); @@ -1044,7 +1059,9 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla } if (found) { + /* locking: needs RTNL and nothing else */ alb_swap_mac_addr(bond, slave, tmp_slave); + alb_fasten_mac_swap(bond, slave, tmp_slave); } } } @@ -1375,8 +1392,10 @@ out: return 0; } -void bond_alb_monitor(struct bonding *bond) +void bond_alb_monitor(struct work_struct *work) { + struct bonding *bond = container_of(work, struct bonding, + alb_work.work); struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *slave; int i; @@ -1436,16 +1455,16 @@ void bond_alb_monitor(struct bonding *bond) /* handle rlb stuff */ if (bond_info->rlb_enabled) { - /* the following code changes the promiscuity of the - * the curr_active_slave. It needs to be locked with a - * write lock to protect from other code that also - * sets the promiscuity. - */ - write_lock_bh(&bond->curr_slave_lock); - if (bond_info->primary_is_promisc && (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { + /* + * dev_set_promiscuity requires rtnl and + * nothing else. + */ + read_unlock(&bond->lock); + rtnl_lock(); + bond_info->rlb_promisc_timeout_counter = 0; /* If the primary was set to promiscuous mode @@ -1454,9 +1473,10 @@ void bond_alb_monitor(struct bonding *bond) */ dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond_info->primary_is_promisc = 0; - } - write_unlock_bh(&bond->curr_slave_lock); + rtnl_unlock(); + read_lock(&bond->lock); + } if (bond_info->rlb_rebalance) { bond_info->rlb_rebalance = 0; @@ -1479,7 +1499,7 @@ void bond_alb_monitor(struct bonding *bond) } re_arm: - mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks); + queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks); out: read_unlock(&bond->lock); } @@ -1500,11 +1520,11 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) /* caller must hold the bond lock for write since the mac addresses * are compared and may be swapped. */ - write_lock_bh(&bond->lock); + read_lock(&bond->lock); res = alb_handle_addr_collision_on_attach(bond, slave); - write_unlock_bh(&bond->lock); + read_unlock(&bond->lock); if (res) { return res; @@ -1569,13 +1589,21 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char * Set the bond->curr_active_slave to @new_slave and handle * mac address swapping and promiscuity changes as needed. * - * Caller must hold bond curr_slave_lock for write (or bond lock for write) + * If new_slave is NULL, caller must hold curr_slave_lock or + * bond->lock for write. + * + * If new_slave is not NULL, caller must hold RTNL, bond->lock for + * read and curr_slave_lock for write. Processing here may sleep, so + * no other locks may be held. */ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave) { struct slave *swap_slave; int i; + if (new_slave) + ASSERT_RTNL(); + if (bond->curr_active_slave == new_slave) { return; } @@ -1608,6 +1636,19 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave } } + /* + * Arrange for swap_slave and new_slave to temporarily be + * ignored so we can mess with their MAC addresses without + * fear of interference from transmit activity. + */ + if (swap_slave) { + tlb_clear_slave(bond, swap_slave, 1); + } + tlb_clear_slave(bond, new_slave, 1); + + write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->lock); + /* curr_active_slave must be set before calling alb_swap_mac_addr */ if (swap_slave) { /* swap mac address */ @@ -1616,11 +1657,23 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave /* set the new_slave to the bond mac address */ alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, bond->alb_info.rlb_enabled); + } + + read_lock(&bond->lock); + + if (swap_slave) { + alb_fasten_mac_swap(bond, swap_slave, new_slave); + } else { /* fasten bond mac on new current slave */ alb_send_learning_packets(new_slave, bond->dev->dev_addr); } + + write_lock_bh(&bond->curr_slave_lock); } +/* + * Called with RTNL + */ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) { struct bonding *bond = bond_dev->priv; @@ -1657,8 +1710,12 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) } } + write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->lock); + if (swap_slave) { alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); + alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave); } else { alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, bond->alb_info.rlb_enabled); @@ -1670,6 +1727,9 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) } } + read_lock(&bond->lock); + write_lock_bh(&bond->curr_slave_lock); + return 0; } diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index fd872642989..50968f8196c 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 bonding *bond, struct slave *slave); 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(struct work_struct *); 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 6f85cc31f8a..6909becb10f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1590,15 +1590,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) case BOND_MODE_TLB: case BOND_MODE_ALB: new_slave->state = BOND_STATE_ACTIVE; - if ((!bond->curr_active_slave) && - (new_slave->link != BOND_LINK_DOWN)) { - /* first slave or no active slave yet, and this link - * is OK, so make this interface the active one - */ - bond_change_active_slave(bond, new_slave); - } else { - bond_set_slave_inactive_flags(new_slave); - } + bond_set_slave_inactive_flags(new_slave); break; default: dprintk("This slave is always active in trunk mode\n"); @@ -1754,9 +1746,23 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_alb_deinit_slave(bond, slave); } - if (oldcurrent == slave) + if (oldcurrent == slave) { + /* + * Note that we hold RTNL over this sequence, so there + * is no concern that another slave add/remove event + * will interfere. + */ + write_unlock_bh(&bond->lock); + read_lock(&bond->lock); + write_lock_bh(&bond->curr_slave_lock); + bond_select_active_slave(bond); + write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->lock); + write_lock_bh(&bond->lock); + } + if (bond->slave_cnt == 0) { bond_set_carrier(bond); @@ -1840,9 +1846,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) */ void bond_destroy(struct bonding *bond) { + unregister_netdevice(bond->dev); bond_deinit(bond->dev); bond_destroy_sysfs_entry(bond); - unregister_netdevice(bond->dev); } /* @@ -2012,16 +2018,19 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi return -EINVAL; } - write_lock_bh(&bond->lock); + read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); old_active = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + new_active = bond_get_slave_by_dev(bond, slave_dev); /* * Changing to the current active: do nothing; return success. */ if (new_active && (new_active == old_active)) { - write_unlock_bh(&bond->lock); + read_unlock(&bond->lock); return 0; } @@ -2029,12 +2038,14 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi (old_active) && (new_active->link == BOND_LINK_UP) && IS_UP(new_active->dev)) { + write_lock_bh(&bond->curr_slave_lock); bond_change_active_slave(bond, new_active); + write_unlock_bh(&bond->curr_slave_lock); } else { res = -EINVAL; } - write_unlock_bh(&bond->lock); + read_unlock(&bond->lock); return res; } @@ -2046,9 +2057,9 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) 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; } @@ -2063,7 +2074,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in return -ENODEV; } - read_lock_bh(&bond->lock); + read_lock(&bond->lock); bond_for_each_slave(bond, slave, i) { if (i == (int)info->slave_id) { @@ -2072,7 +2083,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in } } - read_unlock_bh(&bond->lock); + read_unlock(&bond->lock); if (found) { strcpy(info->slave_name, slave->dev->name); @@ -2088,26 +2099,25 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in /*-------------------------------- Monitoring -------------------------------*/ -/* this function is called regularly to monitor each slave's link. */ -void bond_mii_monitor(struct net_device *bond_dev) +/* + * if !have_locks, return nonzero if a failover is necessary. if + * have_locks, do whatever failover activities are needed. + * + * This is to separate the inspection and failover steps for locking + * purposes; failover requires rtnl, but acquiring it for every + * inspection is undesirable, so a wrapper first does inspection, and + * the acquires the necessary locks and calls again to perform + * failover if needed. Since all locks are dropped, a complete + * restart is needed between calls. + */ +static int __bond_mii_monitor(struct bonding *bond, int have_locks) { - struct bonding *bond = bond_dev->priv; struct slave *slave, *oldcurrent; int do_failover = 0; - int delta_in_ticks; int i; - read_lock(&bond->lock); - - delta_in_ticks = (bond->params.miimon * HZ) / 1000; - - if (bond->kill_timers) { + if (bond->slave_cnt == 0) goto out; - } - - if (bond->slave_cnt == 0) { - goto re_arm; - } /* we will try to read the link status of each of our slaves, and * set their IFF_RUNNING flag appropriately. For each slave not @@ -2141,7 +2151,11 @@ void bond_mii_monitor(struct net_device *bond_dev) switch (slave->link) { case BOND_LINK_UP: /* the link was up */ if (link_state == BMSR_LSTATUS) { - /* link stays up, nothing more to do */ + if (!oldcurrent) { + if (!have_locks) + return 1; + do_failover = 1; + } break; } else { /* link going down */ slave->link = BOND_LINK_FAIL; @@ -2156,7 +2170,7 @@ void bond_mii_monitor(struct net_device *bond_dev) ": %s: link status down for %s " "interface %s, disabling it in " "%d ms.\n", - bond_dev->name, + bond->dev->name, IS_UP(slave_dev) ? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) ? ((slave == oldcurrent) @@ -2174,6 +2188,9 @@ void bond_mii_monitor(struct net_device *bond_dev) if (link_state != BMSR_LSTATUS) { /* link stays down */ if (slave->delay <= 0) { + if (!have_locks) + return 1; + /* link down for too long time */ slave->link = BOND_LINK_DOWN; @@ -2189,7 +2206,7 @@ void bond_mii_monitor(struct net_device *bond_dev) ": %s: link status definitely " "down for interface %s, " "disabling it\n", - bond_dev->name, + bond->dev->name, slave_dev->name); /* notify ad that the link status has changed */ @@ -2215,7 +2232,7 @@ void bond_mii_monitor(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: link status up again after %d " "ms for interface %s.\n", - bond_dev->name, + bond->dev->name, (bond->params.downdelay - slave->delay) * bond->params.miimon, slave_dev->name); } @@ -2235,7 +2252,7 @@ void bond_mii_monitor(struct net_device *bond_dev) ": %s: link status up for " "interface %s, enabling it " "in %d ms.\n", - bond_dev->name, + bond->dev->name, slave_dev->name, bond->params.updelay * bond->params.miimon); } @@ -2251,12 +2268,15 @@ void bond_mii_monitor(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: link status down again after %d " "ms for interface %s.\n", - bond_dev->name, + bond->dev->name, (bond->params.updelay - slave->delay) * bond->params.miimon, slave_dev->name); } else { /* link stays up */ if (slave->delay == 0) { + if (!have_locks) + return 1; + /* now the link has been up for long time enough */ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; @@ -2275,7 +2295,7 @@ void bond_mii_monitor(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: link status definitely " "up for interface %s.\n", - bond_dev->name, + bond->dev->name, slave_dev->name); /* notify ad that the link status has changed */ @@ -2301,7 +2321,7 @@ void bond_mii_monitor(struct net_device *bond_dev) /* Should not happen */ printk(KERN_ERR DRV_NAME ": %s: Error: %s Illegal value (link=%d)\n", - bond_dev->name, + bond->dev->name, slave->dev->name, slave->link); goto out; @@ -2322,22 +2342,52 @@ void bond_mii_monitor(struct net_device *bond_dev) } /* end of for */ if (do_failover) { - write_lock(&bond->curr_slave_lock); + ASSERT_RTNL(); + + write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); - write_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); + } else bond_set_carrier(bond); -re_arm: - if (bond->params.miimon) { - mod_timer(&bond->mii_timer, jiffies + delta_in_ticks); - } out: - read_unlock(&bond->lock); + return 0; } +/* + * bond_mii_monitor + * + * Really a wrapper that splits the mii monitor into two phases: an + * inspection, then (if inspection indicates something needs to be + * done) an acquisition of appropriate locks followed by another pass + * to implement whatever link state changes are indicated. + */ +void bond_mii_monitor(struct work_struct *work) +{ + struct bonding *bond = container_of(work, struct bonding, + mii_work.work); + unsigned long delay; + + read_lock(&bond->lock); + if (bond->kill_timers) { + read_unlock(&bond->lock); + return; + } + if (__bond_mii_monitor(bond, 0)) { + read_unlock(&bond->lock); + rtnl_lock(); + read_lock(&bond->lock); + __bond_mii_monitor(bond, 1); + rtnl_unlock(); + } + + delay = ((bond->params.miimon * HZ) / 1000) ? : 1; + read_unlock(&bond->lock); + queue_delayed_work(bond->wq, &bond->mii_work, delay); +} static __be32 bond_glean_dev_ip(struct net_device *dev) { @@ -2636,9 +2686,10 @@ 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(struct work_struct *work) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = container_of(work, struct bonding, + arp_work.work); struct slave *slave, *oldcurrent; int do_failover = 0; int delta_in_ticks; @@ -2685,13 +2736,13 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: link status definitely " "up for interface %s, ", - bond_dev->name, + bond->dev->name, slave->dev->name); do_failover = 1; } else { printk(KERN_INFO DRV_NAME ": %s: interface %s is now up\n", - bond_dev->name, + bond->dev->name, slave->dev->name); } } @@ -2715,7 +2766,7 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: interface %s is now down.\n", - bond_dev->name, + bond->dev->name, slave->dev->name); if (slave == oldcurrent) { @@ -2737,17 +2788,19 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev) } if (do_failover) { - write_lock(&bond->curr_slave_lock); + rtnl_lock(); + write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); - write_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); + rtnl_unlock(); + } re_arm: - if (bond->params.arp_interval) { - mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); - } + if (bond->params.arp_interval) + queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); out: read_unlock(&bond->lock); } @@ -2767,9 +2820,10 @@ 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(struct work_struct *work) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = container_of(work, struct bonding, + arp_work.work); struct slave *slave; int delta_in_ticks; int i; @@ -2798,7 +2852,9 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) slave->link = BOND_LINK_UP; - write_lock(&bond->curr_slave_lock); + rtnl_lock(); + + write_lock_bh(&bond->curr_slave_lock); if ((!bond->curr_active_slave) && ((jiffies - slave->dev->trans_start) <= delta_in_ticks)) { @@ -2821,18 +2877,19 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: %s is up and now the " "active interface\n", - bond_dev->name, + bond->dev->name, slave->dev->name); netif_carrier_on(bond->dev); } else { printk(KERN_INFO DRV_NAME ": %s: backup interface %s is " "now up\n", - bond_dev->name, + bond->dev->name, slave->dev->name); } - write_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); + rtnl_unlock(); } } else { read_lock(&bond->curr_slave_lock); @@ -2864,7 +2921,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: backup interface %s is now down\n", - bond_dev->name, + bond->dev->name, slave->dev->name); } else { read_unlock(&bond->curr_slave_lock); @@ -2899,15 +2956,18 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: link status down for active interface " "%s, disabling it\n", - bond_dev->name, + bond->dev->name, slave->dev->name); - write_lock(&bond->curr_slave_lock); + rtnl_lock(); + write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); slave = bond->curr_active_slave; - write_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); + + rtnl_unlock(); bond->current_arp_slave = slave; @@ -2921,14 +2981,17 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: changing from interface %s to primary " "interface %s\n", - bond_dev->name, + bond->dev->name, slave->dev->name, bond->primary_slave->dev->name); /* primary is up so switch to it */ - write_lock(&bond->curr_slave_lock); + rtnl_lock(); + write_lock_bh(&bond->curr_slave_lock); bond_change_active_slave(bond, bond->primary_slave); - write_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); + + rtnl_unlock(); slave = bond->primary_slave; slave->jiffies = jiffies; @@ -2985,7 +3048,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) printk(KERN_INFO DRV_NAME ": %s: backup interface %s is " "now down.\n", - bond_dev->name, + bond->dev->name, slave->dev->name); } } @@ -2994,7 +3057,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) re_arm: if (bond->params.arp_interval) { - mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); + queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); } out: read_unlock(&bond->lock); @@ -3015,7 +3078,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) /* 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; @@ -3049,7 +3112,7 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v) { struct bonding *bond = seq->private; - read_unlock_bh(&bond->lock); + read_unlock(&bond->lock); read_unlock(&dev_base_lock); } @@ -3582,15 +3645,11 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, 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. */ @@ -3599,44 +3658,31 @@ static int bond_open(struct net_device *bond_dev) 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); + INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor); + queue_delayed_work(bond->wq, &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); + INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor); + queue_delayed_work(bond->wq, &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; - } else { - arp_timer->function |