diff options
Diffstat (limited to 'net/sched/sch_multiq.c')
-rw-r--r-- | net/sched/sch_multiq.c | 82 |
1 files changed, 39 insertions, 43 deletions
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 915f3149dde2..7e151861794b 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c | |||
@@ -92,40 +92,6 @@ multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
92 | return ret; | 92 | return ret; |
93 | } | 93 | } |
94 | 94 | ||
95 | |||
96 | static int | ||
97 | multiq_requeue(struct sk_buff *skb, struct Qdisc *sch) | ||
98 | { | ||
99 | struct Qdisc *qdisc; | ||
100 | struct multiq_sched_data *q = qdisc_priv(sch); | ||
101 | int ret; | ||
102 | |||
103 | qdisc = multiq_classify(skb, sch, &ret); | ||
104 | #ifdef CONFIG_NET_CLS_ACT | ||
105 | if (qdisc == NULL) { | ||
106 | if (ret & __NET_XMIT_BYPASS) | ||
107 | sch->qstats.drops++; | ||
108 | kfree_skb(skb); | ||
109 | return ret; | ||
110 | } | ||
111 | #endif | ||
112 | |||
113 | ret = qdisc->ops->requeue(skb, qdisc); | ||
114 | if (ret == NET_XMIT_SUCCESS) { | ||
115 | sch->q.qlen++; | ||
116 | sch->qstats.requeues++; | ||
117 | if (q->curband) | ||
118 | q->curband--; | ||
119 | else | ||
120 | q->curband = q->bands - 1; | ||
121 | return NET_XMIT_SUCCESS; | ||
122 | } | ||
123 | if (net_xmit_drop_count(ret)) | ||
124 | sch->qstats.drops++; | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | |||
129 | static struct sk_buff *multiq_dequeue(struct Qdisc *sch) | 95 | static struct sk_buff *multiq_dequeue(struct Qdisc *sch) |
130 | { | 96 | { |
131 | struct multiq_sched_data *q = qdisc_priv(sch); | 97 | struct multiq_sched_data *q = qdisc_priv(sch); |
@@ -140,7 +106,7 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch) | |||
140 | q->curband = 0; | 106 | q->curband = 0; |
141 | 107 | ||
142 | /* Check that target subqueue is available before | 108 | /* Check that target subqueue is available before |
143 | * pulling an skb to avoid excessive requeues | 109 | * pulling an skb to avoid head-of-line blocking. |
144 | */ | 110 | */ |
145 | if (!__netif_subqueue_stopped(qdisc_dev(sch), q->curband)) { | 111 | if (!__netif_subqueue_stopped(qdisc_dev(sch), q->curband)) { |
146 | qdisc = q->queues[q->curband]; | 112 | qdisc = q->queues[q->curband]; |
@@ -155,6 +121,34 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch) | |||
155 | 121 | ||
156 | } | 122 | } |
157 | 123 | ||
124 | static struct sk_buff *multiq_peek(struct Qdisc *sch) | ||
125 | { | ||
126 | struct multiq_sched_data *q = qdisc_priv(sch); | ||
127 | unsigned int curband = q->curband; | ||
128 | struct Qdisc *qdisc; | ||
129 | struct sk_buff *skb; | ||
130 | int band; | ||
131 | |||
132 | for (band = 0; band < q->bands; band++) { | ||
133 | /* cycle through bands to ensure fairness */ | ||
134 | curband++; | ||
135 | if (curband >= q->bands) | ||
136 | curband = 0; | ||
137 | |||
138 | /* Check that target subqueue is available before | ||
139 | * pulling an skb to avoid head-of-line blocking. | ||
140 | */ | ||
141 | if (!__netif_subqueue_stopped(qdisc_dev(sch), curband)) { | ||
142 | qdisc = q->queues[curband]; | ||
143 | skb = qdisc->ops->peek(qdisc); | ||
144 | if (skb) | ||
145 | return skb; | ||
146 | } | ||
147 | } | ||
148 | return NULL; | ||
149 | |||
150 | } | ||
151 | |||
158 | static unsigned int multiq_drop(struct Qdisc *sch) | 152 | static unsigned int multiq_drop(struct Qdisc *sch) |
159 | { | 153 | { |
160 | struct multiq_sched_data *q = qdisc_priv(sch); | 154 | struct multiq_sched_data *q = qdisc_priv(sch); |
@@ -220,7 +214,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) | |||
220 | q->bands = qopt->bands; | 214 | q->bands = qopt->bands; |
221 | for (i = q->bands; i < q->max_bands; i++) { | 215 | for (i = q->bands; i < q->max_bands; i++) { |
222 | if (q->queues[i] != &noop_qdisc) { | 216 | if (q->queues[i] != &noop_qdisc) { |
223 | struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc); | 217 | struct Qdisc *child = q->queues[i]; |
218 | q->queues[i] = &noop_qdisc; | ||
224 | qdisc_tree_decrease_qlen(child, child->q.qlen); | 219 | qdisc_tree_decrease_qlen(child, child->q.qlen); |
225 | qdisc_destroy(child); | 220 | qdisc_destroy(child); |
226 | } | 221 | } |
@@ -230,7 +225,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) | |||
230 | 225 | ||
231 | for (i = 0; i < q->bands; i++) { | 226 | for (i = 0; i < q->bands; i++) { |
232 | if (q->queues[i] == &noop_qdisc) { | 227 | if (q->queues[i] == &noop_qdisc) { |
233 | struct Qdisc *child; | 228 | struct Qdisc *child, *old; |
234 | child = qdisc_create_dflt(qdisc_dev(sch), | 229 | child = qdisc_create_dflt(qdisc_dev(sch), |
235 | sch->dev_queue, | 230 | sch->dev_queue, |
236 | &pfifo_qdisc_ops, | 231 | &pfifo_qdisc_ops, |
@@ -238,12 +233,13 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) | |||
238 | i + 1)); | 233 | i + 1)); |
239 | if (child) { | 234 | if (child) { |
240 | sch_tree_lock(sch); | 235 | sch_tree_lock(sch); |
241 | child = xchg(&q->queues[i], child); | 236 | old = q->queues[i]; |
237 | q->queues[i] = child; | ||
242 | 238 | ||
243 | if (child != &noop_qdisc) { | 239 | if (old != &noop_qdisc) { |
244 | qdisc_tree_decrease_qlen(child, | 240 | qdisc_tree_decrease_qlen(old, |
245 | child->q.qlen); | 241 | old->q.qlen); |
246 | qdisc_destroy(child); | 242 | qdisc_destroy(old); |
247 | } | 243 | } |
248 | sch_tree_unlock(sch); | 244 | sch_tree_unlock(sch); |
249 | } | 245 | } |
@@ -451,7 +447,7 @@ static struct Qdisc_ops multiq_qdisc_ops __read_mostly = { | |||
451 | .priv_size = sizeof(struct multiq_sched_data), | 447 | .priv_size = sizeof(struct multiq_sched_data), |
452 | .enqueue = multiq_enqueue, | 448 | .enqueue = multiq_enqueue, |
453 | .dequeue = multiq_dequeue, | 449 | .dequeue = multiq_dequeue, |
454 | .requeue = multiq_requeue, | 450 | .peek = multiq_peek, |
455 | .drop = multiq_drop, | 451 | .drop = multiq_drop, |
456 | .init = multiq_init, | 452 | .init = multiq_init, |
457 | .reset = multiq_reset, | 453 | .reset = multiq_reset, |