diff options
Diffstat (limited to 'net/sched/cls_u32.c')
-rw-r--r-- | net/sched/cls_u32.c | 21 |
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) | |||
398 | static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n, | 398 | static 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); |