diff options
-rw-r--r-- | Documentation/networking/multiqueue.txt | 14 | ||||
-rw-r--r-- | net/sched/sch_multiq.c | 13 |
2 files changed, 16 insertions, 11 deletions
diff --git a/Documentation/networking/multiqueue.txt b/Documentation/networking/multiqueue.txt index 8c2b06b77f61..4caa0e314cc2 100644 --- a/Documentation/networking/multiqueue.txt +++ b/Documentation/networking/multiqueue.txt | |||
@@ -29,15 +29,15 @@ Section 2: Qdisc support for multiqueue devices | |||
29 | 29 | ||
30 | ----------------------------------------------- | 30 | ----------------------------------------------- |
31 | 31 | ||
32 | Currently two qdiscs support multiqueue devices. The first is the default | 32 | Currently two qdiscs are optimized for multiqueue devices. The first is the |
33 | pfifo_fast qdisc. This qdisc supports one qdisc per hardware queue. A new | 33 | default pfifo_fast qdisc. This qdisc supports one qdisc per hardware queue. |
34 | round-robin qdisc, sch_multiq also supports multiple hardware queues. The | 34 | A new round-robin qdisc, sch_multiq also supports multiple hardware queues. The |
35 | qdisc is responsible for classifying the skb's and then directing the skb's to | 35 | qdisc is responsible for classifying the skb's and then directing the skb's to |
36 | bands and queues based on the value in skb->queue_mapping. Use this field in | 36 | bands and queues based on the value in skb->queue_mapping. Use this field in |
37 | the base driver to determine which queue to send the skb to. | 37 | the base driver to determine which queue to send the skb to. |
38 | 38 | ||
39 | sch_multiq has been added for hardware that wishes to avoid unnecessary | 39 | sch_multiq has been added for hardware that wishes to avoid head-of-line |
40 | requeuing. It will cycle though the bands and verify that the hardware queue | 40 | blocking. It will cycle though the bands and verify that the hardware queue |
41 | associated with the band is not stopped prior to dequeuing a packet. | 41 | associated with the band is not stopped prior to dequeuing a packet. |
42 | 42 | ||
43 | On qdisc load, the number of bands is based on the number of queues on the | 43 | On qdisc load, the number of bands is based on the number of queues on the |
@@ -63,8 +63,8 @@ band 1 => queue 1 | |||
63 | band 2 => queue 2 | 63 | band 2 => queue 2 |
64 | band 3 => queue 3 | 64 | band 3 => queue 3 |
65 | 65 | ||
66 | Traffic will begin flowing through each queue if your base device has either | 66 | Traffic will begin flowing through each queue based on either the simple_tx_hash |
67 | the default simple_tx_hash or a custom netdev->select_queue() defined. | 67 | function or based on netdev->select_queue() if you have it defined. |
68 | 68 | ||
69 | The behavior of tc filters remains the same. However a new tc action, | 69 | The behavior of tc filters remains the same. However a new tc action, |
70 | skbedit, has been added. Assuming you wanted to route all traffic to a | 70 | skbedit, has been added. Assuming you wanted to route all traffic to a |
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 49a8b67ed3b8..5d9cd68e91d1 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c | |||
@@ -214,8 +214,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) | |||
214 | sch_tree_lock(sch); | 214 | sch_tree_lock(sch); |
215 | q->bands = qopt->bands; | 215 | q->bands = qopt->bands; |
216 | for (i = q->bands; i < q->max_bands; i++) { | 216 | for (i = q->bands; i < q->max_bands; i++) { |
217 | struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc); | 217 | if (q->queues[i] != &noop_qdisc) { |
218 | if (child != &noop_qdisc) { | 218 | struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc); |
219 | qdisc_tree_decrease_qlen(child, child->q.qlen); | 219 | qdisc_tree_decrease_qlen(child, child->q.qlen); |
220 | qdisc_destroy(child); | 220 | qdisc_destroy(child); |
221 | } | 221 | } |
@@ -250,7 +250,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) | |||
250 | static int multiq_init(struct Qdisc *sch, struct nlattr *opt) | 250 | static int multiq_init(struct Qdisc *sch, struct nlattr *opt) |
251 | { | 251 | { |
252 | struct multiq_sched_data *q = qdisc_priv(sch); | 252 | struct multiq_sched_data *q = qdisc_priv(sch); |
253 | int i; | 253 | int i, err; |
254 | 254 | ||
255 | q->queues = NULL; | 255 | q->queues = NULL; |
256 | 256 | ||
@@ -265,7 +265,12 @@ static int multiq_init(struct Qdisc *sch, struct nlattr *opt) | |||
265 | for (i = 0; i < q->max_bands; i++) | 265 | for (i = 0; i < q->max_bands; i++) |
266 | q->queues[i] = &noop_qdisc; | 266 | q->queues[i] = &noop_qdisc; |
267 | 267 | ||
268 | return multiq_tune(sch, opt); | 268 | err = multiq_tune(sch,opt); |
269 | |||
270 | if (err) | ||
271 | kfree(q->queues); | ||
272 | |||
273 | return err; | ||
269 | } | 274 | } |
270 | 275 | ||
271 | static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb) | 276 | static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb) |