Commit 89890422 authored by Konstantin Khlebnikov's avatar Konstantin Khlebnikov Committed by David S. Miller

net_sched: reset pointers to tcf blocks in classful qdiscs' destructors

Traffic filters could keep direct pointers to classes in classful qdisc,
thus qdisc destruction first removes all filters before freeing classes.
Class destruction methods also tries to free attached filters but now
this isn't safe because tcf_block_put() unlike to tcf_destroy_chain()
cannot be called second time.

This patch set class->block to NULL after first tcf_block_put() and
turn second call into no-op.

Fixes: 6529eaba ("net: sched: introduce tcf block infractructure")
Signed-off-by: default avatarKonstantin Khlebnikov <khlebnikov@yandex-team.ru>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 187e5b3a
...@@ -572,8 +572,10 @@ static void atm_tc_destroy(struct Qdisc *sch) ...@@ -572,8 +572,10 @@ static void atm_tc_destroy(struct Qdisc *sch)
struct atm_flow_data *flow, *tmp; struct atm_flow_data *flow, *tmp;
pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p); pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
list_for_each_entry(flow, &p->flows, list) list_for_each_entry(flow, &p->flows, list) {
tcf_block_put(flow->block); tcf_block_put(flow->block);
flow->block = NULL;
}
list_for_each_entry_safe(flow, tmp, &p->flows, list) { list_for_each_entry_safe(flow, tmp, &p->flows, list) {
if (flow->ref > 1) if (flow->ref > 1)
......
...@@ -1431,8 +1431,10 @@ static void cbq_destroy(struct Qdisc *sch) ...@@ -1431,8 +1431,10 @@ static void cbq_destroy(struct Qdisc *sch)
* be bound to classes which have been destroyed already. --TGR '04 * be bound to classes which have been destroyed already. --TGR '04
*/ */
for (h = 0; h < q->clhash.hashsize; h++) { for (h = 0; h < q->clhash.hashsize; h++) {
hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode) {
tcf_block_put(cl->block); tcf_block_put(cl->block);
cl->block = NULL;
}
} }
for (h = 0; h < q->clhash.hashsize; h++) { for (h = 0; h < q->clhash.hashsize; h++) {
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h], hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h],
......
...@@ -1530,8 +1530,10 @@ hfsc_destroy_qdisc(struct Qdisc *sch) ...@@ -1530,8 +1530,10 @@ hfsc_destroy_qdisc(struct Qdisc *sch)
unsigned int i; unsigned int i;
for (i = 0; i < q->clhash.hashsize; i++) { for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry(cl, &q->clhash.hash[i], cl_common.hnode) hlist_for_each_entry(cl, &q->clhash.hash[i], cl_common.hnode) {
tcf_block_put(cl->block); tcf_block_put(cl->block);
cl->block = NULL;
}
} }
for (i = 0; i < q->clhash.hashsize; i++) { for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i], hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
......
...@@ -1258,8 +1258,10 @@ static void htb_destroy(struct Qdisc *sch) ...@@ -1258,8 +1258,10 @@ static void htb_destroy(struct Qdisc *sch)
tcf_block_put(q->block); tcf_block_put(q->block);
for (i = 0; i < q->clhash.hashsize; i++) { for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) {
tcf_block_put(cl->block); tcf_block_put(cl->block);
cl->block = NULL;
}
} }
for (i = 0; i < q->clhash.hashsize; i++) { for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i], hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment