Skip to content

Commit

Permalink
net_sched: fix a memory leak in cls_tcindex
Browse files Browse the repository at this point in the history
(cherry picked from commit 033b228)

When tcindex_destroy() destroys all the filter results in
the perfect hash table, it invokes the walker to delete
each of them. However, results with class==0 are skipped
in either tcindex_walk() or tcindex_delete(), which causes
a memory leak reported by kmemleak.

This patch fixes it by skipping the walker and directly
deleting these filter results so we don't miss any filter
result.

As a result of this change, we have to initialize exts->net
properly in tcindex_alloc_perfect_hash(). For net-next, we
need to consider whether we should initialize ->net in
tcf_exts_init() instead, before that just directly test
CONFIG_NET_CLS_ACT=y.

Cc: Jamal Hadi Salim <[email protected]>
Cc: Jiri Pirko <[email protected]>
Signed-off-by: Cong Wang <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
congwang authored and davem330 committed Feb 21, 2019
1 parent 3d21053 commit 51dcb69
Showing 1 changed file with 24 additions and 13 deletions.
37 changes: 24 additions & 13 deletions net/sched/cls_tcindex.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,14 +221,6 @@ static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last,
return 0;
}

static int tcindex_destroy_element(struct tcf_proto *tp,
void *arg, struct tcf_walker *walker)
{
bool last;

return tcindex_delete(tp, arg, &last, false, NULL);
}

static void tcindex_destroy_work(struct work_struct *work)
{
struct tcindex_data *p = container_of(to_rcu_work(work),
Expand Down Expand Up @@ -568,13 +560,32 @@ static void tcindex_destroy(struct tcf_proto *tp, bool rtnl_held,
struct netlink_ext_ack *extack)
{
struct tcindex_data *p = rtnl_dereference(tp->root);
struct tcf_walker walker;
int i;

pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p);
walker.count = 0;
walker.skip = 0;
walker.fn = tcindex_destroy_element;
tcindex_walk(tp, &walker, true);

if (p->perfect) {
for (i = 0; i < p->hash; i++) {
struct tcindex_filter_result *r = p->perfect + i;

tcf_unbind_filter(tp, &r->res);
if (tcf_exts_get_net(&r->exts))
tcf_queue_work(&r->rwork,
tcindex_destroy_rexts_work);
else
__tcindex_destroy_rexts(r);
}
}

for (i = 0; p->h && i < p->hash; i++) {
struct tcindex_filter *f, *next;
bool last;

for (f = rtnl_dereference(p->h[i]); f; f = next) {
next = rtnl_dereference(f->next);
tcindex_delete(tp, &f->result, &last, rtnl_held, NULL);
}
}

tcf_queue_work(&p->rwork, tcindex_destroy_work);
}
Expand Down

0 comments on commit 51dcb69

Please sign in to comment.