net: sched: use rcu for action cookie update
Implement functions to atomically update and free action cookie using rcu mechanism. Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: Vlad Buslov <vladbu@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
b233504033
Коммит
eec94fdb04
|
@ -37,7 +37,7 @@ struct tc_action {
|
||||||
spinlock_t tcfa_lock;
|
spinlock_t tcfa_lock;
|
||||||
struct gnet_stats_basic_cpu __percpu *cpu_bstats;
|
struct gnet_stats_basic_cpu __percpu *cpu_bstats;
|
||||||
struct gnet_stats_queue __percpu *cpu_qstats;
|
struct gnet_stats_queue __percpu *cpu_qstats;
|
||||||
struct tc_cookie *act_cookie;
|
struct tc_cookie __rcu *act_cookie;
|
||||||
struct tcf_chain *goto_chain;
|
struct tcf_chain *goto_chain;
|
||||||
};
|
};
|
||||||
#define tcf_index common.tcfa_index
|
#define tcf_index common.tcfa_index
|
||||||
|
|
|
@ -781,6 +781,7 @@ struct tc_mqprio_qopt_offload {
|
||||||
struct tc_cookie {
|
struct tc_cookie {
|
||||||
u8 *data;
|
u8 *data;
|
||||||
u32 len;
|
u32 len;
|
||||||
|
struct rcu_head rcu;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tc_qopt_offload_stats {
|
struct tc_qopt_offload_stats {
|
||||||
|
|
|
@ -55,6 +55,24 @@ static void tcf_action_goto_chain_exec(const struct tc_action *a,
|
||||||
res->goto_tp = rcu_dereference_bh(chain->filter_chain);
|
res->goto_tp = rcu_dereference_bh(chain->filter_chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tcf_free_cookie_rcu(struct rcu_head *p)
|
||||||
|
{
|
||||||
|
struct tc_cookie *cookie = container_of(p, struct tc_cookie, rcu);
|
||||||
|
|
||||||
|
kfree(cookie->data);
|
||||||
|
kfree(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcf_set_action_cookie(struct tc_cookie __rcu **old_cookie,
|
||||||
|
struct tc_cookie *new_cookie)
|
||||||
|
{
|
||||||
|
struct tc_cookie *old;
|
||||||
|
|
||||||
|
old = xchg(old_cookie, new_cookie);
|
||||||
|
if (old)
|
||||||
|
call_rcu(&old->rcu, tcf_free_cookie_rcu);
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: For standalone actions, we don't need a RCU grace period either, because
|
/* XXX: For standalone actions, we don't need a RCU grace period either, because
|
||||||
* actions are always connected to filters and filters are already destroyed in
|
* actions are always connected to filters and filters are already destroyed in
|
||||||
* RCU callbacks, so after a RCU grace period actions are already disconnected
|
* RCU callbacks, so after a RCU grace period actions are already disconnected
|
||||||
|
@ -65,10 +83,7 @@ static void free_tcf(struct tc_action *p)
|
||||||
free_percpu(p->cpu_bstats);
|
free_percpu(p->cpu_bstats);
|
||||||
free_percpu(p->cpu_qstats);
|
free_percpu(p->cpu_qstats);
|
||||||
|
|
||||||
if (p->act_cookie) {
|
tcf_set_action_cookie(&p->act_cookie, NULL);
|
||||||
kfree(p->act_cookie->data);
|
|
||||||
kfree(p->act_cookie);
|
|
||||||
}
|
|
||||||
if (p->goto_chain)
|
if (p->goto_chain)
|
||||||
tcf_action_goto_chain_fini(p);
|
tcf_action_goto_chain_fini(p);
|
||||||
|
|
||||||
|
@ -567,16 +582,22 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
unsigned char *b = skb_tail_pointer(skb);
|
unsigned char *b = skb_tail_pointer(skb);
|
||||||
struct nlattr *nest;
|
struct nlattr *nest;
|
||||||
|
struct tc_cookie *cookie;
|
||||||
|
|
||||||
if (nla_put_string(skb, TCA_KIND, a->ops->kind))
|
if (nla_put_string(skb, TCA_KIND, a->ops->kind))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
if (tcf_action_copy_stats(skb, a, 0))
|
if (tcf_action_copy_stats(skb, a, 0))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
if (a->act_cookie) {
|
|
||||||
if (nla_put(skb, TCA_ACT_COOKIE, a->act_cookie->len,
|
rcu_read_lock();
|
||||||
a->act_cookie->data))
|
cookie = rcu_dereference(a->act_cookie);
|
||||||
|
if (cookie) {
|
||||||
|
if (nla_put(skb, TCA_ACT_COOKIE, cookie->len, cookie->data)) {
|
||||||
|
rcu_read_unlock();
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
nest = nla_nest_start(skb, TCA_OPTIONS);
|
nest = nla_nest_start(skb, TCA_OPTIONS);
|
||||||
if (nest == NULL)
|
if (nest == NULL)
|
||||||
|
@ -719,13 +740,8 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_mod;
|
goto err_mod;
|
||||||
|
|
||||||
if (name == NULL && tb[TCA_ACT_COOKIE]) {
|
if (!name && tb[TCA_ACT_COOKIE])
|
||||||
if (a->act_cookie) {
|
tcf_set_action_cookie(&a->act_cookie, cookie);
|
||||||
kfree(a->act_cookie->data);
|
|
||||||
kfree(a->act_cookie);
|
|
||||||
}
|
|
||||||
a->act_cookie = cookie;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* module count goes up only when brand new policy is created
|
/* module count goes up only when brand new policy is created
|
||||||
* if it exists and is only bound to in a_o->init() then
|
* if it exists and is only bound to in a_o->init() then
|
||||||
|
|
Загрузка…
Ссылка в новой задаче