mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
neighbour: switch to standard rcu, instead of rcu_bh
rcu_bh is no longer a win, especially for objects freed with standard call_rcu(). Switch neighbour code to no longer disable BH when not necessary. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
4c5c496a94
commit
09eed1192c
@ -38,11 +38,11 @@ static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32
|
|||||||
{
|
{
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
n = __ipv4_neigh_lookup_noref(dev, key);
|
n = __ipv4_neigh_lookup_noref(dev, key);
|
||||||
if (n && !refcount_inc_not_zero(&n->refcnt))
|
if (n && !refcount_inc_not_zero(&n->refcnt))
|
||||||
n = NULL;
|
n = NULL;
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -51,10 +51,10 @@ static inline void __ipv4_confirm_neigh(struct net_device *dev, u32 key)
|
|||||||
{
|
{
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
n = __ipv4_neigh_lookup_noref(dev, key);
|
n = __ipv4_neigh_lookup_noref(dev, key);
|
||||||
neigh_confirm(n);
|
neigh_confirm(n);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void arp_init(void);
|
void arp_init(void);
|
||||||
|
@ -395,11 +395,11 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, cons
|
|||||||
{
|
{
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
n = __ipv6_neigh_lookup_noref(dev, pkey);
|
n = __ipv6_neigh_lookup_noref(dev, pkey);
|
||||||
if (n && !refcount_inc_not_zero(&n->refcnt))
|
if (n && !refcount_inc_not_zero(&n->refcnt))
|
||||||
n = NULL;
|
n = NULL;
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -409,10 +409,10 @@ static inline void __ipv6_confirm_neigh(struct net_device *dev,
|
|||||||
{
|
{
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
n = __ipv6_neigh_lookup_noref(dev, pkey);
|
n = __ipv6_neigh_lookup_noref(dev, pkey);
|
||||||
neigh_confirm(n);
|
neigh_confirm(n);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __ipv6_confirm_neigh_stub(struct net_device *dev,
|
static inline void __ipv6_confirm_neigh_stub(struct net_device *dev,
|
||||||
@ -420,10 +420,10 @@ static inline void __ipv6_confirm_neigh_stub(struct net_device *dev,
|
|||||||
{
|
{
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
n = __ipv6_neigh_lookup_noref_stub(dev, pkey);
|
n = __ipv6_neigh_lookup_noref_stub(dev, pkey);
|
||||||
neigh_confirm(n);
|
neigh_confirm(n);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* uses ipv6_stub and is meant for use outside of IPv6 core */
|
/* uses ipv6_stub and is meant for use outside of IPv6 core */
|
||||||
|
@ -299,14 +299,14 @@ static inline struct neighbour *___neigh_lookup_noref(
|
|||||||
const void *pkey,
|
const void *pkey,
|
||||||
struct net_device *dev)
|
struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct neigh_hash_table *nht = rcu_dereference_bh(tbl->nht);
|
struct neigh_hash_table *nht = rcu_dereference(tbl->nht);
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
u32 hash_val;
|
u32 hash_val;
|
||||||
|
|
||||||
hash_val = hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
|
hash_val = hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
|
||||||
for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
|
for (n = rcu_dereference(nht->hash_buckets[hash_val]);
|
||||||
n != NULL;
|
n != NULL;
|
||||||
n = rcu_dereference_bh(n->next)) {
|
n = rcu_dereference(n->next)) {
|
||||||
if (n->dev == dev && key_eq(n, pkey))
|
if (n->dev == dev && key_eq(n, pkey))
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -498,7 +498,7 @@ static inline struct fib6_nh *nexthop_fib6_nh(struct nexthop *nh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Variant of nexthop_fib6_nh().
|
/* Variant of nexthop_fib6_nh().
|
||||||
* Caller should either hold rcu_read_lock_bh(), or RTNL.
|
* Caller should either hold rcu_read_lock(), or RTNL.
|
||||||
*/
|
*/
|
||||||
static inline struct fib6_nh *nexthop_fib6_nh_bh(struct nexthop *nh)
|
static inline struct fib6_nh *nexthop_fib6_nh_bh(struct nexthop *nh)
|
||||||
{
|
{
|
||||||
@ -507,13 +507,13 @@ static inline struct fib6_nh *nexthop_fib6_nh_bh(struct nexthop *nh)
|
|||||||
if (nh->is_group) {
|
if (nh->is_group) {
|
||||||
struct nh_group *nh_grp;
|
struct nh_group *nh_grp;
|
||||||
|
|
||||||
nh_grp = rcu_dereference_bh_rtnl(nh->nh_grp);
|
nh_grp = rcu_dereference_rtnl(nh->nh_grp);
|
||||||
nh = nexthop_mpath_select(nh_grp, 0);
|
nh = nexthop_mpath_select(nh_grp, 0);
|
||||||
if (!nh)
|
if (!nh)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
nhi = rcu_dereference_bh_rtnl(nh->nh_info);
|
nhi = rcu_dereference_rtnl(nh->nh_info);
|
||||||
if (nhi->family == AF_INET6)
|
if (nhi->family == AF_INET6)
|
||||||
return &nhi->fib6_nh;
|
return &nhi->fib6_nh;
|
||||||
|
|
||||||
|
@ -2204,7 +2204,7 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
if (!nh) {
|
if (!nh) {
|
||||||
dst = skb_dst(skb);
|
dst = skb_dst(skb);
|
||||||
nexthop = rt6_nexthop(container_of(dst, struct rt6_info, dst),
|
nexthop = rt6_nexthop(container_of(dst, struct rt6_info, dst),
|
||||||
@ -2217,10 +2217,12 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
sock_confirm_neigh(skb, neigh);
|
sock_confirm_neigh(skb, neigh);
|
||||||
|
local_bh_disable();
|
||||||
dev_xmit_recursion_inc();
|
dev_xmit_recursion_inc();
|
||||||
ret = neigh_output(neigh, skb, false);
|
ret = neigh_output(neigh, skb, false);
|
||||||
dev_xmit_recursion_dec();
|
dev_xmit_recursion_dec();
|
||||||
rcu_read_unlock_bh();
|
local_bh_enable();
|
||||||
|
rcu_read_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock_bh();
|
||||||
@ -2302,7 +2304,7 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
if (!nh) {
|
if (!nh) {
|
||||||
struct dst_entry *dst = skb_dst(skb);
|
struct dst_entry *dst = skb_dst(skb);
|
||||||
struct rtable *rt = container_of(dst, struct rtable, dst);
|
struct rtable *rt = container_of(dst, struct rtable, dst);
|
||||||
@ -2314,7 +2316,7 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb,
|
|||||||
} else if (nh->nh_family == AF_INET) {
|
} else if (nh->nh_family == AF_INET) {
|
||||||
neigh = ip_neigh_gw4(dev, nh->ipv4_nh);
|
neigh = ip_neigh_gw4(dev, nh->ipv4_nh);
|
||||||
} else {
|
} else {
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
goto out_drop;
|
goto out_drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2322,13 +2324,15 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
sock_confirm_neigh(skb, neigh);
|
sock_confirm_neigh(skb, neigh);
|
||||||
|
local_bh_disable();
|
||||||
dev_xmit_recursion_inc();
|
dev_xmit_recursion_inc();
|
||||||
ret = neigh_output(neigh, skb, is_v6gw);
|
ret = neigh_output(neigh, skb, is_v6gw);
|
||||||
dev_xmit_recursion_dec();
|
dev_xmit_recursion_dec();
|
||||||
rcu_read_unlock_bh();
|
local_bh_enable();
|
||||||
|
rcu_read_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
out_drop:
|
out_drop:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return -ENETDOWN;
|
return -ENETDOWN;
|
||||||
|
@ -614,7 +614,7 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
|
|||||||
|
|
||||||
NEIGH_CACHE_STAT_INC(tbl, lookups);
|
NEIGH_CACHE_STAT_INC(tbl, lookups);
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
n = __neigh_lookup_noref(tbl, pkey, dev);
|
n = __neigh_lookup_noref(tbl, pkey, dev);
|
||||||
if (n) {
|
if (n) {
|
||||||
if (!refcount_inc_not_zero(&n->refcnt))
|
if (!refcount_inc_not_zero(&n->refcnt))
|
||||||
@ -622,7 +622,7 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
|
|||||||
NEIGH_CACHE_STAT_INC(tbl, hits);
|
NEIGH_CACHE_STAT_INC(tbl, hits);
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(neigh_lookup);
|
EXPORT_SYMBOL(neigh_lookup);
|
||||||
@ -2184,11 +2184,11 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
|
|||||||
.ndtc_proxy_qlen = tbl->proxy_queue.qlen,
|
.ndtc_proxy_qlen = tbl->proxy_queue.qlen,
|
||||||
};
|
};
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
nht = rcu_dereference_bh(tbl->nht);
|
nht = rcu_dereference(tbl->nht);
|
||||||
ndc.ndtc_hash_rnd = nht->hash_rnd[0];
|
ndc.ndtc_hash_rnd = nht->hash_rnd[0];
|
||||||
ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
|
ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
|
if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
@ -2703,15 +2703,15 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
|
|||||||
if (filter->dev_idx || filter->master_idx)
|
if (filter->dev_idx || filter->master_idx)
|
||||||
flags |= NLM_F_DUMP_FILTERED;
|
flags |= NLM_F_DUMP_FILTERED;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
nht = rcu_dereference_bh(tbl->nht);
|
nht = rcu_dereference(tbl->nht);
|
||||||
|
|
||||||
for (h = s_h; h < (1 << nht->hash_shift); h++) {
|
for (h = s_h; h < (1 << nht->hash_shift); h++) {
|
||||||
if (h > s_h)
|
if (h > s_h)
|
||||||
s_idx = 0;
|
s_idx = 0;
|
||||||
for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
|
for (n = rcu_dereference(nht->hash_buckets[h]), idx = 0;
|
||||||
n != NULL;
|
n != NULL;
|
||||||
n = rcu_dereference_bh(n->next)) {
|
n = rcu_dereference(n->next)) {
|
||||||
if (idx < s_idx || !net_eq(dev_net(n->dev), net))
|
if (idx < s_idx || !net_eq(dev_net(n->dev), net))
|
||||||
goto next;
|
goto next;
|
||||||
if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
|
if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
|
||||||
@ -2730,7 +2730,7 @@ next:
|
|||||||
}
|
}
|
||||||
rc = skb->len;
|
rc = skb->len;
|
||||||
out:
|
out:
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
cb->args[1] = h;
|
cb->args[1] = h;
|
||||||
cb->args[2] = idx;
|
cb->args[2] = idx;
|
||||||
return rc;
|
return rc;
|
||||||
@ -3075,20 +3075,20 @@ void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void
|
|||||||
int chain;
|
int chain;
|
||||||
struct neigh_hash_table *nht;
|
struct neigh_hash_table *nht;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
nht = rcu_dereference_bh(tbl->nht);
|
nht = rcu_dereference(tbl->nht);
|
||||||
|
|
||||||
read_lock(&tbl->lock); /* avoid resizes */
|
read_lock_bh(&tbl->lock); /* avoid resizes */
|
||||||
for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
|
for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
|
for (n = rcu_dereference(nht->hash_buckets[chain]);
|
||||||
n != NULL;
|
n != NULL;
|
||||||
n = rcu_dereference_bh(n->next))
|
n = rcu_dereference(n->next))
|
||||||
cb(n, cookie);
|
cb(n, cookie);
|
||||||
}
|
}
|
||||||
read_unlock(&tbl->lock);
|
read_unlock_bh(&tbl->lock);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(neigh_for_each);
|
EXPORT_SYMBOL(neigh_for_each);
|
||||||
|
|
||||||
@ -3138,7 +3138,7 @@ int neigh_xmit(int index, struct net_device *dev,
|
|||||||
tbl = neigh_tables[index];
|
tbl = neigh_tables[index];
|
||||||
if (!tbl)
|
if (!tbl)
|
||||||
goto out;
|
goto out;
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
if (index == NEIGH_ARP_TABLE) {
|
if (index == NEIGH_ARP_TABLE) {
|
||||||
u32 key = *((u32 *)addr);
|
u32 key = *((u32 *)addr);
|
||||||
|
|
||||||
@ -3150,11 +3150,11 @@ int neigh_xmit(int index, struct net_device *dev,
|
|||||||
neigh = __neigh_create(tbl, addr, dev, false);
|
neigh = __neigh_create(tbl, addr, dev, false);
|
||||||
err = PTR_ERR(neigh);
|
err = PTR_ERR(neigh);
|
||||||
if (IS_ERR(neigh)) {
|
if (IS_ERR(neigh)) {
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
goto out_kfree_skb;
|
goto out_kfree_skb;
|
||||||
}
|
}
|
||||||
err = neigh->output(neigh, skb);
|
err = neigh->output(neigh, skb);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
else if (index == NEIGH_LINK_TABLE) {
|
else if (index == NEIGH_LINK_TABLE) {
|
||||||
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
|
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
|
||||||
@ -3183,7 +3183,7 @@ static struct neighbour *neigh_get_first(struct seq_file *seq)
|
|||||||
|
|
||||||
state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
|
state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
|
||||||
for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
|
for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
|
||||||
n = rcu_dereference_bh(nht->hash_buckets[bucket]);
|
n = rcu_dereference(nht->hash_buckets[bucket]);
|
||||||
|
|
||||||
while (n) {
|
while (n) {
|
||||||
if (!net_eq(dev_net(n->dev), net))
|
if (!net_eq(dev_net(n->dev), net))
|
||||||
@ -3201,7 +3201,7 @@ static struct neighbour *neigh_get_first(struct seq_file *seq)
|
|||||||
if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
|
if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
|
||||||
break;
|
break;
|
||||||
next:
|
next:
|
||||||
n = rcu_dereference_bh(n->next);
|
n = rcu_dereference(n->next);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n)
|
if (n)
|
||||||
@ -3225,7 +3225,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq,
|
|||||||
if (v)
|
if (v)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
n = rcu_dereference_bh(n->next);
|
n = rcu_dereference(n->next);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
while (n) {
|
while (n) {
|
||||||
@ -3243,7 +3243,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq,
|
|||||||
if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
|
if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
|
||||||
break;
|
break;
|
||||||
next:
|
next:
|
||||||
n = rcu_dereference_bh(n->next);
|
n = rcu_dereference(n->next);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n)
|
if (n)
|
||||||
@ -3252,7 +3252,7 @@ next:
|
|||||||
if (++state->bucket >= (1 << nht->hash_shift))
|
if (++state->bucket >= (1 << nht->hash_shift))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
|
n = rcu_dereference(nht->hash_buckets[state->bucket]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n && pos)
|
if (n && pos)
|
||||||
@ -3354,7 +3354,7 @@ static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
|
|||||||
|
|
||||||
void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
|
void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
|
||||||
__acquires(tbl->lock)
|
__acquires(tbl->lock)
|
||||||
__acquires(rcu_bh)
|
__acquires(rcu)
|
||||||
{
|
{
|
||||||
struct neigh_seq_state *state = seq->private;
|
struct neigh_seq_state *state = seq->private;
|
||||||
|
|
||||||
@ -3362,9 +3362,9 @@ void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl
|
|||||||
state->bucket = 0;
|
state->bucket = 0;
|
||||||
state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
|
state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
state->nht = rcu_dereference_bh(tbl->nht);
|
state->nht = rcu_dereference(tbl->nht);
|
||||||
read_lock(&tbl->lock);
|
read_lock_bh(&tbl->lock);
|
||||||
|
|
||||||
return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
|
return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
|
||||||
}
|
}
|
||||||
@ -3399,13 +3399,13 @@ EXPORT_SYMBOL(neigh_seq_next);
|
|||||||
|
|
||||||
void neigh_seq_stop(struct seq_file *seq, void *v)
|
void neigh_seq_stop(struct seq_file *seq, void *v)
|
||||||
__releases(tbl->lock)
|
__releases(tbl->lock)
|
||||||
__releases(rcu_bh)
|
__releases(rcu)
|
||||||
{
|
{
|
||||||
struct neigh_seq_state *state = seq->private;
|
struct neigh_seq_state *state = seq->private;
|
||||||
struct neigh_table *tbl = state->tbl;
|
struct neigh_table *tbl = state->tbl;
|
||||||
|
|
||||||
read_unlock(&tbl->lock);
|
read_unlock_bh(&tbl->lock);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(neigh_seq_stop);
|
EXPORT_SYMBOL(neigh_seq_stop);
|
||||||
|
|
||||||
|
@ -2191,7 +2191,7 @@ static bool fib_good_nh(const struct fib_nh *nh)
|
|||||||
if (nh->fib_nh_scope == RT_SCOPE_LINK) {
|
if (nh->fib_nh_scope == RT_SCOPE_LINK) {
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
|
|
||||||
if (likely(nh->fib_nh_gw_family == AF_INET))
|
if (likely(nh->fib_nh_gw_family == AF_INET))
|
||||||
n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev,
|
n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev,
|
||||||
@ -2204,7 +2204,7 @@ static bool fib_good_nh(const struct fib_nh *nh)
|
|||||||
if (n)
|
if (n)
|
||||||
state = READ_ONCE(n->nud_state);
|
state = READ_ONCE(n->nud_state);
|
||||||
|
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!(state & NUD_VALID);
|
return !!(state & NUD_VALID);
|
||||||
|
@ -219,7 +219,7 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
neigh = ip_neigh_for_gw(rt, skb, &is_v6gw);
|
neigh = ip_neigh_for_gw(rt, skb, &is_v6gw);
|
||||||
if (!IS_ERR(neigh)) {
|
if (!IS_ERR(neigh)) {
|
||||||
int res;
|
int res;
|
||||||
@ -227,10 +227,10 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s
|
|||||||
sock_confirm_neigh(skb, neigh);
|
sock_confirm_neigh(skb, neigh);
|
||||||
/* if crossing protocols, can not use the cached header */
|
/* if crossing protocols, can not use the cached header */
|
||||||
res = neigh_output(neigh, skb, is_v6gw);
|
res = neigh_output(neigh, skb, is_v6gw);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
net_dbg_ratelimited("%s: No header cache and no neighbour!\n",
|
net_dbg_ratelimited("%s: No header cache and no neighbour!\n",
|
||||||
__func__);
|
__func__);
|
||||||
|
@ -1124,13 +1124,13 @@ static bool ipv6_good_nh(const struct fib6_nh *nh)
|
|||||||
int state = NUD_REACHABLE;
|
int state = NUD_REACHABLE;
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
|
|
||||||
n = __ipv6_neigh_lookup_noref_stub(nh->fib_nh_dev, &nh->fib_nh_gw6);
|
n = __ipv6_neigh_lookup_noref_stub(nh->fib_nh_dev, &nh->fib_nh_gw6);
|
||||||
if (n)
|
if (n)
|
||||||
state = READ_ONCE(n->nud_state);
|
state = READ_ONCE(n->nud_state);
|
||||||
|
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return !!(state & NUD_VALID);
|
return !!(state & NUD_VALID);
|
||||||
}
|
}
|
||||||
@ -1140,14 +1140,14 @@ static bool ipv4_good_nh(const struct fib_nh *nh)
|
|||||||
int state = NUD_REACHABLE;
|
int state = NUD_REACHABLE;
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
|
|
||||||
n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev,
|
n = __ipv4_neigh_lookup_noref(nh->fib_nh_dev,
|
||||||
(__force u32)nh->fib_nh_gw4);
|
(__force u32)nh->fib_nh_gw4);
|
||||||
if (n)
|
if (n)
|
||||||
state = READ_ONCE(n->nud_state);
|
state = READ_ONCE(n->nud_state);
|
||||||
|
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return !!(state & NUD_VALID);
|
return !!(state & NUD_VALID);
|
||||||
}
|
}
|
||||||
|
@ -408,7 +408,7 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
|
|||||||
struct net_device *dev = dst->dev;
|
struct net_device *dev = dst->dev;
|
||||||
struct neighbour *n;
|
struct neighbour *n;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
|
|
||||||
if (likely(rt->rt_gw_family == AF_INET)) {
|
if (likely(rt->rt_gw_family == AF_INET)) {
|
||||||
n = ip_neigh_gw4(dev, rt->rt_gw4);
|
n = ip_neigh_gw4(dev, rt->rt_gw4);
|
||||||
@ -424,7 +424,7 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
|
|||||||
if (!IS_ERR(n) && !refcount_inc_not_zero(&n->refcnt))
|
if (!IS_ERR(n) && !refcount_inc_not_zero(&n->refcnt))
|
||||||
n = NULL;
|
n = NULL;
|
||||||
|
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -1034,7 +1034,7 @@ static int ipv6_add_addr_hash(struct net_device *dev, struct inet6_ifaddr *ifa)
|
|||||||
unsigned int hash = inet6_addr_hash(net, &ifa->addr);
|
unsigned int hash = inet6_addr_hash(net, &ifa->addr);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
spin_lock(&net->ipv6.addrconf_hash_lock);
|
spin_lock_bh(&net->ipv6.addrconf_hash_lock);
|
||||||
|
|
||||||
/* Ignore adding duplicate addresses on an interface */
|
/* Ignore adding duplicate addresses on an interface */
|
||||||
if (ipv6_chk_same_addr(net, &ifa->addr, dev, hash)) {
|
if (ipv6_chk_same_addr(net, &ifa->addr, dev, hash)) {
|
||||||
@ -1044,7 +1044,7 @@ static int ipv6_add_addr_hash(struct net_device *dev, struct inet6_ifaddr *ifa)
|
|||||||
hlist_add_head_rcu(&ifa->addr_lst, &net->ipv6.inet6_addr_lst[hash]);
|
hlist_add_head_rcu(&ifa->addr_lst, &net->ipv6.inet6_addr_lst[hash]);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&net->ipv6.addrconf_hash_lock);
|
spin_unlock_bh(&net->ipv6.addrconf_hash_lock);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1139,15 +1139,15 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
|
|||||||
/* For caller */
|
/* For caller */
|
||||||
refcount_set(&ifa->refcnt, 1);
|
refcount_set(&ifa->refcnt, 1);
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
|
|
||||||
err = ipv6_add_addr_hash(idev->dev, ifa);
|
err = ipv6_add_addr_hash(idev->dev, ifa);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_lock(&idev->lock);
|
write_lock_bh(&idev->lock);
|
||||||
|
|
||||||
/* Add to inet6_dev unicast addr list. */
|
/* Add to inet6_dev unicast addr list. */
|
||||||
ipv6_link_dev_addr(idev, ifa);
|
ipv6_link_dev_addr(idev, ifa);
|
||||||
@ -1158,9 +1158,9 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
in6_ifa_hold(ifa);
|
in6_ifa_hold(ifa);
|
||||||
write_unlock(&idev->lock);
|
write_unlock_bh(&idev->lock);
|
||||||
|
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
inet6addr_notifier_call_chain(NETDEV_UP, ifa);
|
inet6addr_notifier_call_chain(NETDEV_UP, ifa);
|
||||||
out:
|
out:
|
||||||
|
@ -116,7 +116,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
nexthop = rt6_nexthop((struct rt6_info *)dst, daddr);
|
nexthop = rt6_nexthop((struct rt6_info *)dst, daddr);
|
||||||
neigh = __ipv6_neigh_lookup_noref(dev, nexthop);
|
neigh = __ipv6_neigh_lookup_noref(dev, nexthop);
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
|
|||||||
if (unlikely(!neigh))
|
if (unlikely(!neigh))
|
||||||
neigh = __neigh_create(&nd_tbl, nexthop, dev, false);
|
neigh = __neigh_create(&nd_tbl, nexthop, dev, false);
|
||||||
if (IS_ERR(neigh)) {
|
if (IS_ERR(neigh)) {
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTNOROUTES);
|
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTNOROUTES);
|
||||||
kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_CREATEFAIL);
|
kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_CREATEFAIL);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -132,7 +132,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
|
|||||||
}
|
}
|
||||||
sock_confirm_neigh(skb, neigh);
|
sock_confirm_neigh(skb, neigh);
|
||||||
ret = neigh_output(neigh, skb, false);
|
ret = neigh_output(neigh, skb, false);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1150,11 +1150,11 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
|
|||||||
* dst entry of the nexthop router
|
* dst entry of the nexthop router
|
||||||
*/
|
*/
|
||||||
rt = (struct rt6_info *) *dst;
|
rt = (struct rt6_info *) *dst;
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
n = __ipv6_neigh_lookup_noref(rt->dst.dev,
|
n = __ipv6_neigh_lookup_noref(rt->dst.dev,
|
||||||
rt6_nexthop(rt, &fl6->daddr));
|
rt6_nexthop(rt, &fl6->daddr));
|
||||||
err = n && !(READ_ONCE(n->nud_state) & NUD_VALID) ? -EINVAL : 0;
|
err = n && !(READ_ONCE(n->nud_state) & NUD_VALID) ? -EINVAL : 0;
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
struct inet6_ifaddr *ifp;
|
struct inet6_ifaddr *ifp;
|
||||||
|
@ -633,7 +633,7 @@ static void rt6_probe(struct fib6_nh *fib6_nh)
|
|||||||
|
|
||||||
nh_gw = &fib6_nh->fib_nh_gw6;
|
nh_gw = &fib6_nh->fib_nh_gw6;
|
||||||
dev = fib6_nh->fib_nh_dev;
|
dev = fib6_nh->fib_nh_dev;
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
last_probe = READ_ONCE(fib6_nh->last_probe);
|
last_probe = READ_ONCE(fib6_nh->last_probe);
|
||||||
idev = __in6_dev_get(dev);
|
idev = __in6_dev_get(dev);
|
||||||
neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
|
neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
|
||||||
@ -641,7 +641,7 @@ static void rt6_probe(struct fib6_nh *fib6_nh)
|
|||||||
if (READ_ONCE(neigh->nud_state) & NUD_VALID)
|
if (READ_ONCE(neigh->nud_state) & NUD_VALID)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
write_lock(&neigh->lock);
|
write_lock_bh(&neigh->lock);
|
||||||
if (!(neigh->nud_state & NUD_VALID) &&
|
if (!(neigh->nud_state & NUD_VALID) &&
|
||||||
time_after(jiffies,
|
time_after(jiffies,
|
||||||
neigh->updated + idev->cnf.rtr_probe_interval)) {
|
neigh->updated + idev->cnf.rtr_probe_interval)) {
|
||||||
@ -649,7 +649,7 @@ static void rt6_probe(struct fib6_nh *fib6_nh)
|
|||||||
if (work)
|
if (work)
|
||||||
__neigh_set_probe_once(neigh);
|
__neigh_set_probe_once(neigh);
|
||||||
}
|
}
|
||||||
write_unlock(&neigh->lock);
|
write_unlock_bh(&neigh->lock);
|
||||||
} else if (time_after(jiffies, last_probe +
|
} else if (time_after(jiffies, last_probe +
|
||||||
idev->cnf.rtr_probe_interval)) {
|
idev->cnf.rtr_probe_interval)) {
|
||||||
work = kmalloc(sizeof(*work), GFP_ATOMIC);
|
work = kmalloc(sizeof(*work), GFP_ATOMIC);
|
||||||
@ -667,7 +667,7 @@ static void rt6_probe(struct fib6_nh *fib6_nh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline void rt6_probe(struct fib6_nh *fib6_nh)
|
static inline void rt6_probe(struct fib6_nh *fib6_nh)
|
||||||
@ -683,7 +683,7 @@ static enum rt6_nud_state rt6_check_neigh(const struct fib6_nh *fib6_nh)
|
|||||||
enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
|
enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
|
||||||
struct neighbour *neigh;
|
struct neighbour *neigh;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock();
|
||||||
neigh = __ipv6_neigh_lookup_noref(fib6_nh->fib_nh_dev,
|
neigh = __ipv6_neigh_lookup_noref(fib6_nh->fib_nh_dev,
|
||||||
&fib6_nh->fib_nh_gw6);
|
&fib6_nh->fib_nh_gw6);
|
||||||
if (neigh) {
|
if (neigh) {
|
||||||
@ -701,7 +701,7 @@ static enum rt6_nud_state rt6_check_neigh(const struct fib6_nh *fib6_nh)
|
|||||||
ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
|
ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
|
||||||
RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
|
RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
|
||||||
}
|
}
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user