Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 932bc4d7 authored by Julian Anastasov's avatar Julian Anastasov Committed by Pablo Neira Ayuso
Browse files

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: default avatarJulian Anastasov <ja@ssi.bg>
Signed-off by: Hans Schillstrom <hans@schillstrom.com>
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSimon Horman <horms@verge.net.au>
parent e5c5d22e
Loading
Loading
Loading
Loading
+34 −1
Original line number Diff line number Diff line
@@ -575,7 +575,40 @@ static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
	skb->_skb_refdst = (unsigned long)dst;
}

extern void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst);
extern void __skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst,
				bool force);

/**
 * skb_dst_set_noref - sets skb dst, hopefully, without taking reference
 * @skb: buffer
 * @dst: dst entry
 *
 * Sets skb dst, assuming a reference was not taken on dst.
 * If dst entry is cached, we do not take reference and dst_release
 * will be avoided by refdst_drop. If dst entry is not cached, we take
 * reference, so that last dst_release can destroy the dst immediately.
 */
static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
{
	__skb_dst_set_noref(skb, dst, false);
}

/**
 * skb_dst_set_noref_force - sets skb dst, without taking reference
 * @skb: buffer
 * @dst: dst entry
 *
 * Sets skb dst, assuming a reference was not taken on dst.
 * No reference is taken and no dst_release will be called. While for
 * cached dsts deferred reclaim is a basic feature, for entries that are
 * not cached it is caller's job to guarantee that last dst_release for
 * provided dst happens when nobody uses it, eg. after a RCU grace period.
 */
static inline void skb_dst_set_noref_force(struct sk_buff *skb,
					   struct dst_entry *dst)
{
	__skb_dst_set_noref(skb, dst, true);
}

/**
 * skb_dst_is_noref - Test if skb dst isn't refcounted
+5 −4
Original line number Diff line number Diff line
@@ -320,27 +320,28 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)
EXPORT_SYMBOL(__dst_destroy_metrics_generic);

/**
 * skb_dst_set_noref - sets skb dst, without a reference
 * __skb_dst_set_noref - sets skb dst, without a reference
 * @skb: buffer
 * @dst: dst entry
 * @force: if force is set, use noref version even for DST_NOCACHE entries
 *
 * Sets skb dst, assuming a reference was not taken on dst
 * skb_dst_drop() should not dst_release() this dst
 */
void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
void __skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst, bool force)
{
	WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
	/* If dst not in cache, we must take a reference, because
	 * dst_release() will destroy dst as soon as its refcount becomes zero
	 */
	if (unlikely(dst->flags & DST_NOCACHE)) {
	if (unlikely((dst->flags & DST_NOCACHE) && !force)) {
		dst_hold(dst);
		skb_dst_set(skb, dst);
	} else {
		skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
	}
}
EXPORT_SYMBOL(skb_dst_set_noref);
EXPORT_SYMBOL(__skb_dst_set_noref);

/* Dirty hack. We did it in 2.2 (in __dst_free),
 * we have _very_ good reasons not to repeat