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: Cong Wang <xiyou.wangcong@gmail.com>
This commit is contained in:
commit
a090d7948e
|
@ -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,
|
||||||
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;
|
struct tcindex_data *p = container_of(to_rcu_work(work),
|
||||||
|
struct tcindex_data,
|
||||||
return tcindex_delete(tp, arg, &last, NULL);
|
rwork);
|
||||||
}
|
|
||||||
|
|
||||||
static void __tcindex_destroy(struct rcu_head *head)
|
|
||||||
{
|
|
||||||
struct tcindex_data *p = container_of(head, struct tcindex_data, rcu);
|
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
; /* 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,
|
||||||
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,
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue