diff options
Diffstat (limited to 'net/sched/sch_generic.c')
-rw-r--r-- | net/sched/sch_generic.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index ec0a0839ce51..31f6b614b59b 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -44,23 +44,29 @@ static inline int qdisc_qlen(struct Qdisc *q) | |||
44 | 44 | ||
45 | static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) | 45 | static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) |
46 | { | 46 | { |
47 | if (unlikely(skb->next)) | 47 | q->gso_skb = skb; |
48 | q->gso_skb = skb; | ||
49 | else | ||
50 | q->ops->requeue(skb, q); | ||
51 | |||
52 | __netif_schedule(q); | 48 | __netif_schedule(q); |
49 | |||
53 | return 0; | 50 | return 0; |
54 | } | 51 | } |
55 | 52 | ||
56 | static inline struct sk_buff *dequeue_skb(struct Qdisc *q) | 53 | static inline struct sk_buff *dequeue_skb(struct Qdisc *q) |
57 | { | 54 | { |
58 | struct sk_buff *skb; | 55 | struct sk_buff *skb = q->gso_skb; |
59 | 56 | ||
60 | if ((skb = q->gso_skb)) | 57 | if (unlikely(skb)) { |
61 | q->gso_skb = NULL; | 58 | struct net_device *dev = qdisc_dev(q); |
62 | else | 59 | struct netdev_queue *txq; |
60 | |||
61 | /* check the reason of requeuing without tx lock first */ | ||
62 | txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); | ||
63 | if (!netif_tx_queue_stopped(txq) && !netif_tx_queue_frozen(txq)) | ||
64 | q->gso_skb = NULL; | ||
65 | else | ||
66 | skb = NULL; | ||
67 | } else { | ||
63 | skb = q->dequeue(q); | 68 | skb = q->dequeue(q); |
69 | } | ||
64 | 70 | ||
65 | return skb; | 71 | return skb; |
66 | } | 72 | } |
@@ -327,6 +333,7 @@ struct Qdisc noop_qdisc = { | |||
327 | .flags = TCQ_F_BUILTIN, | 333 | .flags = TCQ_F_BUILTIN, |
328 | .ops = &noop_qdisc_ops, | 334 | .ops = &noop_qdisc_ops, |
329 | .list = LIST_HEAD_INIT(noop_qdisc.list), | 335 | .list = LIST_HEAD_INIT(noop_qdisc.list), |
336 | .requeue.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), | ||
330 | .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), | 337 | .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), |
331 | .dev_queue = &noop_netdev_queue, | 338 | .dev_queue = &noop_netdev_queue, |
332 | }; | 339 | }; |
@@ -352,6 +359,7 @@ static struct Qdisc noqueue_qdisc = { | |||
352 | .flags = TCQ_F_BUILTIN, | 359 | .flags = TCQ_F_BUILTIN, |
353 | .ops = &noqueue_qdisc_ops, | 360 | .ops = &noqueue_qdisc_ops, |
354 | .list = LIST_HEAD_INIT(noqueue_qdisc.list), | 361 | .list = LIST_HEAD_INIT(noqueue_qdisc.list), |
362 | .requeue.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), | ||
355 | .q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), | 363 | .q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), |
356 | .dev_queue = &noqueue_netdev_queue, | 364 | .dev_queue = &noqueue_netdev_queue, |
357 | }; | 365 | }; |
@@ -472,6 +480,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, | |||
472 | sch->padded = (char *) sch - (char *) p; | 480 | sch->padded = (char *) sch - (char *) p; |
473 | 481 | ||
474 | INIT_LIST_HEAD(&sch->list); | 482 | INIT_LIST_HEAD(&sch->list); |
483 | skb_queue_head_init(&sch->requeue); | ||
475 | skb_queue_head_init(&sch->q); | 484 | skb_queue_head_init(&sch->q); |
476 | sch->ops = ops; | 485 | sch->ops = ops; |
477 | sch->enqueue = ops->enqueue; | 486 | sch->enqueue = ops->enqueue; |
@@ -540,6 +549,7 @@ void qdisc_destroy(struct Qdisc *qdisc) | |||
540 | dev_put(qdisc_dev(qdisc)); | 549 | dev_put(qdisc_dev(qdisc)); |
541 | 550 | ||
542 | kfree_skb(qdisc->gso_skb); | 551 | kfree_skb(qdisc->gso_skb); |
552 | __skb_queue_purge(&qdisc->requeue); | ||
543 | 553 | ||
544 | kfree((char *) qdisc - qdisc->padded); | 554 | kfree((char *) qdisc - qdisc->padded); |
545 | } | 555 | } |