diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-04 11:47:58 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-04 11:47:58 -0700 | 
| commit | 6ba74014c1ab0e37af7de6f64b4eccbbae3cb9e7 (patch) | |
| tree | 8f3892fc44f1e403675a6d7e88fda5c70e56ee4c /net/ipv6/anycast.c | |
| parent | 5abd9ccced7a726c817dd6b5b96bc933859138d1 (diff) | |
| parent | 3ff1c25927e3af61c6bf0e4ed959504058ae4565 (diff) | |
| download | olio-linux-3.10-6ba74014c1ab0e37af7de6f64b4eccbbae3cb9e7.tar.xz olio-linux-3.10-6ba74014c1ab0e37af7de6f64b4eccbbae3cb9e7.zip  | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1443 commits)
  phy/marvell: add 88ec048 support
  igb: Program MDICNFG register prior to PHY init
  e1000e: correct MAC-PHY interconnect register offset for 82579
  hso: Add new product ID
  can: Add driver for esd CAN-USB/2 device
  l2tp: fix export of header file for userspace
  can-raw: Fix skb_orphan_try handling
  Revert "net: remove zap_completion_queue"
  net: cleanup inclusion
  phy/marvell: add 88e1121 interface mode support
  u32: negative offset fix
  net: Fix a typo from "dev" to "ndev"
  igb: Use irq_synchronize per vector when using MSI-X
  ixgbevf: fix null pointer dereference due to filter being set for VLAN 0
  e1000e: Fix irq_synchronize in MSI-X case
  e1000e: register pm_qos request on hardware activation
  ip_fragment: fix subtracting PPPOE_SES_HLEN from mtu twice
  net: Add getsockopt support for TCP thin-streams
  cxgb4: update driver version
  cxgb4: add new PCI IDs
  ...
Manually fix up conflicts in:
 - drivers/net/e1000e/netdev.c: due to pm_qos registration
   infrastructure changes
 - drivers/net/phy/marvell.c: conflict between adding 88ec048 support
   and cleaning up the IDs
 - drivers/net/wireless/ipw2x00/ipw2100.c: trivial ipw2100_pm_qos_req
   conflict (registration change vs marking it static)
