net_sched: reset pointers to tcf blocks in classful qdiscs' destructors
authorKonstantin Khlebnikov <khlebnikov@yandex-team.ru>
Tue, 15 Aug 2017 13:35:21 +0000 (16:35 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Aug 2017 00:16:39 +0000 (17:16 -0700)
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: 6529eaba33f0 ("net: sched: introduce tcf block infractructure")
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/sch_atm.c
net/sched/sch_cbq.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c

index 572fe2584e48c81dbf58d90ce9d6a4ae68d2a385..c403c87aff7a44bccfdd5f07e2e00ea0698a5c90 100644 (file)
@@ -572,8 +572,10 @@ static void atm_tc_destroy(struct Qdisc *sch)
        struct atm_flow_data *flow, *tmp;
 
        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);
+               flow->block = NULL;
+       }
 
        list_for_each_entry_safe(flow, tmp, &p->flows, list) {
                if (flow->ref > 1)
index 481036f6b54e4730ee27fae6236277c64d3eaa1a..780db43300b16284192b24006b0ae8677adbe505 100644 (file)
@@ -1431,8 +1431,10 @@ static void cbq_destroy(struct Qdisc *sch)
         * be bound to classes which have been destroyed already. --TGR '04
         */
        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);
+                       cl->block = NULL;
+               }
        }
        for (h = 0; h < q->clhash.hashsize; h++) {
                hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h],
index 3ad02bbe6903ac3400f088beeb7850de498c06d7..fd15200f86273add7d6c8c4a18aaef912aba7411 100644 (file)
@@ -1530,8 +1530,10 @@ hfsc_destroy_qdisc(struct Qdisc *sch)
        unsigned int 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);
+                       cl->block = NULL;
+               }
        }
        for (i = 0; i < q->clhash.hashsize; i++) {
                hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
index 203286ab442799a07808bd8f73af9f07b0482cbd..5d65ec5207e91202d501a83c983793f2e923f075 100644 (file)
@@ -1258,8 +1258,10 @@ static void htb_destroy(struct Qdisc *sch)
        tcf_block_put(q->block);
 
        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);
+                       cl->block = NULL;
+               }
        }
        for (i = 0; i < q->clhash.hashsize; i++) {
                hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],