Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 215373
b: refs/heads/master
c: 27b75c9
h: refs/heads/master
i:
  215371: 6b78189
v: v3
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Oct 20, 2010
1 parent 875cadc commit dcb66d9
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 20 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e6484930d7c73d324bccda7d43d131088da697b9
refs/heads/master: 27b75c95f10d249574d9c4cb9dab878107faede8
14 changes: 1 addition & 13 deletions trunk/include/linux/skbuff.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,19 +460,7 @@ static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
skb->_skb_refdst = (unsigned long)dst;
}

/**
* skb_dst_set_noref - sets skb dst, without a reference
* @skb: buffer
* @dst: dst entry
*
* Sets skb dst, assuming a reference was not taken on dst
* skb_dst_drop() should not dst_release() this dst
*/
static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
{
WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
}
extern void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst);

/**
* skb_dst_is_noref - Test if skb dst isnt refcounted
Expand Down
29 changes: 28 additions & 1 deletion trunk/net/core/dst.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,13 +271,40 @@ void dst_release(struct dst_entry *dst)
if (dst) {
int newrefcnt;

smp_mb__before_atomic_dec();
newrefcnt = atomic_dec_return(&dst->__refcnt);
WARN_ON(newrefcnt < 0);
if (unlikely(dst->flags & DST_NOCACHE) && !newrefcnt) {
dst = dst_destroy(dst);
if (dst)
__dst_free(dst);
}
}
}
EXPORT_SYMBOL(dst_release);

/**
* skb_dst_set_noref - sets skb dst, without a reference
* @skb: buffer
* @dst: dst entry
*
* 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)
{
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)) {
dst_hold(dst);
skb_dst_set(skb, dst);
} else {
skb->_skb_refdst = (unsigned long)dst | SKB_DST_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
* this mistake in 2.3, but we have no choice
Expand Down
9 changes: 4 additions & 5 deletions trunk/net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -1105,9 +1105,9 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt,
* Note that we do rt_free on this new route entry, so that
* once its refcount hits zero, we are still able to reap it
* (Thanks Alexey)
* Note also the rt_free uses call_rcu. We don't actually
* need rcu protection here, this is just our path to get
* on the route gc list.
* Note: To avoid expensive rcu stuff for this uncached dst,
* we set DST_NOCACHE so that dst_release() can free dst without
* waiting a grace period.
*/

rt->dst.flags |= DST_NOCACHE;
Expand All @@ -1117,12 +1117,11 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt,
if (net_ratelimit())
printk(KERN_WARNING
"Neighbour table failure & not caching routes.\n");
rt_drop(rt);
ip_rt_put(rt);
return err;
}
}

rt_free(rt);
goto skip_hashing;
}

Expand Down

0 comments on commit dcb66d9

Please sign in to comment.