|
@@ -398,10 +398,12 @@ static int u32_init(struct tcf_proto *tp)
|
|
|
static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n,
|
|
|
bool free_pf)
|
|
|
{
|
|
|
+ struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
|
|
|
+
|
|
|
tcf_exts_destroy(&n->exts);
|
|
|
tcf_exts_put_net(&n->exts);
|
|
|
- if (n->ht_down)
|
|
|
- n->ht_down->refcnt--;
|
|
|
+ if (ht && --ht->refcnt == 0)
|
|
|
+ kfree(ht);
|
|
|
#ifdef CONFIG_CLS_U32_PERF
|
|
|
if (free_pf)
|
|
|
free_percpu(n->pf);
|
|
@@ -659,16 +661,15 @@ static void u32_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
|
|
|
|
|
|
hlist_del(&tp_c->hnode);
|
|
|
|
|
|
- for (ht = rtnl_dereference(tp_c->hlist);
|
|
|
- ht;
|
|
|
- ht = rtnl_dereference(ht->next)) {
|
|
|
- ht->refcnt--;
|
|
|
- u32_clear_hnode(tp, ht, extack);
|
|
|
- }
|
|
|
-
|
|
|
while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) {
|
|
|
+ u32_clear_hnode(tp, ht, extack);
|
|
|
RCU_INIT_POINTER(tp_c->hlist, ht->next);
|
|
|
- kfree_rcu(ht, rcu);
|
|
|
+
|
|
|
+ /* u32_destroy_key() will later free ht for us, if it's
|
|
|
+ * still referenced by some knode
|
|
|
+ */
|
|
|
+ if (--ht->refcnt == 0)
|
|
|
+ kfree_rcu(ht, rcu);
|
|
|
}
|
|
|
|
|
|
idr_destroy(&tp_c->handle_idr);
|