aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_u32.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_u32.c')
-rw-r--r--net/sched/cls_u32.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index e3c5e390ec23..6311a548046b 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -398,10 +398,12 @@ static int u32_init(struct tcf_proto *tp)
398static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n, 398static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n,
399 bool free_pf) 399 bool free_pf)
400{ 400{
401 struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
402
401 tcf_exts_destroy(&n->exts); 403 tcf_exts_destroy(&n->exts);
402 tcf_exts_put_net(&n->exts); 404 tcf_exts_put_net(&n->exts);
403 if (n->ht_down) 405 if (ht && --ht->refcnt == 0)
404 n->ht_down->refcnt--; 406 kfree(ht);
405#ifdef CONFIG_CLS_U32_PERF 407#ifdef CONFIG_CLS_U32_PERF
406 if (free_pf) 408 if (free_pf)
407 free_percpu(n->pf); 409 free_percpu(n->pf);
@@ -659,16 +661,15 @@ static void u32_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
659 661
660 hlist_del(&tp_c->hnode); 662 hlist_del(&tp_c->hnode);
661 663
662 for (ht = rtnl_dereference(tp_c->hlist);
663 ht;
664 ht = rtnl_dereference(ht->next)) {
665 ht->refcnt--;
666 u32_clear_hnode(tp, ht, extack);
667 }
668
669 while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) { 664 while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) {
665 u32_clear_hnode(tp, ht, extack);
670 RCU_INIT_POINTER(tp_c->hlist, ht->next); 666 RCU_INIT_POINTER(tp_c->hlist, ht->next);
671 kfree_rcu(ht, rcu); 667
668 /* u32_destroy_key() will later free ht for us, if it's
669 * still referenced by some knode
670 */
671 if (--ht->refcnt == 0)
672 kfree_rcu(ht, rcu);
672 } 673 }
673 674
674 idr_destroy(&tp_c->handle_idr); 675 idr_destroy(&tp_c->handle_idr);