Diffstat (limited to 'net/ipv6/anycast.c')
| -rw-r--r-- | net/ipv6/anycast.c | 96 | 
1 files changed, 45 insertions, 51 deletions
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index b5b07054508..0e5e943446f 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -77,41 +77,40 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)  	pac->acl_next = NULL;  	ipv6_addr_copy(&pac->acl_addr, addr); +	rcu_read_lock();  	if (ifindex == 0) {  		struct rt6_info *rt;  		rt = rt6_lookup(net, addr, NULL, 0, 0);  		if (rt) {  			dev = rt->rt6i_dev; -			dev_hold(dev); -			dst_release(&rt->u.dst); +			dst_release(&rt->dst);  		} else if (ishost) {  			err = -EADDRNOTAVAIL; -			goto out_free_pac; +			goto error;  		} else {  			/* router, no matching interface: just pick one */ - -			dev = dev_get_by_flags(net, IFF_UP, IFF_UP|IFF_LOOPBACK); +			dev = dev_get_by_flags_rcu(net, IFF_UP, +						   IFF_UP | IFF_LOOPBACK);  		}  	} else -		dev = dev_get_by_index(net, ifindex); +		dev = dev_get_by_index_rcu(net, ifindex);  	if (dev == NULL) {  		err = -ENODEV; -		goto out_free_pac; +		goto error;  	} -	idev = in6_dev_get(dev); +	idev = __in6_dev_get(dev);  	if (!idev) {  		if (ifindex)  			err = -ENODEV;  		else  			err = -EADDRNOTAVAIL; -		goto out_dev_put; +		goto error;  	}  	/* reset ishost, now that we have a specific device */  	ishost = !idev->cnf.forwarding; -	in6_dev_put(idev);  	pac->acl_ifindex = dev->ifindex; @@ -124,26 +123,22 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)  		if (ishost)  			err = -EADDRNOTAVAIL;  		if (err) -			goto out_dev_put; +			goto error;  	}  	err = ipv6_dev_ac_inc(dev, addr); -	if (err) -		goto out_dev_put; - -	write_lock_bh(&ipv6_sk_ac_lock); -	pac->acl_next = np->ipv6_ac_list; -	np->ipv6_ac_list = pac; -	write_unlock_bh(&ipv6_sk_ac_lock); - -	dev_put(dev); - -	return 0; +	if (!err) { +		write_lock_bh(&ipv6_sk_ac_lock); +		pac->acl_next = np->ipv6_ac_list; +		np->ipv6_ac_list = pac; +		write_unlock_bh(&ipv6_sk_ac_lock); +		pac = NULL; +	} -out_dev_put: -	dev_put(dev); -out_free_pac: -	sock_kfree_s(sk, pac, sizeof(*pac)); +error: +	rcu_read_unlock(); +	if (pac) +		sock_kfree_s(sk, pac, sizeof(*pac));  	return err;  } @@ -176,11 +171,12 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)  	write_unlock_bh(&ipv6_sk_ac_lock); -	dev = dev_get_by_index(net, pac->acl_ifindex); -	if (dev) { +	rcu_read_lock(); +	dev = dev_get_by_index_rcu(net, pac->acl_ifindex); +	if (dev)  		ipv6_dev_ac_dec(dev, &pac->acl_addr); -		dev_put(dev); -	} +	rcu_read_unlock(); +  	sock_kfree_s(sk, pac, sizeof(*pac));  	return 0;  } @@ -199,13 +195,12 @@ void ipv6_sock_ac_close(struct sock *sk)  	write_unlock_bh(&ipv6_sk_ac_lock);  	prev_index = 0; +	rcu_read_lock();  	while (pac) {  		struct ipv6_ac_socklist *next = pac->acl_next;  		if (pac->acl_ifindex != prev_index) { -			if (dev) -				dev_put(dev); -			dev = dev_get_by_index(net, pac->acl_ifindex); +			dev = dev_get_by_index_rcu(net, pac->acl_ifindex);  			prev_index = pac->acl_ifindex;  		}  		if (dev) @@ -213,8 +208,7 @@ void ipv6_sock_ac_close(struct sock *sk)  		sock_kfree_s(sk, pac, sizeof(*pac));  		pac = next;  	} -	if (dev) -		dev_put(dev); +	rcu_read_unlock();  }  #if 0 @@ -250,7 +244,7 @@ static void aca_put(struct ifacaddr6 *ac)  {  	if (atomic_dec_and_test(&ac->aca_refcnt)) {  		in6_dev_put(ac->aca_idev); -		dst_release(&ac->aca_rt->u.dst); +		dst_release(&ac->aca_rt->dst);  		kfree(ac);  	}  } @@ -356,40 +350,39 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr)  	write_unlock_bh(&idev->lock);  	addrconf_leave_solict(idev, &aca->aca_addr); -	dst_hold(&aca->aca_rt->u.dst); +	dst_hold(&aca->aca_rt->dst);  	ip6_del_rt(aca->aca_rt);  	aca_put(aca);  	return 0;  } +/* called with rcu_read_lock() */  static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)  { -	int ret; -	struct inet6_dev *idev = in6_dev_get(dev); +	struct inet6_dev *idev = __in6_dev_get(dev); +  	if (idev == NULL)  		return -ENODEV; -	ret = __ipv6_dev_ac_dec(idev, addr); -	in6_dev_put(idev); -	return ret; +	return __ipv6_dev_ac_dec(idev, addr);  }  /*   *	check if the interface has this anycast address + *	called with rcu_read_lock()   */  static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)  {  	struct inet6_dev *idev;  	struct ifacaddr6 *aca; -	idev = in6_dev_get(dev); +	idev = __in6_dev_get(dev);  	if (idev) {  		read_lock_bh(&idev->lock);  		for (aca = idev->ac_list; aca; aca = aca->aca_next)  			if (ipv6_addr_equal(&aca->aca_addr, addr))  				break;  		read_unlock_bh(&idev->lock); -		in6_dev_put(idev);  		return aca != NULL;  	}  	return 0; @@ -403,14 +396,15 @@ int ipv6_chk_acast_addr(struct net *net, struct net_device *dev,  {  	int found = 0; -	if (dev) -		return ipv6_chk_acast_dev(dev, addr);  	rcu_read_lock(); -	for_each_netdev_rcu(net, dev) -		if (ipv6_chk_acast_dev(dev, addr)) { -			found = 1; -			break; -		} +	if (dev) +		found = ipv6_chk_acast_dev(dev, addr); +	else +		for_each_netdev_rcu(net, dev) +			if (ipv6_chk_acast_dev(dev, addr)) { +				found = 1; +				break; +			}  	rcu_read_unlock();  	return found;  }  |