diff options
| author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2014-12-06 13:19:42 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-12-09 16:08:17 -0500 |
| commit | dbfc4fb7d578d4f224faa6b60deb40804dfdc1b1 (patch) | |
| tree | f474094df71aa758eab9799a7809f6f07712071e /net | |
| parent | c19be735c99e221e00157c6db475fe007c056638 (diff) | |
dst: no need to take reference on DST_NOCACHE dsts
Since commit f8864972126899 ("ipv4: fix dst race in sk_dst_get()")
DST_NOCACHE dst_entries get freed by RCU. So there is no need to get a
reference on them when we are in rcu protected sections.
Cc: Eric Dumazet <edumazet@google.com>
Cc: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Reviewed-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
| -rw-r--r-- | net/core/dst.c | 24 | ||||
| -rw-r--r-- | net/netfilter/ipvs/ip_vs_xmit.c | 4 |
2 files changed, 2 insertions, 26 deletions
diff --git a/net/core/dst.c b/net/core/dst.c index a028409ee438..e956ce6d1378 100644 --- a/net/core/dst.c +++ b/net/core/dst.c | |||
| @@ -327,30 +327,6 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old) | |||
| 327 | } | 327 | } |
| 328 | EXPORT_SYMBOL(__dst_destroy_metrics_generic); | 328 | EXPORT_SYMBOL(__dst_destroy_metrics_generic); |
| 329 | 329 | ||
| 330 | /** | ||
| 331 | * __skb_dst_set_noref - sets skb dst, without a reference | ||
| 332 | * @skb: buffer | ||
| 333 | * @dst: dst entry | ||
| 334 | * @force: if force is set, use noref version even for DST_NOCACHE entries | ||
| 335 | * | ||
| 336 | * Sets skb dst, assuming a reference was not taken on dst | ||
| 337 | * skb_dst_drop() should not dst_release() this dst | ||
| 338 | */ | ||
| 339 | void __skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst, bool force) | ||
| 340 | { | ||
| 341 | WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); | ||
| 342 | /* If dst not in cache, we must take a reference, because | ||
| 343 | * dst_release() will destroy dst as soon as its refcount becomes zero | ||
| 344 | */ | ||
| 345 | if (unlikely((dst->flags & DST_NOCACHE) && !force)) { | ||
| 346 | dst_hold(dst); | ||
| 347 | skb_dst_set(skb, dst); | ||
| 348 | } else { | ||
| 349 | skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | EXPORT_SYMBOL(__skb_dst_set_noref); | ||
| 353 | |||
| 354 | /* Dirty hack. We did it in 2.2 (in __dst_free), | 330 | /* Dirty hack. We did it in 2.2 (in __dst_free), |
| 355 | * we have _very_ good reasons not to repeat | 331 | * we have _very_ good reasons not to repeat |
| 356 | * this mistake in 2.3, but we have no choice | 332 | * this mistake in 2.3, but we have no choice |
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 1f933136155a..3aedbda7658a 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
| @@ -343,7 +343,7 @@ __ip_vs_get_out_rt(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest, | |||
| 343 | skb_dst_drop(skb); | 343 | skb_dst_drop(skb); |
| 344 | if (noref) { | 344 | if (noref) { |
| 345 | if (!local) | 345 | if (!local) |
| 346 | skb_dst_set_noref_force(skb, &rt->dst); | 346 | skb_dst_set_noref(skb, &rt->dst); |
| 347 | else | 347 | else |
| 348 | skb_dst_set(skb, dst_clone(&rt->dst)); | 348 | skb_dst_set(skb, dst_clone(&rt->dst)); |
| 349 | } else | 349 | } else |
| @@ -487,7 +487,7 @@ __ip_vs_get_out_rt_v6(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest, | |||
| 487 | skb_dst_drop(skb); | 487 | skb_dst_drop(skb); |
| 488 | if (noref) { | 488 | if (noref) { |
| 489 | if (!local) | 489 | if (!local) |
| 490 | skb_dst_set_noref_force(skb, &rt->dst); | 490 | skb_dst_set_noref(skb, &rt->dst); |
| 491 | else | 491 | else |
| 492 | skb_dst_set(skb, dst_clone(&rt->dst)); | 492 | skb_dst_set(skb, dst_clone(&rt->dst)); |
| 493 | } else | 493 | } else |
