diff options
author | Patrick McHardy <kaber@trash.net> | 2008-07-06 02:22:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-06 02:22:35 -0400 |
commit | f4c1f3e0c59be0e6566d9c00b1d8b204ffb861a2 (patch) | |
tree | 6dffffa3a06bf252fd23c681b19063693174bdb8 /net | |
parent | fbd8f1379aeeb3e44a59302a6b2850636130bb2a (diff) |
net-sched: sch_htb: use dynamic class hash helpers
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/sched/sch_htb.c | 100 |
1 files changed, 42 insertions, 58 deletions
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index d01fe3a1a623..e7461a17d71e 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -51,7 +51,6 @@ | |||
51 | one less than their parent. | 51 | one less than their parent. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | #define HTB_HSIZE 16 /* classid hash size */ | ||
55 | static int htb_hysteresis __read_mostly = 0; /* whether to use mode hysteresis for speedup */ | 54 | static int htb_hysteresis __read_mostly = 0; /* whether to use mode hysteresis for speedup */ |
56 | #define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ | 55 | #define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ |
57 | 56 | ||
@@ -72,8 +71,8 @@ enum htb_cmode { | |||
72 | 71 | ||
73 | /* interior & leaf nodes; props specific to leaves are marked L: */ | 72 | /* interior & leaf nodes; props specific to leaves are marked L: */ |
74 | struct htb_class { | 73 | struct htb_class { |
74 | struct Qdisc_class_common common; | ||
75 | /* general class parameters */ | 75 | /* general class parameters */ |
76 | u32 classid; | ||
77 | struct gnet_stats_basic bstats; | 76 | struct gnet_stats_basic bstats; |
78 | struct gnet_stats_queue qstats; | 77 | struct gnet_stats_queue qstats; |
79 | struct gnet_stats_rate_est rate_est; | 78 | struct gnet_stats_rate_est rate_est; |
@@ -83,7 +82,6 @@ struct htb_class { | |||
83 | /* topology */ | 82 | /* topology */ |
84 | int level; /* our level (see above) */ | 83 | int level; /* our level (see above) */ |
85 | struct htb_class *parent; /* parent class */ | 84 | struct htb_class *parent; /* parent class */ |
86 | struct hlist_node hlist; /* classid hash list item */ | ||
87 | struct list_head sibling; /* sibling list item */ | 85 | struct list_head sibling; /* sibling list item */ |
88 | struct list_head children; /* children list */ | 86 | struct list_head children; /* children list */ |
89 | 87 | ||
@@ -141,7 +139,7 @@ static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate, | |||
141 | 139 | ||
142 | struct htb_sched { | 140 | struct htb_sched { |
143 | struct list_head root; /* root classes list */ | 141 | struct list_head root; /* root classes list */ |
144 | struct hlist_head hash[HTB_HSIZE]; /* hashed by classid */ | 142 | struct Qdisc_class_hash clhash; |
145 | struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */ | 143 | struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */ |
146 | 144 | ||
147 | /* self list - roots of self generating tree */ | 145 | /* self list - roots of self generating tree */ |
@@ -176,32 +174,16 @@ struct htb_sched { | |||
176 | long direct_pkts; | 174 | long direct_pkts; |
177 | }; | 175 | }; |
178 | 176 | ||
179 | /* compute hash of size HTB_HSIZE for given handle */ | ||
180 | static inline int htb_hash(u32 h) | ||
181 | { | ||
182 | #if HTB_HSIZE != 16 | ||
183 | #error "Declare new hash for your HTB_HSIZE" | ||
184 | #endif | ||
185 | h ^= h >> 8; /* stolen from cbq_hash */ | ||
186 | h ^= h >> 4; | ||
187 | return h & 0xf; | ||
188 | } | ||
189 | |||
190 | /* find class in global hash table using given handle */ | 177 | /* find class in global hash table using given handle */ |
191 | static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch) | 178 | static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch) |
192 | { | 179 | { |
193 | struct htb_sched *q = qdisc_priv(sch); | 180 | struct htb_sched *q = qdisc_priv(sch); |
194 | struct hlist_node *p; | 181 | struct Qdisc_class_common *clc; |
195 | struct htb_class *cl; | ||
196 | 182 | ||
197 | if (TC_H_MAJ(handle) != sch->handle) | 183 | clc = qdisc_class_find(&q->clhash, handle); |
184 | if (clc == NULL) | ||
198 | return NULL; | 185 | return NULL; |
199 | 186 | return container_of(clc, struct htb_class, common); | |
200 | hlist_for_each_entry(cl, p, q->hash + htb_hash(handle), hlist) { | ||
201 | if (cl->classid == handle) | ||
202 | return cl; | ||
203 | } | ||
204 | return NULL; | ||
205 | } | 187 | } |
206 | 188 | ||
207 | /** | 189 | /** |
@@ -282,7 +264,7 @@ static void htb_add_to_id_tree(struct rb_root *root, | |||
282 | parent = *p; | 264 | parent = *p; |
283 | c = rb_entry(parent, struct htb_class, node[prio]); | 265 | c = rb_entry(parent, struct htb_class, node[prio]); |
284 | 266 | ||
285 | if (cl->classid > c->classid) | 267 | if (cl->common.classid > c->common.classid) |
286 | p = &parent->rb_right; | 268 | p = &parent->rb_right; |
287 | else | 269 | else |
288 | p = &parent->rb_left; | 270 | p = &parent->rb_left; |
@@ -446,7 +428,7 @@ static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl) | |||
446 | /* we are removing child which is pointed to from | 428 | /* we are removing child which is pointed to from |
447 | parent feed - forget the pointer but remember | 429 | parent feed - forget the pointer but remember |
448 | classid */ | 430 | classid */ |
449 | p->un.inner.last_ptr_id[prio] = cl->classid; | 431 | p->un.inner.last_ptr_id[prio] = cl->common.classid; |
450 | p->un.inner.ptr[prio] = NULL; | 432 | p->un.inner.ptr[prio] = NULL; |
451 | } | 433 | } |
452 | 434 | ||
@@ -751,10 +733,10 @@ static struct rb_node *htb_id_find_next_upper(int prio, struct rb_node *n, | |||
751 | while (n) { | 733 | while (n) { |
752 | struct htb_class *cl = | 734 | struct htb_class *cl = |
753 | rb_entry(n, struct htb_class, node[prio]); | 735 | rb_entry(n, struct htb_class, node[prio]); |
754 | if (id == cl->classid) | 736 | if (id == cl->common.classid) |
755 | return n; | 737 | return n; |
756 | 738 | ||
757 | if (id > cl->classid) { | 739 | if (id > cl->common.classid) { |
758 | n = n->rb_right; | 740 | n = n->rb_right; |
759 | } else { | 741 | } else { |
760 | r = n; | 742 | r = n; |
@@ -864,7 +846,7 @@ next: | |||
864 | if (!cl->warned) { | 846 | if (!cl->warned) { |
865 | printk(KERN_WARNING | 847 | printk(KERN_WARNING |
866 | "htb: class %X isn't work conserving ?!\n", | 848 | "htb: class %X isn't work conserving ?!\n", |
867 | cl->classid); | 849 | cl->common.classid); |
868 | cl->warned = 1; | 850 | cl->warned = 1; |
869 | } | 851 | } |
870 | q->nwc_hit++; | 852 | q->nwc_hit++; |
@@ -975,13 +957,12 @@ static unsigned int htb_drop(struct Qdisc *sch) | |||
975 | static void htb_reset(struct Qdisc *sch) | 957 | static void htb_reset(struct Qdisc *sch) |
976 | { | 958 | { |
977 | struct htb_sched *q = qdisc_priv(sch); | 959 | struct htb_sched *q = qdisc_priv(sch); |
978 | int i; | 960 | struct htb_class *cl; |
979 | 961 | struct hlist_node *n; | |
980 | for (i = 0; i < HTB_HSIZE; i++) { | 962 | unsigned int i; |
981 | struct hlist_node *p; | ||
982 | struct htb_class *cl; | ||
983 | 963 | ||
984 | hlist_for_each_entry(cl, p, q->hash + i, hlist) { | 964 | for (i = 0; i < q->clhash.hashsize; i++) { |
965 | hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) { | ||
985 | if (cl->level) | 966 | if (cl->level) |
986 | memset(&cl->un.inner, 0, sizeof(cl->un.inner)); | 967 | memset(&cl->un.inner, 0, sizeof(cl->un.inner)); |
987 | else { | 968 | else { |
@@ -1040,8 +1021,9 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) | |||
1040 | } | 1021 | } |
1041 | 1022 | ||
1042 | INIT_LIST_HEAD(&q->root); | 1023 | INIT_LIST_HEAD(&q->root); |
1043 | for (i = 0; i < HTB_HSIZE; i++) | 1024 | err = qdisc_class_hash_init(&q->clhash); |
1044 | INIT_HLIST_HEAD(q->hash + i); | 1025 | if (err < 0) |
1026 | return err; | ||
1045 | for (i = 0; i < TC_HTB_NUMPRIO; i++) | 1027 | for (i = 0; i < TC_HTB_NUMPRIO; i++) |
1046 | INIT_LIST_HEAD(q->drops + i); | 1028 | INIT_LIST_HEAD(q->drops + i); |
1047 | 1029 | ||
@@ -1096,8 +1078,8 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, | |||
1096 | struct tc_htb_opt opt; | 1078 | struct tc_htb_opt opt; |
1097 | 1079 | ||
1098 | spin_lock_bh(&sch->dev->queue_lock); | 1080 | spin_lock_bh(&sch->dev->queue_lock); |
1099 | tcm->tcm_parent = cl->parent ? cl->parent->classid : TC_H_ROOT; | 1081 | tcm->tcm_parent = cl->parent ? cl->parent->common.classid : TC_H_ROOT; |
1100 | tcm->tcm_handle = cl->classid; | 1082 | tcm->tcm_handle = cl->common.classid; |
1101 | if (!cl->level && cl->un.leaf.q) | 1083 | if (!cl->level && cl->un.leaf.q) |
1102 | tcm->tcm_info = cl->un.leaf.q->handle; | 1084 | tcm->tcm_info = cl->un.leaf.q->handle; |
1103 | 1085 | ||
@@ -1152,7 +1134,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, | |||
1152 | if (cl && !cl->level) { | 1134 | if (cl && !cl->level) { |
1153 | if (new == NULL && | 1135 | if (new == NULL && |
1154 | (new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, | 1136 | (new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, |
1155 | cl->classid)) | 1137 | cl->common.classid)) |
1156 | == NULL) | 1138 | == NULL) |
1157 | return -ENOBUFS; | 1139 | return -ENOBUFS; |
1158 | sch_tree_lock(sch); | 1140 | sch_tree_lock(sch); |
@@ -1253,14 +1235,16 @@ static void htb_destroy(struct Qdisc *sch) | |||
1253 | unbind_filter on it (without Oops). */ | 1235 | unbind_filter on it (without Oops). */ |
1254 | tcf_destroy_chain(&q->filter_list); | 1236 | tcf_destroy_chain(&q->filter_list); |
1255 | 1237 | ||
1256 | for (i = 0; i < HTB_HSIZE; i++) { | 1238 | for (i = 0; i < q->clhash.hashsize; i++) { |
1257 | hlist_for_each_entry(cl, n, q->hash + i, hlist) | 1239 | hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) |
1258 | tcf_destroy_chain(&cl->filter_list); | 1240 | tcf_destroy_chain(&cl->filter_list); |
1259 | } | 1241 | } |
1260 | for (i = 0; i < HTB_HSIZE; i++) { | 1242 | for (i = 0; i < q->clhash.hashsize; i++) { |
1261 | hlist_for_each_entry_safe(cl, n, next, q->hash + i, hlist) | 1243 | hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i], |
1244 | common.hnode) | ||
1262 | htb_destroy_class(sch, cl); | 1245 | htb_destroy_class(sch, cl); |
1263 | } | 1246 | } |
1247 | qdisc_class_hash_destroy(&q->clhash); | ||
1264 | __skb_queue_purge(&q->direct_queue); | 1248 | __skb_queue_purge(&q->direct_queue); |
1265 | } | 1249 | } |
1266 | 1250 | ||
@@ -1280,7 +1264,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) | |||
1280 | 1264 | ||
1281 | if (!cl->level && htb_parent_last_child(cl)) { | 1265 | if (!cl->level && htb_parent_last_child(cl)) { |
1282 | new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, | 1266 | new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, |
1283 | cl->parent->classid); | 1267 | cl->parent->common.classid); |
1284 | last_child = 1; | 1268 | last_child = 1; |
1285 | } | 1269 | } |
1286 | 1270 | ||
@@ -1292,8 +1276,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) | |||
1292 | qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen); | 1276 | qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen); |
1293 | } | 1277 | } |
1294 | 1278 | ||
1295 | /* delete from hash, sibling list and active */ | 1279 | /* delete from hash and active; remainder in destroy_class */ |
1296 | hlist_del(&cl->hlist); | 1280 | qdisc_class_hash_remove(&q->clhash, &cl->common); |
1297 | list_del(&cl->sibling); | 1281 | list_del(&cl->sibling); |
1298 | 1282 | ||
1299 | if (cl->prio_activity) | 1283 | if (cl->prio_activity) |
@@ -1390,7 +1374,6 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1390 | tca[TCA_RATE] ? : &est.nla); | 1374 | tca[TCA_RATE] ? : &est.nla); |
1391 | cl->refcnt = 1; | 1375 | cl->refcnt = 1; |
1392 | INIT_LIST_HEAD(&cl->sibling); | 1376 | INIT_LIST_HEAD(&cl->sibling); |
1393 | INIT_HLIST_NODE(&cl->hlist); | ||
1394 | INIT_LIST_HEAD(&cl->children); | 1377 | INIT_LIST_HEAD(&cl->children); |
1395 | INIT_LIST_HEAD(&cl->un.leaf.drop_list); | 1378 | INIT_LIST_HEAD(&cl->un.leaf.drop_list); |
1396 | RB_CLEAR_NODE(&cl->pq_node); | 1379 | RB_CLEAR_NODE(&cl->pq_node); |
@@ -1425,7 +1408,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1425 | /* leaf (we) needs elementary qdisc */ | 1408 | /* leaf (we) needs elementary qdisc */ |
1426 | cl->un.leaf.q = new_q ? new_q : &noop_qdisc; | 1409 | cl->un.leaf.q = new_q ? new_q : &noop_qdisc; |
1427 | 1410 | ||
1428 | cl->classid = classid; | 1411 | cl->common.classid = classid; |
1429 | cl->parent = parent; | 1412 | cl->parent = parent; |
1430 | 1413 | ||
1431 | /* set class to be in HTB_CAN_SEND state */ | 1414 | /* set class to be in HTB_CAN_SEND state */ |
@@ -1436,7 +1419,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1436 | cl->cmode = HTB_CAN_SEND; | 1419 | cl->cmode = HTB_CAN_SEND; |
1437 | 1420 | ||
1438 | /* attach to the hash list and parent's family */ | 1421 | /* attach to the hash list and parent's family */ |
1439 | hlist_add_head(&cl->hlist, q->hash + htb_hash(classid)); | 1422 | qdisc_class_hash_insert(&q->clhash, &cl->common); |
1440 | list_add_tail(&cl->sibling, | 1423 | list_add_tail(&cl->sibling, |
1441 | parent ? &parent->children : &q->root); | 1424 | parent ? &parent->children : &q->root); |
1442 | } else { | 1425 | } else { |
@@ -1454,13 +1437,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1454 | if (!hopt->quantum && cl->un.leaf.quantum < 1000) { | 1437 | if (!hopt->quantum && cl->un.leaf.quantum < 1000) { |
1455 | printk(KERN_WARNING | 1438 | printk(KERN_WARNING |
1456 | "HTB: quantum of class %X is small. Consider r2q change.\n", | 1439 | "HTB: quantum of class %X is small. Consider r2q change.\n", |
1457 | cl->classid); | 1440 | cl->common.classid); |
1458 | cl->un.leaf.quantum = 1000; | 1441 | cl->un.leaf.quantum = 1000; |
1459 | } | 1442 | } |
1460 | if (!hopt->quantum && cl->un.leaf.quantum > 200000) { | 1443 | if (!hopt->quantum && cl->un.leaf.quantum > 200000) { |
1461 | printk(KERN_WARNING | 1444 | printk(KERN_WARNING |
1462 | "HTB: quantum of class %X is big. Consider r2q change.\n", | 1445 | "HTB: quantum of class %X is big. Consider r2q change.\n", |
1463 | cl->classid); | 1446 | cl->common.classid); |
1464 | cl->un.leaf.quantum = 200000; | 1447 | cl->un.leaf.quantum = 200000; |
1465 | } | 1448 | } |
1466 | if (hopt->quantum) | 1449 | if (hopt->quantum) |
@@ -1483,6 +1466,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1483 | cl->ceil = ctab; | 1466 | cl->ceil = ctab; |
1484 | sch_tree_unlock(sch); | 1467 | sch_tree_unlock(sch); |
1485 | 1468 | ||
1469 | qdisc_class_hash_grow(sch, &q->clhash); | ||
1470 | |||
1486 | *arg = (unsigned long)cl; | 1471 | *arg = (unsigned long)cl; |
1487 | return 0; | 1472 | return 0; |
1488 | 1473 | ||
@@ -1539,16 +1524,15 @@ static void htb_unbind_filter(struct Qdisc *sch, unsigned long arg) | |||
1539 | static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg) | 1524 | static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg) |
1540 | { | 1525 | { |
1541 | struct htb_sched *q = qdisc_priv(sch); | 1526 | struct htb_sched *q = qdisc_priv(sch); |
1542 | int i; | 1527 | struct htb_class *cl; |
1528 | struct hlist_node *n; | ||
1529 | unsigned int i; | ||
1543 | 1530 | ||
1544 | if (arg->stop) | 1531 | if (arg->stop) |
1545 | return; | 1532 | return; |
1546 | 1533 | ||
1547 | for (i = 0; i < HTB_HSIZE; i++) { | 1534 | for (i = 0; i < q->clhash.hashsize; i++) { |
1548 | struct hlist_node *p; | 1535 | hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) { |
1549 | struct htb_class *cl; | ||
1550 | |||
1551 | hlist_for_each_entry(cl, p, q->hash + i, hlist) { | ||
1552 | if (arg->count < arg->skip) { | 1536 | if (arg->count < arg->skip) { |
1553 | arg->count++; | 1537 | arg->count++; |
1554 | continue; | 1538 | continue; |