Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Hannes Frederic Sowa and committed by
David S. Miller
dbfc4fb7 c19be735

+4 -47
+2 -21
include/linux/skbuff.h
··· 717 717 skb->_skb_refdst = (unsigned long)dst; 718 718 } 719 719 720 - void __skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst, 721 - bool force); 722 - 723 720 /** 724 721 * skb_dst_set_noref - sets skb dst, hopefully, without taking reference 725 722 * @skb: buffer ··· 729 732 */ 730 733 static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst) 731 734 { 732 - __skb_dst_set_noref(skb, dst, false); 733 - } 734 - 735 - /** 736 - * skb_dst_set_noref_force - sets skb dst, without taking reference 737 - * @skb: buffer 738 - * @dst: dst entry 739 - * 740 - * Sets skb dst, assuming a reference was not taken on dst. 741 - * No reference is taken and no dst_release will be called. While for 742 - * cached dsts deferred reclaim is a basic feature, for entries that are 743 - * not cached it is caller's job to guarantee that last dst_release for 744 - * provided dst happens when nobody uses it, eg. after a RCU grace period. 745 - */ 746 - static inline void skb_dst_set_noref_force(struct sk_buff *skb, 747 - struct dst_entry *dst) 748 - { 749 - __skb_dst_set_noref(skb, dst, true); 735 + WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); 736 + skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF; 750 737 } 751 738 752 739 /**
-24
net/core/dst.c
··· 327 327 } 328 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 330 /* Dirty hack. We did it in 2.2 (in __dst_free), 355 331 * we have _very_ good reasons not to repeat 356 332 * this mistake in 2.3, but we have no choice
+2 -2
net/netfilter/ipvs/ip_vs_xmit.c
··· 343 343 skb_dst_drop(skb); 344 344 if (noref) { 345 345 if (!local) 346 - skb_dst_set_noref_force(skb, &rt->dst); 346 + skb_dst_set_noref(skb, &rt->dst); 347 347 else 348 348 skb_dst_set(skb, dst_clone(&rt->dst)); 349 349 } else ··· 487 487 skb_dst_drop(skb); 488 488 if (noref) { 489 489 if (!local) 490 - skb_dst_set_noref_force(skb, &rt->dst); 490 + skb_dst_set_noref(skb, &rt->dst); 491 491 else 492 492 skb_dst_set(skb, dst_clone(&rt->dst)); 493 493 } else