diff options
author | Julian Anastasov <ja@ssi.bg> | 2013-03-21 05:57:58 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-04-01 18:22:53 -0400 |
commit | 932bc4d7a53ba418de67fdab533248df5b36c752 (patch) | |
tree | 19747cdef824180014d98baf8959757d0bae1198 | |
parent | e5c5d22e8dcf7c2d430336cbf8e180bd38e8daf1 (diff) |
net: add skb_dst_set_noref_force
Rename skb_dst_set_noref to __skb_dst_set_noref and
add force flag as suggested by David Miller. The new wrapper
skb_dst_set_noref_force will force dst entries that are not
cached to be attached as skb dst without taking reference
as long as provided dst is reclaimed after RCU grace period.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off by: Hans Schillstrom <hans@schillstrom.com>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r-- | include/linux/skbuff.h | 35 | ||||
-rw-r--r-- | net/core/dst.c | 9 |
2 files changed, 39 insertions, 5 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 878e0ee81068..364e2440a7ee 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -575,7 +575,40 @@ static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst) | |||
575 | skb->_skb_refdst = (unsigned long)dst; | 575 | skb->_skb_refdst = (unsigned long)dst; |
576 | } | 576 | } |
577 | 577 | ||
578 | extern void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst); | 578 | extern void __skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst, |
579 | bool force); | ||
580 | |||
581 | /** | ||
582 | * skb_dst_set_noref - sets skb dst, hopefully, without taking reference | ||
583 | * @skb: buffer | ||
584 | * @dst: dst entry | ||
585 | * | ||
586 | * Sets skb dst, assuming a reference was not taken on dst. | ||
587 | * If dst entry is cached, we do not take reference and dst_release | ||
588 | * will be avoided by refdst_drop. If dst entry is not cached, we take | ||
589 | * reference, so that last dst_release can destroy the dst immediately. | ||
590 | */ | ||
591 | static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst) | ||
592 | { | ||
593 | __skb_dst_set_noref(skb, dst, false); | ||
594 | } | ||
595 | |||
596 | /** | ||
597 | * skb_dst_set_noref_force - sets skb dst, without taking reference | ||
598 | * @skb: buffer | ||
599 | * @dst: dst entry | ||
600 | * | ||
601 | * Sets skb dst, assuming a reference was not taken on dst. | ||
602 | * No reference is taken and no dst_release will be called. While for | ||
603 | * cached dsts deferred reclaim is a basic feature, for entries that are | ||
604 | * not cached it is caller's job to guarantee that last dst_release for | ||
605 | * provided dst happens when nobody uses it, eg. after a RCU grace period. | ||
606 | */ | ||
607 | static inline void skb_dst_set_noref_force(struct sk_buff *skb, | ||
608 | struct dst_entry *dst) | ||
609 | { | ||
610 | __skb_dst_set_noref(skb, dst, true); | ||
611 | } | ||
579 | 612 | ||
580 | /** | 613 | /** |
581 | * skb_dst_is_noref - Test if skb dst isn't refcounted | 614 | * skb_dst_is_noref - Test if skb dst isn't refcounted |
diff --git a/net/core/dst.c b/net/core/dst.c index 35fd12f1a69c..df9cc810ec8e 100644 --- a/net/core/dst.c +++ b/net/core/dst.c | |||
@@ -320,27 +320,28 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old) | |||
320 | EXPORT_SYMBOL(__dst_destroy_metrics_generic); | 320 | EXPORT_SYMBOL(__dst_destroy_metrics_generic); |
321 | 321 | ||
322 | /** | 322 | /** |
323 | * skb_dst_set_noref - sets skb dst, without a reference | 323 | * __skb_dst_set_noref - sets skb dst, without a reference |
324 | * @skb: buffer | 324 | * @skb: buffer |
325 | * @dst: dst entry | 325 | * @dst: dst entry |
326 | * @force: if force is set, use noref version even for DST_NOCACHE entries | ||
326 | * | 327 | * |
327 | * Sets skb dst, assuming a reference was not taken on dst | 328 | * Sets skb dst, assuming a reference was not taken on dst |
328 | * skb_dst_drop() should not dst_release() this dst | 329 | * skb_dst_drop() should not dst_release() this dst |
329 | */ | 330 | */ |
330 | void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst) | 331 | void __skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst, bool force) |
331 | { | 332 | { |
332 | WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); | 333 | WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); |
333 | /* If dst not in cache, we must take a reference, because | 334 | /* If dst not in cache, we must take a reference, because |
334 | * dst_release() will destroy dst as soon as its refcount becomes zero | 335 | * dst_release() will destroy dst as soon as its refcount becomes zero |
335 | */ | 336 | */ |
336 | if (unlikely(dst->flags & DST_NOCACHE)) { | 337 | if (unlikely((dst->flags & DST_NOCACHE) && !force)) { |
337 | dst_hold(dst); | 338 | dst_hold(dst); |
338 | skb_dst_set(skb, dst); | 339 | skb_dst_set(skb, dst); |
339 | } else { | 340 | } else { |
340 | skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF; | 341 | skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF; |
341 | } | 342 | } |
342 | } | 343 | } |
343 | EXPORT_SYMBOL(skb_dst_set_noref); | 344 | EXPORT_SYMBOL(__skb_dst_set_noref); |
344 | 345 | ||
345 | /* Dirty hack. We did it in 2.2 (in __dst_free), | 346 | /* Dirty hack. We did it in 2.2 (in __dst_free), |
346 | * we have _very_ good reasons not to repeat | 347 | * we have _very_ good reasons not to repeat |