Hi, On Fri, 2018-02-02 at 13:52 -0800, Cong Wang wrote: > On Fri, Feb 2, 2018 at 6:30 AM, Paolo Abeni <pab...@redhat.com> wrote: > > The problem is that the htnode is freed before the linked knodes and the > > latter will try to access the first at u32_destroy_key() time. > > This change addresses the issue using the htnode refcnt to guarantee > > the correct free order. While at it also add a RCU annotation, > > to keep sparse happy. > > > > v1 -> v2: use rtnl_derefence() instead of RCU read locks > > > > Reported-by: Li Shuang <shu...@redhat.com> > > Fixes: c0d378ef1266 ("net_sched: use tcf_queue_work() in u32 filter") > > Signed-off-by: Paolo Abeni <pab...@redhat.com> > > --- > > net/sched/cls_u32.c | 19 +++++++++++++++---- > > 1 file changed, 15 insertions(+), 4 deletions(-) > > > > diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c > > index 60c892c36a60..10440fbf3c68 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) > > 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); > > @@ -624,7 +626,12 @@ static int u32_destroy_hnode(struct tcf_proto *tp, > > struct tc_u_hnode *ht, > > idr_destroy(&ht->handle_idr); > > idr_remove_ext(&tp_c->handle_idr, ht->handle); > > RCU_INIT_POINTER(*hn, ht->next); > > - kfree_rcu(ht, rcu); > > + > > + /* u32_destroy_key() will will later free ht for > > us, if > > + * it's still referenced by some knode > > + */ > > + if (ht->refcnt == 0) > > + kfree_rcu(ht, rcu); > > > Isn't u32_destroy_hnode() always called with ht->refcnt==0 ? > So no need this check at all? > > > > return 0; > > } > > } > > @@ -667,7 +674,11 @@ static void u32_destroy(struct tcf_proto *tp, struct > > netlink_ext_ack *extack) > > > > while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) { > > RCU_INIT_POINTER(tp_c->hlist, ht->next); > > - kfree_rcu(ht, rcu); > > + /* u32_destroy_key() will will later free ht for > > us, if > > > Nit: double "will" > > > > + * it's still referenced by some knode > > + */ > > + if (ht->refcnt == 0) > > + kfree_rcu(ht, rcu); > > > This part looks fine. > > Thanks!
Thank you for the feedback! I will send a v3 soon, after some testing. Cheers, Paolo