diff options
author | Patrick McHardy <kaber@trash.net> | 2008-07-06 02:21:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-06 02:21:47 -0400 |
commit | be0d39d52ce35554e856de7e9ea37ac1fa4a7f91 (patch) | |
tree | bc76beba534507e921d4eafdf615d19d012437e4 /net/sched/sch_hfsc.c | |
parent | 6fe1c7a5556807e9d7154a2d2fb938d8a9e47e5f (diff) |
net-sched: sch_hfsc: 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/sched/sch_hfsc.c')
-rw-r--r-- | net/sched/sch_hfsc.c | 81 |
1 files changed, 40 insertions, 41 deletions
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index e817aa00441d..3a8267246a4f 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c | |||
@@ -113,7 +113,7 @@ enum hfsc_class_flags | |||
113 | 113 | ||
114 | struct hfsc_class | 114 | struct hfsc_class |
115 | { | 115 | { |
116 | u32 classid; /* class id */ | 116 | struct Qdisc_class_common cl_common; |
117 | unsigned int refcnt; /* usage count */ | 117 | unsigned int refcnt; /* usage count */ |
118 | 118 | ||
119 | struct gnet_stats_basic bstats; | 119 | struct gnet_stats_basic bstats; |
@@ -134,7 +134,6 @@ struct hfsc_class | |||
134 | struct rb_node vt_node; /* parent's vt_tree member */ | 134 | struct rb_node vt_node; /* parent's vt_tree member */ |
135 | struct rb_root cf_tree; /* active children sorted by cl_f */ | 135 | struct rb_root cf_tree; /* active children sorted by cl_f */ |
136 | struct rb_node cf_node; /* parent's cf_heap member */ | 136 | struct rb_node cf_node; /* parent's cf_heap member */ |
137 | struct list_head hlist; /* hash list member */ | ||
138 | struct list_head dlist; /* drop list member */ | 137 | struct list_head dlist; /* drop list member */ |
139 | 138 | ||
140 | u64 cl_total; /* total work in bytes */ | 139 | u64 cl_total; /* total work in bytes */ |
@@ -177,13 +176,11 @@ struct hfsc_class | |||
177 | unsigned long cl_nactive; /* number of active children */ | 176 | unsigned long cl_nactive; /* number of active children */ |
178 | }; | 177 | }; |
179 | 178 | ||
180 | #define HFSC_HSIZE 16 | ||
181 | |||
182 | struct hfsc_sched | 179 | struct hfsc_sched |
183 | { | 180 | { |
184 | u16 defcls; /* default class id */ | 181 | u16 defcls; /* default class id */ |
185 | struct hfsc_class root; /* root class */ | 182 | struct hfsc_class root; /* root class */ |
186 | struct list_head clhash[HFSC_HSIZE]; /* class hash */ | 183 | struct Qdisc_class_hash clhash; /* class hash */ |
187 | struct rb_root eligible; /* eligible tree */ | 184 | struct rb_root eligible; /* eligible tree */ |
188 | struct list_head droplist; /* active leaf class list (for | 185 | struct list_head droplist; /* active leaf class list (for |
189 | dropping) */ | 186 | dropping) */ |
@@ -933,26 +930,16 @@ hfsc_adjust_levels(struct hfsc_class *cl) | |||
933 | } while ((cl = cl->cl_parent) != NULL); | 930 | } while ((cl = cl->cl_parent) != NULL); |
934 | } | 931 | } |
935 | 932 | ||
936 | static inline unsigned int | ||
937 | hfsc_hash(u32 h) | ||
938 | { | ||
939 | h ^= h >> 8; | ||
940 | h ^= h >> 4; | ||
941 | |||
942 | return h & (HFSC_HSIZE - 1); | ||
943 | } | ||
944 | |||
945 | static inline struct hfsc_class * | 933 | static inline struct hfsc_class * |
946 | hfsc_find_class(u32 classid, struct Qdisc *sch) | 934 | hfsc_find_class(u32 classid, struct Qdisc *sch) |
947 | { | 935 | { |
948 | struct hfsc_sched *q = qdisc_priv(sch); | 936 | struct hfsc_sched *q = qdisc_priv(sch); |
949 | struct hfsc_class *cl; | 937 | struct Qdisc_class_common *clc; |
950 | 938 | ||
951 | list_for_each_entry(cl, &q->clhash[hfsc_hash(classid)], hlist) { | 939 | clc = qdisc_class_find(&q->clhash, classid); |
952 | if (cl->classid == classid) | 940 | if (clc == NULL) |
953 | return cl; | 941 | return NULL; |
954 | } | 942 | return container_of(clc, struct hfsc_class, cl_common); |
955 | return NULL; | ||
956 | } | 943 | } |
957 | 944 | ||
958 | static void | 945 | static void |
@@ -1032,7 +1019,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
1032 | 1019 | ||
1033 | if (cl != NULL) { | 1020 | if (cl != NULL) { |
1034 | if (parentid) { | 1021 | if (parentid) { |
1035 | if (cl->cl_parent && cl->cl_parent->classid != parentid) | 1022 | if (cl->cl_parent && |
1023 | cl->cl_parent->cl_common.classid != parentid) | ||
1036 | return -EINVAL; | 1024 | return -EINVAL; |
1037 | if (cl->cl_parent == NULL && parentid != TC_H_ROOT) | 1025 | if (cl->cl_parent == NULL && parentid != TC_H_ROOT) |
1038 | return -EINVAL; | 1026 | return -EINVAL; |
@@ -1091,8 +1079,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
1091 | if (usc != NULL) | 1079 | if (usc != NULL) |
1092 | hfsc_change_usc(cl, usc, 0); | 1080 | hfsc_change_usc(cl, usc, 0); |
1093 | 1081 | ||
1082 | cl->cl_common.classid = classid; | ||
1094 | cl->refcnt = 1; | 1083 | cl->refcnt = 1; |
1095 | cl->classid = classid; | ||
1096 | cl->sched = q; | 1084 | cl->sched = q; |
1097 | cl->cl_parent = parent; | 1085 | cl->cl_parent = parent; |
1098 | cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); | 1086 | cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); |
@@ -1103,7 +1091,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
1103 | cl->cf_tree = RB_ROOT; | 1091 | cl->cf_tree = RB_ROOT; |
1104 | 1092 | ||
1105 | sch_tree_lock(sch); | 1093 | sch_tree_lock(sch); |
1106 | list_add_tail(&cl->hlist, &q->clhash[hfsc_hash(classid)]); | 1094 | qdisc_class_hash_insert(&q->clhash, &cl->cl_common); |
1107 | list_add_tail(&cl->siblings, &parent->children); | 1095 | list_add_tail(&cl->siblings, &parent->children); |
1108 | if (parent->level == 0) | 1096 | if (parent->level == 0) |
1109 | hfsc_purge_queue(sch, parent); | 1097 | hfsc_purge_queue(sch, parent); |
@@ -1111,6 +1099,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
1111 | cl->cl_pcvtoff = parent->cl_cvtoff; | 1099 | cl->cl_pcvtoff = parent->cl_cvtoff; |
1112 | sch_tree_unlock(sch); | 1100 | sch_tree_unlock(sch); |
1113 | 1101 | ||
1102 | qdisc_class_hash_grow(sch, &q->clhash); | ||
1103 | |||
1114 | if (tca[TCA_RATE]) | 1104 | if (tca[TCA_RATE]) |
1115 | gen_new_estimator(&cl->bstats, &cl->rate_est, | 1105 | gen_new_estimator(&cl->bstats, &cl->rate_est, |
1116 | &sch->dev->queue_lock, tca[TCA_RATE]); | 1106 | &sch->dev->queue_lock, tca[TCA_RATE]); |
@@ -1145,7 +1135,7 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg) | |||
1145 | hfsc_adjust_levels(cl->cl_parent); | 1135 | hfsc_adjust_levels(cl->cl_parent); |
1146 | 1136 | ||
1147 | hfsc_purge_queue(sch, cl); | 1137 | hfsc_purge_queue(sch, cl); |
1148 | list_del(&cl->hlist); | 1138 | qdisc_class_hash_remove(&q->clhash, &cl->cl_common); |
1149 | 1139 | ||
1150 | if (--cl->refcnt == 0) | 1140 | if (--cl->refcnt == 0) |
1151 | hfsc_destroy_class(sch, cl); | 1141 | hfsc_destroy_class(sch, cl); |
@@ -1212,7 +1202,7 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, | |||
1212 | return -EINVAL; | 1202 | return -EINVAL; |
1213 | if (new == NULL) { | 1203 | if (new == NULL) { |
1214 | new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, | 1204 | new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, |
1215 | cl->classid); | 1205 | cl->cl_common.classid); |
1216 | if (new == NULL) | 1206 | if (new == NULL) |
1217 | new = &noop_qdisc; | 1207 | new = &noop_qdisc; |
1218 | } | 1208 | } |
@@ -1345,8 +1335,9 @@ hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, | |||
1345 | struct hfsc_class *cl = (struct hfsc_class *)arg; | 1335 | struct hfsc_class *cl = (struct hfsc_class *)arg; |
1346 | struct nlattr *nest; | 1336 | struct nlattr *nest; |
1347 | 1337 | ||
1348 | tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->classid : TC_H_ROOT; | 1338 | tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->cl_common.classid : |
1349 | tcm->tcm_handle = cl->classid; | 1339 | TC_H_ROOT; |
1340 | tcm->tcm_handle = cl->cl_common.classid; | ||
1350 | if (cl->level == 0) | 1341 | if (cl->level == 0) |
1351 | tcm->tcm_info = cl->qdisc->handle; | 1342 | tcm->tcm_info = cl->qdisc->handle; |
1352 | 1343 | ||
@@ -1390,14 +1381,16 @@ static void | |||
1390 | hfsc_walk(struct Qdisc *sch, struct qdisc_walker *arg) | 1381 | hfsc_walk(struct Qdisc *sch, struct qdisc_walker *arg) |
1391 | { | 1382 | { |
1392 | struct hfsc_sched *q = qdisc_priv(sch); | 1383 | struct hfsc_sched *q = qdisc_priv(sch); |
1384 | struct hlist_node *n; | ||
1393 | struct hfsc_class *cl; | 1385 | struct hfsc_class *cl; |
1394 | unsigned int i; | 1386 | unsigned int i; |
1395 | 1387 | ||
1396 | if (arg->stop) | 1388 | if (arg->stop) |
1397 | return; | 1389 | return; |
1398 | 1390 | ||
1399 | for (i = 0; i < HFSC_HSIZE; i++) { | 1391 | for (i = 0; i < q->clhash.hashsize; i++) { |
1400 | list_for_each_entry(cl, &q->clhash[i], hlist) { | 1392 | hlist_for_each_entry(cl, n, &q->clhash.hash[i], |
1393 | cl_common.hnode) { | ||
1401 | if (arg->count < arg->skip) { | 1394 | if (arg->count < arg->skip) { |
1402 | arg->count++; | 1395 | arg->count++; |
1403 | continue; | 1396 | continue; |
@@ -1433,21 +1426,22 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) | |||
1433 | { | 1426 | { |
1434 | struct hfsc_sched *q = qdisc_priv(sch); | 1427 | struct hfsc_sched *q = qdisc_priv(sch); |
1435 | struct tc_hfsc_qopt *qopt; | 1428 | struct tc_hfsc_qopt *qopt; |
1436 | unsigned int i; | 1429 | int err; |
1437 | 1430 | ||
1438 | if (opt == NULL || nla_len(opt) < sizeof(*qopt)) | 1431 | if (opt == NULL || nla_len(opt) < sizeof(*qopt)) |
1439 | return -EINVAL; | 1432 | return -EINVAL; |
1440 | qopt = nla_data(opt); | 1433 | qopt = nla_data(opt); |
1441 | 1434 | ||
1442 | q->defcls = qopt->defcls; | 1435 | q->defcls = qopt->defcls; |
1443 | for (i = 0; i < HFSC_HSIZE; i++) | 1436 | err = qdisc_class_hash_init(&q->clhash); |
1444 | INIT_LIST_HEAD(&q->clhash[i]); | 1437 | if (err < 0) |
1438 | return err; | ||
1445 | q->eligible = RB_ROOT; | 1439 | q->eligible = RB_ROOT; |
1446 | INIT_LIST_HEAD(&q->droplist); | 1440 | INIT_LIST_HEAD(&q->droplist); |
1447 | skb_queue_head_init(&q->requeue); | 1441 | skb_queue_head_init(&q->requeue); |
1448 | 1442 | ||
1443 | q->root.cl_common.classid = sch->handle; | ||
1449 | q->root.refcnt = 1; | 1444 | q->root.refcnt = 1; |
1450 | q->root.classid = sch->handle; | ||
1451 | q->root.sched = q; | 1445 | q->root.sched = q; |
1452 | q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, | 1446 | q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, |
1453 | sch->handle); | 1447 | sch->handle); |
@@ -1457,7 +1451,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) | |||
1457 | q->root.vt_tree = RB_ROOT; | 1451 | q->root.vt_tree = RB_ROOT; |
1458 | q->root.cf_tree = RB_ROOT; | 1452 | q->root.cf_tree = RB_ROOT; |
1459 | 1453 | ||
1460 | list_add(&q->root.hlist, &q->clhash[hfsc_hash(q->root.classid)]); | 1454 | qdisc_class_hash_insert(&q->clhash, &q->root.cl_common); |
1455 | qdisc_class_hash_grow(sch, &q->clhash); | ||
1461 | 1456 | ||
1462 | qdisc_watchdog_init(&q->watchdog, sch); | 1457 | qdisc_watchdog_init(&q->watchdog, sch); |
1463 | 1458 | ||
@@ -1520,10 +1515,11 @@ hfsc_reset_qdisc(struct Qdisc *sch) | |||
1520 | { | 1515 | { |
1521 | struct hfsc_sched *q = qdisc_priv(sch); | 1516 | struct hfsc_sched *q = qdisc_priv(sch); |
1522 | struct hfsc_class *cl; | 1517 | struct hfsc_class *cl; |
1518 | struct hlist_node *n; | ||
1523 | unsigned int i; | 1519 | unsigned int i; |
1524 | 1520 | ||
1525 | for (i = 0; i < HFSC_HSIZE; i++) { | 1521 | for (i = 0; i < q->clhash.hashsize; i++) { |
1526 | list_for_each_entry(cl, &q->clhash[i], hlist) | 1522 | hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode) |
1527 | hfsc_reset_class(cl); | 1523 | hfsc_reset_class(cl); |
1528 | } | 1524 | } |
1529 | __skb_queue_purge(&q->requeue); | 1525 | __skb_queue_purge(&q->requeue); |
@@ -1537,17 +1533,20 @@ static void | |||
1537 | hfsc_destroy_qdisc(struct Qdisc *sch) | 1533 | hfsc_destroy_qdisc(struct Qdisc *sch) |
1538 | { | 1534 | { |
1539 | struct hfsc_sched *q = qdisc_priv(sch); | 1535 | struct hfsc_sched *q = qdisc_priv(sch); |
1540 | struct hfsc_class *cl, *next; | 1536 | struct hlist_node *n, *next; |
1537 | struct hfsc_class *cl; | ||
1541 | unsigned int i; | 1538 | unsigned int i; |
1542 | 1539 | ||
1543 | for (i = 0; i < HFSC_HSIZE; i++) { | 1540 | for (i = 0; i < q->clhash.hashsize; i++) { |
1544 | list_for_each_entry(cl, &q->clhash[i], hlist) | 1541 | hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode) |
1545 | tcf_destroy_chain(&cl->filter_list); | 1542 | tcf_destroy_chain(&cl->filter_list); |
1546 | } | 1543 | } |
1547 | for (i = 0; i < HFSC_HSIZE; i++) { | 1544 | for (i = 0; i < q->clhash.hashsize; i++) { |
1548 | list_for_each_entry_safe(cl, next, &q->clhash[i], hlist) | 1545 | hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i], |
1546 | cl_common.hnode) | ||
1549 | hfsc_destroy_class(sch, cl); | 1547 | hfsc_destroy_class(sch, cl); |
1550 | } | 1548 | } |
1549 | qdisc_class_hash_destroy(&q->clhash); | ||
1551 | __skb_queue_purge(&q->requeue); | 1550 | __skb_queue_purge(&q->requeue); |
1552 | qdisc_watchdog_cancel(&q->watchdog); | 1551 | qdisc_watchdog_cancel(&q->watchdog); |
1553 | } | 1552 | } |