Commit ceffcc5e authored by Cong Wang's avatar Cong Wang Committed by David S. Miller

net_sched: hold netns refcnt for each action

TC actions have been destroyed asynchronously for a long time,
previously in a RCU callback and now in a workqueue. If we
don't hold a refcnt for its netns, we could use the per netns
data structure, struct tcf_idrinfo, after it has been freed by
netns workqueue.

Hold refcnt to ensure netns destroy happens after all actions
are gone.

Fixes: ddf97ccd ("net_sched: add network namespace support for tc actions")
Reported-by: default avatarLucas Bates <lucasb@mojatatu.com>
Tested-by: default avatarLucas Bates <lucasb@mojatatu.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a159d3c4
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
struct tcf_idrinfo { struct tcf_idrinfo {
spinlock_t lock; spinlock_t lock;
struct idr action_idr; struct idr action_idr;
struct net *net;
}; };
struct tc_action_ops; struct tc_action_ops;
...@@ -104,7 +105,7 @@ struct tc_action_net { ...@@ -104,7 +105,7 @@ struct tc_action_net {
static inline static inline
int tc_action_net_init(struct tc_action_net *tn, int tc_action_net_init(struct tc_action_net *tn,
const struct tc_action_ops *ops) const struct tc_action_ops *ops, struct net *net)
{ {
int err = 0; int err = 0;
...@@ -112,6 +113,7 @@ int tc_action_net_init(struct tc_action_net *tn, ...@@ -112,6 +113,7 @@ int tc_action_net_init(struct tc_action_net *tn,
if (!tn->idrinfo) if (!tn->idrinfo)
return -ENOMEM; return -ENOMEM;
tn->ops = ops; tn->ops = ops;
tn->idrinfo->net = net;
spin_lock_init(&tn->idrinfo->lock); spin_lock_init(&tn->idrinfo->lock);
idr_init(&tn->idrinfo->action_idr); idr_init(&tn->idrinfo->action_idr);
return err; return err;
......
...@@ -78,6 +78,7 @@ static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p) ...@@ -78,6 +78,7 @@ static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p)
spin_lock_bh(&idrinfo->lock); spin_lock_bh(&idrinfo->lock);
idr_remove_ext(&idrinfo->action_idr, p->tcfa_index); idr_remove_ext(&idrinfo->action_idr, p->tcfa_index);
spin_unlock_bh(&idrinfo->lock); spin_unlock_bh(&idrinfo->lock);
put_net(idrinfo->net);
gen_kill_estimator(&p->tcfa_rate_est); gen_kill_estimator(&p->tcfa_rate_est);
free_tcf(p); free_tcf(p);
} }
...@@ -336,6 +337,7 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, ...@@ -336,6 +337,7 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
p->idrinfo = idrinfo; p->idrinfo = idrinfo;
p->ops = ops; p->ops = ops;
INIT_LIST_HEAD(&p->list); INIT_LIST_HEAD(&p->list);
get_net(idrinfo->net);
*a = p; *a = p;
return 0; return 0;
} }
......
...@@ -398,7 +398,7 @@ static __net_init int bpf_init_net(struct net *net) ...@@ -398,7 +398,7 @@ static __net_init int bpf_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, bpf_net_id); struct tc_action_net *tn = net_generic(net, bpf_net_id);
return tc_action_net_init(tn, &act_bpf_ops); return tc_action_net_init(tn, &act_bpf_ops, net);
} }
static void __net_exit bpf_exit_net(struct net *net) static void __net_exit bpf_exit_net(struct net *net)
......
...@@ -206,7 +206,7 @@ static __net_init int connmark_init_net(struct net *net) ...@@ -206,7 +206,7 @@ static __net_init int connmark_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, connmark_net_id); struct tc_action_net *tn = net_generic(net, connmark_net_id);
return tc_action_net_init(tn, &act_connmark_ops); return tc_action_net_init(tn, &act_connmark_ops, net);
} }
static void __net_exit connmark_exit_net(struct net *net) static void __net_exit connmark_exit_net(struct net *net)
......
...@@ -626,7 +626,7 @@ static __net_init int csum_init_net(struct net *net) ...@@ -626,7 +626,7 @@ static __net_init int csum_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, csum_net_id); struct tc_action_net *tn = net_generic(net, csum_net_id);
return tc_action_net_init(tn, &act_csum_ops); return tc_action_net_init(tn, &act_csum_ops, net);
} }
static void __net_exit csum_exit_net(struct net *net) static void __net_exit csum_exit_net(struct net *net)
......
...@@ -232,7 +232,7 @@ static __net_init int gact_init_net(struct net *net) ...@@ -232,7 +232,7 @@ static __net_init int gact_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, gact_net_id); struct tc_action_net *tn = net_generic(net, gact_net_id);
return tc_action_net_init(tn, &act_gact_ops); return tc_action_net_init(tn, &act_gact_ops, net);
} }
static void __net_exit gact_exit_net(struct net *net) static void __net_exit gact_exit_net(struct net *net)
......
...@@ -818,7 +818,7 @@ static __net_init int ife_init_net(struct net *net) ...@@ -818,7 +818,7 @@ static __net_init int ife_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, ife_net_id); struct tc_action_net *tn = net_generic(net, ife_net_id);
return tc_action_net_init(tn, &act_ife_ops); return tc_action_net_init(tn, &act_ife_ops, net);
} }
static void __net_exit ife_exit_net(struct net *net) static void __net_exit ife_exit_net(struct net *net)
......
...@@ -334,7 +334,7 @@ static __net_init int ipt_init_net(struct net *net) ...@@ -334,7 +334,7 @@ static __net_init int ipt_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, ipt_net_id); struct tc_action_net *tn = net_generic(net, ipt_net_id);
return tc_action_net_init(tn, &act_ipt_ops); return tc_action_net_init(tn, &act_ipt_ops, net);
} }
static void __net_exit ipt_exit_net(struct net *net) static void __net_exit ipt_exit_net(struct net *net)
...@@ -384,7 +384,7 @@ static __net_init int xt_init_net(struct net *net) ...@@ -384,7 +384,7 @@ static __net_init int xt_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, xt_net_id); struct tc_action_net *tn = net_generic(net, xt_net_id);
return tc_action_net_init(tn, &act_xt_ops); return tc_action_net_init(tn, &act_xt_ops, net);
} }
static void __net_exit xt_exit_net(struct net *net) static void __net_exit xt_exit_net(struct net *net)
......
...@@ -343,7 +343,7 @@ static __net_init int mirred_init_net(struct net *net) ...@@ -343,7 +343,7 @@ static __net_init int mirred_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, mirred_net_id); struct tc_action_net *tn = net_generic(net, mirred_net_id);
return tc_action_net_init(tn, &act_mirred_ops); return tc_action_net_init(tn, &act_mirred_ops, net);
} }
static void __net_exit mirred_exit_net(struct net *net) static void __net_exit mirred_exit_net(struct net *net)
......
...@@ -307,7 +307,7 @@ static __net_init int nat_init_net(struct net *net) ...@@ -307,7 +307,7 @@ static __net_init int nat_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, nat_net_id); struct tc_action_net *tn = net_generic(net, nat_net_id);
return tc_action_net_init(tn, &act_nat_ops); return tc_action_net_init(tn, &act_nat_ops, net);
} }
static void __net_exit nat_exit_net(struct net *net) static void __net_exit nat_exit_net(struct net *net)
......
...@@ -450,7 +450,7 @@ static __net_init int pedit_init_net(struct net *net) ...@@ -450,7 +450,7 @@ static __net_init int pedit_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, pedit_net_id); struct tc_action_net *tn = net_generic(net, pedit_net_id);
return tc_action_net_init(tn, &act_pedit_ops); return tc_action_net_init(tn, &act_pedit_ops, net);
} }
static void __net_exit pedit_exit_net(struct net *net) static void __net_exit pedit_exit_net(struct net *net)
......
...@@ -331,7 +331,7 @@ static __net_init int police_init_net(struct net *net) ...@@ -331,7 +331,7 @@ static __net_init int police_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, police_net_id); struct tc_action_net *tn = net_generic(net, police_net_id);
return tc_action_net_init(tn, &act_police_ops); return tc_action_net_init(tn, &act_police_ops, net);
} }
static void __net_exit police_exit_net(struct net *net) static void __net_exit police_exit_net(struct net *net)
......
...@@ -240,7 +240,7 @@ static __net_init int sample_init_net(struct net *net) ...@@ -240,7 +240,7 @@ static __net_init int sample_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, sample_net_id); struct tc_action_net *tn = net_generic(net, sample_net_id);
return tc_action_net_init(tn, &act_sample_ops); return tc_action_net_init(tn, &act_sample_ops, net);
} }
static void __net_exit sample_exit_net(struct net *net) static void __net_exit sample_exit_net(struct net *net)
......
...@@ -201,7 +201,7 @@ static __net_init int simp_init_net(struct net *net) ...@@ -201,7 +201,7 @@ static __net_init int simp_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, simp_net_id); struct tc_action_net *tn = net_generic(net, simp_net_id);
return tc_action_net_init(tn, &act_simp_ops); return tc_action_net_init(tn, &act_simp_ops, net);
} }
static void __net_exit simp_exit_net(struct net *net) static void __net_exit simp_exit_net(struct net *net)
......
...@@ -238,7 +238,7 @@ static __net_init int skbedit_init_net(struct net *net) ...@@ -238,7 +238,7 @@ static __net_init int skbedit_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, skbedit_net_id); struct tc_action_net *tn = net_generic(net, skbedit_net_id);
return tc_action_net_init(tn, &act_skbedit_ops); return tc_action_net_init(tn, &act_skbedit_ops, net);
} }
static void __net_exit skbedit_exit_net(struct net *net) static void __net_exit skbedit_exit_net(struct net *net)
......
...@@ -263,7 +263,7 @@ static __net_init int skbmod_init_net(struct net *net) ...@@ -263,7 +263,7 @@ static __net_init int skbmod_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, skbmod_net_id); struct tc_action_net *tn = net_generic(net, skbmod_net_id);
return tc_action_net_init(tn, &act_skbmod_ops); return tc_action_net_init(tn, &act_skbmod_ops, net);
} }
static void __net_exit skbmod_exit_net(struct net *net) static void __net_exit skbmod_exit_net(struct net *net)
......
...@@ -322,7 +322,7 @@ static __net_init int tunnel_key_init_net(struct net *net) ...@@ -322,7 +322,7 @@ static __net_init int tunnel_key_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
return tc_action_net_init(tn, &act_tunnel_key_ops); return tc_action_net_init(tn, &act_tunnel_key_ops, net);
} }
static void __net_exit tunnel_key_exit_net(struct net *net) static void __net_exit tunnel_key_exit_net(struct net *net)
......
...@@ -269,7 +269,7 @@ static __net_init int vlan_init_net(struct net *net) ...@@ -269,7 +269,7 @@ static __net_init int vlan_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, vlan_net_id); struct tc_action_net *tn = net_generic(net, vlan_net_id);
return tc_action_net_init(tn, &act_vlan_ops); return tc_action_net_init(tn, &act_vlan_ops, net);
} }
static void __net_exit vlan_exit_net(struct net *net) static void __net_exit vlan_exit_net(struct net *net)
......
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