diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2010-05-10 11:59:37 +0200 | 
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2010-05-10 14:20:42 +0200 | 
| commit | dbb6be6d5e974c42bbecd183effaa0df69e1dd8b (patch) | |
| tree | 5735cb47e70853d057a9881dd0ce44b83e88fa63 /drivers/net/bonding/bond_main.c | |
| parent | 6a867a395558a7f882d041783e4cdea6744ca2bf (diff) | |
| parent | b57f95a38233a2e73b679bea4a5453a1cc2a1cc9 (diff) | |
| download | olio-linux-3.10-dbb6be6d5e974c42bbecd183effaa0df69e1dd8b.tar.xz olio-linux-3.10-dbb6be6d5e974c42bbecd183effaa0df69e1dd8b.zip  | |
Merge branch 'linus' into timers/core
Reason: Further posix_cpu_timer patches depend on mainline changes
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
| -rw-r--r-- | drivers/net/bonding/bond_main.c | 66 | 
1 files changed, 46 insertions, 20 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 430c02267d7..0075514bf32 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1235,6 +1235,11 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)  			write_lock_bh(&bond->curr_slave_lock);  		}  	} + +	/* resend IGMP joins since all were sent on curr_active_slave */ +	if (bond->params.mode == BOND_MODE_ROUNDROBIN) { +		bond_resend_igmp_join_requests(bond); +	}  }  /** @@ -4138,22 +4143,41 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev  	struct bonding *bond = netdev_priv(bond_dev);  	struct slave *slave, *start_at;  	int i, slave_no, res = 1; +	struct iphdr *iph = ip_hdr(skb);  	read_lock(&bond->lock);  	if (!BOND_IS_OK(bond))  		goto out; -  	/* -	 * Concurrent TX may collide on rr_tx_counter; we accept that -	 * as being rare enough not to justify using an atomic op here +	 * Start with the curr_active_slave that joined the bond as the +	 * default for sending IGMP traffic.  For failover purposes one +	 * needs to maintain some consistency for the interface that will +	 * send the join/membership reports.  The curr_active_slave found +	 * will send all of this type of traffic.  	 */ -	slave_no = bond->rr_tx_counter++ % bond->slave_cnt; +	if ((iph->protocol == IPPROTO_IGMP) && +	    (skb->protocol == htons(ETH_P_IP))) { -	bond_for_each_slave(bond, slave, i) { -		slave_no--; -		if (slave_no < 0) -			break; +		read_lock(&bond->curr_slave_lock); +		slave = bond->curr_active_slave; +		read_unlock(&bond->curr_slave_lock); + +		if (!slave) +			goto out; +	} else { +		/* +		 * Concurrent TX may collide on rr_tx_counter; we accept +		 * that as being rare enough not to justify using an +		 * atomic op here. +		 */ +		slave_no = bond->rr_tx_counter++ % bond->slave_cnt; + +		bond_for_each_slave(bond, slave, i) { +			slave_no--; +			if (slave_no < 0) +				break; +		}  	}  	start_at = slave; @@ -4426,6 +4450,14 @@ static const struct net_device_ops bond_netdev_ops = {  	.ndo_vlan_rx_kill_vid	= bond_vlan_rx_kill_vid,  }; +static void bond_destructor(struct net_device *bond_dev) +{ +	struct bonding *bond = netdev_priv(bond_dev); +	if (bond->wq) +		destroy_workqueue(bond->wq); +	free_netdev(bond_dev); +} +  static void bond_setup(struct net_device *bond_dev)  {  	struct bonding *bond = netdev_priv(bond_dev); @@ -4446,7 +4478,7 @@ static void bond_setup(struct net_device *bond_dev)  	bond_dev->ethtool_ops = &bond_ethtool_ops;  	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; @@ -4518,9 +4550,6 @@ static void bond_uninit(struct net_device *bond_dev)  	bond_remove_proc_entry(bond); -	if (bond->wq) -		destroy_workqueue(bond->wq); -  	netif_addr_lock_bh(bond_dev);  	bond_mc_list_destroy(bond);  	netif_addr_unlock_bh(bond_dev); @@ -4932,8 +4961,8 @@ int bond_create(struct net *net, const char *name)  				bond_setup);  	if (!bond_dev) {  		pr_err("%s: eek! can't alloc netdev!\n", name); -		res = -ENOMEM; -		goto out; +		rtnl_unlock(); +		return -ENOMEM;  	}  	dev_net_set(bond_dev, net); @@ -4942,19 +4971,16 @@ int bond_create(struct net *net, const char *name)  	if (!name) {  		res = dev_alloc_name(bond_dev, "bond%d");  		if (res < 0) -			goto out_netdev; +			goto out;  	}  	res = register_netdevice(bond_dev); -	if (res < 0) -		goto out_netdev;  out:  	rtnl_unlock(); +	if (res < 0) +		bond_destructor(bond_dev);  	return res; -out_netdev: -	free_netdev(bond_dev); -	goto out;  }  static int __net_init bond_net_init(struct net *net)  |