diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-05-11 19:19:48 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-17 20:18:50 -0400 |
commit | 7fee226ad2397b635e2fd565a59ca3ae08a164cd (patch) | |
tree | 0bcd26150ad74ec1a237109de87a3d214a07fc22 /net/sched | |
parent | ebda37c27d0c768947e9b058332d7ea798210cf8 (diff) |
net: add a noref bit on skb dst
Use low order bit of skb->_skb_dst to tell dst is not refcounted.
Change _skb_dst to _skb_refdst to make sure all uses are catched.
skb_dst() returns the dst, regardless of noref bit set or not, but
with a lockdep check to make sure a noref dst is not given if current
user is not rcu protected.
New skb_dst_set_noref() helper to set an notrefcounted dst on a skb.
(with lockdep check)
skb_dst_drop() drops a reference only if skb dst was refcounted.
skb_dst_force() helper is used to force a refcount on dst, when skb
is queued and not anymore RCU protected.
Use skb_dst_force() in __sk_add_backlog(), __dev_xmit_skb() if
!IFF_XMIT_DST_RELEASE or skb enqueued on qdisc queue, in
sock_queue_rcv_skb(), in __nf_queue().
Use skb_dst_force() in dev_requeue_skb().
Note: dst_use_noref() still dirties dst, we might transform it
later to do one dirtying per jiffies.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_generic.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index a969b111bd76..a63029ef3edd 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <net/pkt_sched.h> | 28 | #include <net/pkt_sched.h> |
29 | #include <net/dst.h> | ||
29 | 30 | ||
30 | /* Main transmission queue. */ | 31 | /* Main transmission queue. */ |
31 | 32 | ||
@@ -40,6 +41,7 @@ | |||
40 | 41 | ||
41 | static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) | 42 | static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) |
42 | { | 43 | { |
44 | skb_dst_force(skb); | ||
43 | q->gso_skb = skb; | 45 | q->gso_skb = skb; |
44 | q->qstats.requeues++; | 46 | q->qstats.requeues++; |
45 | q->q.qlen++; /* it's still part of the queue */ | 47 | q->q.qlen++; /* it's still part of the queue */ |
@@ -179,7 +181,7 @@ static inline int qdisc_restart(struct Qdisc *q) | |||
179 | skb = dequeue_skb(q); | 181 | skb = dequeue_skb(q); |
180 | if (unlikely(!skb)) | 182 | if (unlikely(!skb)) |
181 | return 0; | 183 | return 0; |
182 | 184 | WARN_ON_ONCE(skb_dst_is_noref(skb)); | |
183 | root_lock = qdisc_lock(q); | 185 | root_lock = qdisc_lock(q); |
184 | dev = qdisc_dev(q); | 186 | dev = qdisc_dev(q); |
185 | txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); | 187 | txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); |