提交 bb69ae04 编写于 作者: E Eric Dumazet 提交者: David S. Miller

anycast: Some RCU conversions

- dev_get_by_flags() changed to dev_get_by_flags_rcu()

- ipv6_sock_ac_join() dont touch dev & idev refcounts
- ipv6_sock_ac_drop() dont touch dev & idev refcounts
- ipv6_sock_ac_close() dont touch dev & idev refcounts
- ipv6_dev_ac_dec() dount touch idev refcount
- ipv6_chk_acast_addr() dont touch idev refcount
Signed-off-by: NEric Dumazet <eric.dumazet@gmail.com>
CC: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 6e8b11b4
...@@ -1271,8 +1271,8 @@ extern void dev_add_pack(struct packet_type *pt); ...@@ -1271,8 +1271,8 @@ extern void dev_add_pack(struct packet_type *pt);
extern void dev_remove_pack(struct packet_type *pt); extern void dev_remove_pack(struct packet_type *pt);
extern void __dev_remove_pack(struct packet_type *pt); extern void __dev_remove_pack(struct packet_type *pt);
extern struct net_device *dev_get_by_flags(struct net *net, unsigned short flags, extern struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short flags,
unsigned short mask); unsigned short mask);
extern struct net_device *dev_get_by_name(struct net *net, const char *name); extern struct net_device *dev_get_by_name(struct net *net, const char *name);
extern struct net_device *dev_get_by_name_rcu(struct net *net, const char *name); extern struct net_device *dev_get_by_name_rcu(struct net *net, const char *name);
extern struct net_device *__dev_get_by_name(struct net *net, const char *name); extern struct net_device *__dev_get_by_name(struct net *net, const char *name);
......
...@@ -803,35 +803,31 @@ struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type) ...@@ -803,35 +803,31 @@ struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type)
EXPORT_SYMBOL(dev_getfirstbyhwtype); EXPORT_SYMBOL(dev_getfirstbyhwtype);
/** /**
* dev_get_by_flags - find any device with given flags * dev_get_by_flags_rcu - find any device with given flags
* @net: the applicable net namespace * @net: the applicable net namespace
* @if_flags: IFF_* values * @if_flags: IFF_* values
* @mask: bitmask of bits in if_flags to check * @mask: bitmask of bits in if_flags to check
* *
* Search for any interface with the given flags. Returns NULL if a device * Search for any interface with the given flags. Returns NULL if a device
* is not found or a pointer to the device. The device returned has * is not found or a pointer to the device. Must be called inside
* had a reference added and the pointer is safe until the user calls * rcu_read_lock(), and result refcount is unchanged.
* dev_put to indicate they have finished with it.
*/ */
struct net_device *dev_get_by_flags(struct net *net, unsigned short if_flags, struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags,
unsigned short mask) unsigned short mask)
{ {
struct net_device *dev, *ret; struct net_device *dev, *ret;
ret = NULL; ret = NULL;
rcu_read_lock();
for_each_netdev_rcu(net, dev) { for_each_netdev_rcu(net, dev) {
if (((dev->flags ^ if_flags) & mask) == 0) { if (((dev->flags ^ if_flags) & mask) == 0) {
dev_hold(dev);
ret = dev; ret = dev;
break; break;
} }
} }
rcu_read_unlock();
return ret; return ret;
} }
EXPORT_SYMBOL(dev_get_by_flags); EXPORT_SYMBOL(dev_get_by_flags_rcu);
/** /**
* dev_valid_name - check if name is okay for network device * dev_valid_name - check if name is okay for network device
......
...@@ -77,41 +77,40 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) ...@@ -77,41 +77,40 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
pac->acl_next = NULL; pac->acl_next = NULL;
ipv6_addr_copy(&pac->acl_addr, addr); ipv6_addr_copy(&pac->acl_addr, addr);
rcu_read_lock();
if (ifindex == 0) { if (ifindex == 0) {
struct rt6_info *rt; struct rt6_info *rt;
rt = rt6_lookup(net, addr, NULL, 0, 0); rt = rt6_lookup(net, addr, NULL, 0, 0);
if (rt) { if (rt) {
dev = rt->rt6i_dev; dev = rt->rt6i_dev;
dev_hold(dev);
dst_release(&rt->u.dst); dst_release(&rt->u.dst);
} else if (ishost) { } else if (ishost) {
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
goto out_free_pac; goto error;
} else { } else {
/* router, no matching interface: just pick one */ /* router, no matching interface: just pick one */
dev = dev_get_by_flags_rcu(net, IFF_UP,
dev = dev_get_by_flags(net, IFF_UP, IFF_UP|IFF_LOOPBACK); IFF_UP | IFF_LOOPBACK);
} }
} else } else
dev = dev_get_by_index(net, ifindex); dev = dev_get_by_index_rcu(net, ifindex);
if (dev == NULL) { if (dev == NULL) {
err = -ENODEV; err = -ENODEV;
goto out_free_pac; goto error;
} }
idev = in6_dev_get(dev); idev = __in6_dev_get(dev);
if (!idev) { if (!idev) {
if (ifindex) if (ifindex)
err = -ENODEV; err = -ENODEV;
else else
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
goto out_dev_put; goto error;
} }
/* reset ishost, now that we have a specific device */ /* reset ishost, now that we have a specific device */
ishost = !idev->cnf.forwarding; ishost = !idev->cnf.forwarding;
in6_dev_put(idev);
pac->acl_ifindex = dev->ifindex; pac->acl_ifindex = dev->ifindex;
...@@ -124,26 +123,22 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) ...@@ -124,26 +123,22 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
if (ishost) if (ishost)
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
if (err) if (err)
goto out_dev_put; goto error;
} }
err = ipv6_dev_ac_inc(dev, addr); err = ipv6_dev_ac_inc(dev, addr);
if (err) if (!err) {
goto out_dev_put; write_lock_bh(&ipv6_sk_ac_lock);
pac->acl_next = np->ipv6_ac_list;
write_lock_bh(&ipv6_sk_ac_lock); np->ipv6_ac_list = pac;
pac->acl_next = np->ipv6_ac_list; write_unlock_bh(&ipv6_sk_ac_lock);
np->ipv6_ac_list = pac; pac = NULL;
write_unlock_bh(&ipv6_sk_ac_lock); }
dev_put(dev);
return 0;
out_dev_put: error:
dev_put(dev); rcu_read_unlock();
out_free_pac: if (pac)
sock_kfree_s(sk, pac, sizeof(*pac)); sock_kfree_s(sk, pac, sizeof(*pac));
return err; return err;
} }
...@@ -176,11 +171,12 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr) ...@@ -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); write_unlock_bh(&ipv6_sk_ac_lock);
dev = dev_get_by_index(net, pac->acl_ifindex); rcu_read_lock();
if (dev) { dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
if (dev)
ipv6_dev_ac_dec(dev, &pac->acl_addr); ipv6_dev_ac_dec(dev, &pac->acl_addr);
dev_put(dev); rcu_read_unlock();
}
sock_kfree_s(sk, pac, sizeof(*pac)); sock_kfree_s(sk, pac, sizeof(*pac));
return 0; return 0;
} }
...@@ -199,13 +195,12 @@ void ipv6_sock_ac_close(struct sock *sk) ...@@ -199,13 +195,12 @@ void ipv6_sock_ac_close(struct sock *sk)
write_unlock_bh(&ipv6_sk_ac_lock); write_unlock_bh(&ipv6_sk_ac_lock);
prev_index = 0; prev_index = 0;
rcu_read_lock();
while (pac) { while (pac) {
struct ipv6_ac_socklist *next = pac->acl_next; struct ipv6_ac_socklist *next = pac->acl_next;
if (pac->acl_ifindex != prev_index) { if (pac->acl_ifindex != prev_index) {
if (dev) dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
dev_put(dev);
dev = dev_get_by_index(net, pac->acl_ifindex);
prev_index = pac->acl_ifindex; prev_index = pac->acl_ifindex;
} }
if (dev) if (dev)
...@@ -213,8 +208,7 @@ void ipv6_sock_ac_close(struct sock *sk) ...@@ -213,8 +208,7 @@ void ipv6_sock_ac_close(struct sock *sk)
sock_kfree_s(sk, pac, sizeof(*pac)); sock_kfree_s(sk, pac, sizeof(*pac));
pac = next; pac = next;
} }
if (dev) rcu_read_unlock();
dev_put(dev);
} }
#if 0 #if 0
...@@ -363,33 +357,32 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) ...@@ -363,33 +357,32 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr)
return 0; return 0;
} }
/* called with rcu_read_lock() */
static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) 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) if (idev == NULL)
return -ENODEV; return -ENODEV;
ret = __ipv6_dev_ac_dec(idev, addr); return __ipv6_dev_ac_dec(idev, addr);
in6_dev_put(idev);
return ret;
} }
/* /*
* check if the interface has this anycast address * 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) static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
{ {
struct inet6_dev *idev; struct inet6_dev *idev;
struct ifacaddr6 *aca; struct ifacaddr6 *aca;
idev = in6_dev_get(dev); idev = __in6_dev_get(dev);
if (idev) { if (idev) {
read_lock_bh(&idev->lock); read_lock_bh(&idev->lock);
for (aca = idev->ac_list; aca; aca = aca->aca_next) for (aca = idev->ac_list; aca; aca = aca->aca_next)
if (ipv6_addr_equal(&aca->aca_addr, addr)) if (ipv6_addr_equal(&aca->aca_addr, addr))
break; break;
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
in6_dev_put(idev);
return aca != NULL; return aca != NULL;
} }
return 0; return 0;
...@@ -403,14 +396,15 @@ int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, ...@@ -403,14 +396,15 @@ int ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
{ {
int found = 0; int found = 0;
if (dev)
return ipv6_chk_acast_dev(dev, addr);
rcu_read_lock(); rcu_read_lock();
for_each_netdev_rcu(net, dev) if (dev)
if (ipv6_chk_acast_dev(dev, addr)) { found = ipv6_chk_acast_dev(dev, addr);
found = 1; else
break; for_each_netdev_rcu(net, dev)
} if (ipv6_chk_acast_dev(dev, addr)) {
found = 1;
break;
}
rcu_read_unlock(); rcu_read_unlock();
return found; return found;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册