aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-07-06 02:22:19 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-06 02:22:19 -0400
commitfbd8f1379aeeb3e44a59302a6b2850636130bb2a (patch)
treeaa3c73e765d983f91f6509753c35a019bae19fd8 /net/sched
parentd77fea2eb9206833c7aa1b013044ddeb5225b92c (diff)
net-sched: sch_htb: move hash and sibling list removal to htb_delete
Hash list removal currently happens twice (once in htb_delete, once in htb_destroy_class), which makes it harder to use the dynamically sized class hash without adding special cases for HTB. The reason is that qdisc destruction destroys classes in hierarchical order, which is not necessary if filters are destroyed in a separate iteration during qdisc destruction. Adjust qdisc destruction to follow the same scheme as other hierarchical qdiscs by first performing a filter destruction pass, then destroying all classes in hash order. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/sch_htb.c40
1 files changed, 17 insertions, 23 deletions
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 0284791169c9..d01fe3a1a623 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1226,8 +1226,6 @@ static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl,
1226 1226
1227static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) 1227static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
1228{ 1228{
1229 struct htb_sched *q = qdisc_priv(sch);
1230
1231 if (!cl->level) { 1229 if (!cl->level) {
1232 BUG_TRAP(cl->un.leaf.q); 1230 BUG_TRAP(cl->un.leaf.q);
1233 qdisc_destroy(cl->un.leaf.q); 1231 qdisc_destroy(cl->un.leaf.q);
@@ -1237,21 +1235,6 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
1237 qdisc_put_rtab(cl->ceil); 1235 qdisc_put_rtab(cl->ceil);
1238 1236
1239 tcf_destroy_chain(&cl->filter_list); 1237 tcf_destroy_chain(&cl->filter_list);
1240
1241 while (!list_empty(&cl->children))
1242 htb_destroy_class(sch, list_entry(cl->children.next,
1243 struct htb_class, sibling));
1244
1245 /* note: this delete may happen twice (see htb_delete) */
1246 hlist_del_init(&cl->hlist);
1247 list_del(&cl->sibling);
1248
1249 if (cl->prio_activity)
1250 htb_deactivate(q, cl);
1251
1252 if (cl->cmode != HTB_CAN_SEND)
1253 htb_safe_rb_erase(&cl->pq_node, q->wait_pq + cl->level);
1254
1255 kfree(cl); 1238 kfree(cl);
1256} 1239}
1257 1240
@@ -1259,6 +1242,9 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
1259static void htb_destroy(struct Qdisc *sch) 1242static void htb_destroy(struct Qdisc *sch)
1260{ 1243{
1261 struct htb_sched *q = qdisc_priv(sch); 1244 struct htb_sched *q = qdisc_priv(sch);
1245 struct hlist_node *n, *next;
1246 struct htb_class *cl;
1247 unsigned int i;
1262 1248
1263 qdisc_watchdog_cancel(&q->watchdog); 1249 qdisc_watchdog_cancel(&q->watchdog);
1264 /* This line used to be after htb_destroy_class call below 1250 /* This line used to be after htb_destroy_class call below
@@ -1267,10 +1253,14 @@ static void htb_destroy(struct Qdisc *sch)
1267 unbind_filter on it (without Oops). */ 1253 unbind_filter on it (without Oops). */
1268 tcf_destroy_chain(&q->filter_list); 1254 tcf_destroy_chain(&q->filter_list);
1269 1255
1270 while (!list_empty(&q->root)) 1256 for (i = 0; i < HTB_HSIZE; i++) {
1271 htb_destroy_class(sch, list_entry(q->root.next, 1257 hlist_for_each_entry(cl, n, q->hash + i, hlist)
1272 struct htb_class, sibling)); 1258 tcf_destroy_chain(&cl->filter_list);
1273 1259 }
1260 for (i = 0; i < HTB_HSIZE; i++) {
1261 hlist_for_each_entry_safe(cl, n, next, q->hash + i, hlist)
1262 htb_destroy_class(sch, cl);
1263 }
1274 __skb_queue_purge(&q->direct_queue); 1264 __skb_queue_purge(&q->direct_queue);
1275} 1265}
1276 1266
@@ -1302,12 +1292,16 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
1302 qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen); 1292 qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen);
1303 } 1293 }
1304 1294
1305 /* delete from hash and active; remainder in destroy_class */ 1295 /* delete from hash, sibling list and active */
1306 hlist_del_init(&cl->hlist); 1296 hlist_del(&cl->hlist);
1297 list_del(&cl->sibling);
1307 1298
1308 if (cl->prio_activity) 1299 if (cl->prio_activity)
1309 htb_deactivate(q, cl); 1300 htb_deactivate(q, cl);
1310 1301
1302 if (cl->cmode != HTB_CAN_SEND)
1303 htb_safe_rb_erase(&cl->pq_node, q->wait_pq + cl->level);
1304
1311 if (last_child) 1305 if (last_child)
1312 htb_parent_to_leaf(q, cl, new_q); 1306 htb_parent_to_leaf(q, cl, new_q);
1313 1307