Commit a090d794 authored by David S. Miller's avatar David S. Miller

Merge branch 'net_sched-some-fixes-for-cls_tcindex'

Cong Wang says:

====================
net_sched: some fixes for cls_tcindex

This patchset contains 3 bug fixes for tcindex filter. Please check
each patch for details.

v2: fix a compile error in patch 2
    drop netns refcnt in patch 1
====================
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
parents 6a7dd172 1db817e7
...@@ -48,7 +48,7 @@ struct tcindex_data { ...@@ -48,7 +48,7 @@ struct tcindex_data {
u32 hash; /* hash table size; 0 if undefined */ u32 hash; /* hash table size; 0 if undefined */
u32 alloc_hash; /* allocated size */ u32 alloc_hash; /* allocated size */
u32 fall_through; /* 0: only classify if explicit match */ u32 fall_through; /* 0: only classify if explicit match */
struct rcu_head rcu; struct rcu_work rwork;
}; };
static inline int tcindex_filter_is_set(struct tcindex_filter_result *r) static inline int tcindex_filter_is_set(struct tcindex_filter_result *r)
...@@ -221,17 +221,11 @@ static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last, ...@@ -221,17 +221,11 @@ static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last,
return 0; return 0;
} }
static int tcindex_destroy_element(struct tcf_proto *tp, static void tcindex_destroy_work(struct work_struct *work)
void *arg, struct tcf_walker *walker)
{
bool last;
return tcindex_delete(tp, arg, &last, NULL);
}
static void __tcindex_destroy(struct rcu_head *head)
{ {
struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); struct tcindex_data *p = container_of(to_rcu_work(work),
struct tcindex_data,
rwork);
kfree(p->perfect); kfree(p->perfect);
kfree(p->h); kfree(p->h);
...@@ -258,9 +252,11 @@ static int tcindex_filter_result_init(struct tcindex_filter_result *r) ...@@ -258,9 +252,11 @@ static int tcindex_filter_result_init(struct tcindex_filter_result *r)
return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
} }
static void __tcindex_partial_destroy(struct rcu_head *head) static void tcindex_partial_destroy_work(struct work_struct *work)
{ {
struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); struct tcindex_data *p = container_of(to_rcu_work(work),
struct tcindex_data,
rwork);
kfree(p->perfect); kfree(p->perfect);
kfree(p); kfree(p);
...@@ -275,7 +271,7 @@ static void tcindex_free_perfect_hash(struct tcindex_data *cp) ...@@ -275,7 +271,7 @@ static void tcindex_free_perfect_hash(struct tcindex_data *cp)
kfree(cp->perfect); kfree(cp->perfect);
} }
static int tcindex_alloc_perfect_hash(struct tcindex_data *cp) static int tcindex_alloc_perfect_hash(struct net *net, struct tcindex_data *cp)
{ {
int i, err = 0; int i, err = 0;
...@@ -289,6 +285,9 @@ static int tcindex_alloc_perfect_hash(struct tcindex_data *cp) ...@@ -289,6 +285,9 @@ static int tcindex_alloc_perfect_hash(struct tcindex_data *cp)
TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
if (err < 0) if (err < 0)
goto errout; goto errout;
#ifdef CONFIG_NET_CLS_ACT
cp->perfect[i].exts.net = net;
#endif
} }
return 0; return 0;
...@@ -305,9 +304,9 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, ...@@ -305,9 +304,9 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
struct nlattr *est, bool ovr, struct netlink_ext_ack *extack) struct nlattr *est, bool ovr, struct netlink_ext_ack *extack)
{ {
struct tcindex_filter_result new_filter_result, *old_r = r; struct tcindex_filter_result new_filter_result, *old_r = r;
struct tcindex_filter_result cr;
struct tcindex_data *cp = NULL, *oldp; struct tcindex_data *cp = NULL, *oldp;
struct tcindex_filter *f = NULL; /* make gcc behave */ struct tcindex_filter *f = NULL; /* make gcc behave */
struct tcf_result cr = {};
int err, balloc = 0; int err, balloc = 0;
struct tcf_exts e; struct tcf_exts e;
...@@ -337,7 +336,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, ...@@ -337,7 +336,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
if (p->perfect) { if (p->perfect) {
int i; int i;
if (tcindex_alloc_perfect_hash(cp) < 0) if (tcindex_alloc_perfect_hash(net, cp) < 0)
goto errout; goto errout;
for (i = 0; i < cp->hash; i++) for (i = 0; i < cp->hash; i++)
cp->perfect[i].res = p->perfect[i].res; cp->perfect[i].res = p->perfect[i].res;
...@@ -346,13 +345,10 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, ...@@ -346,13 +345,10 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
cp->h = p->h; cp->h = p->h;
err = tcindex_filter_result_init(&new_filter_result); err = tcindex_filter_result_init(&new_filter_result);
if (err < 0)
goto errout1;
err = tcindex_filter_result_init(&cr);
if (err < 0) if (err < 0)
goto errout1; goto errout1;
if (old_r) if (old_r)
cr.res = r->res; cr = r->res;
if (tb[TCA_TCINDEX_HASH]) if (tb[TCA_TCINDEX_HASH])
cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]);
...@@ -406,7 +402,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, ...@@ -406,7 +402,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
err = -ENOMEM; err = -ENOMEM;
if (!cp->perfect && !cp->h) { if (!cp->perfect && !cp->h) {
if (valid_perfect_hash(cp)) { if (valid_perfect_hash(cp)) {
if (tcindex_alloc_perfect_hash(cp) < 0) if (tcindex_alloc_perfect_hash(net, cp) < 0)
goto errout_alloc; goto errout_alloc;
balloc = 1; balloc = 1;
} else { } else {
...@@ -443,8 +439,8 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, ...@@ -443,8 +439,8 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
} }
if (tb[TCA_TCINDEX_CLASSID]) { if (tb[TCA_TCINDEX_CLASSID]) {
cr.res.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]); cr.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]);
tcf_bind_filter(tp, &cr.res, base); tcf_bind_filter(tp, &cr, base);
} }
if (old_r && old_r != r) { if (old_r && old_r != r) {
...@@ -456,7 +452,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, ...@@ -456,7 +452,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
} }
oldp = p; oldp = p;
r->res = cr.res; r->res = cr;
tcf_exts_change(&r->exts, &e); tcf_exts_change(&r->exts, &e);
rcu_assign_pointer(tp->root, cp); rcu_assign_pointer(tp->root, cp);
...@@ -475,10 +471,12 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, ...@@ -475,10 +471,12 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
; /* nothing */ ; /* nothing */
rcu_assign_pointer(*fp, f); rcu_assign_pointer(*fp, f);
} else {
tcf_exts_destroy(&new_filter_result.exts);
} }
if (oldp) if (oldp)
call_rcu(&oldp->rcu, __tcindex_partial_destroy); tcf_queue_work(&oldp->rwork, tcindex_partial_destroy_work);
return 0; return 0;
errout_alloc: errout_alloc:
...@@ -487,7 +485,6 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, ...@@ -487,7 +485,6 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
else if (balloc == 2) else if (balloc == 2)
kfree(cp->h); kfree(cp->h);
errout1: errout1:
tcf_exts_destroy(&cr.exts);
tcf_exts_destroy(&new_filter_result.exts); tcf_exts_destroy(&new_filter_result.exts);
errout: errout:
kfree(cp); kfree(cp);
...@@ -562,15 +559,34 @@ static void tcindex_destroy(struct tcf_proto *tp, ...@@ -562,15 +559,34 @@ static void tcindex_destroy(struct tcf_proto *tp,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct tcindex_data *p = rtnl_dereference(tp->root); 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); 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);
call_rcu(&p->rcu, __tcindex_destroy); 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, NULL);
}
}
tcf_queue_work(&p->rwork, tcindex_destroy_work);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment