Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
struct tcf_idrinfo {
	spinlock_t	lock;
	struct idr	action_idr;
	struct net	*net;
};

struct tc_action_ops;
@@ -104,7 +105,7 @@ struct tc_action_net {

static inline
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;

@@ -112,6 +113,7 @@ int tc_action_net_init(struct tc_action_net *tn,
	if (!tn->idrinfo)
		return -ENOMEM;
	tn->ops = ops;
	tn->idrinfo->net = net;
	spin_lock_init(&tn->idrinfo->lock);
	idr_init(&tn->idrinfo->action_idr);
	return err;
+2 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p)
	spin_lock_bh(&idrinfo->lock);
	idr_remove_ext(&idrinfo->action_idr, p->tcfa_index);
	spin_unlock_bh(&idrinfo->lock);
	put_net(idrinfo->net);
	gen_kill_estimator(&p->tcfa_rate_est);
	free_tcf(p);
}
@@ -336,6 +337,7 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
	p->idrinfo = idrinfo;
	p->ops = ops;
	INIT_LIST_HEAD(&p->list);
	get_net(idrinfo->net);
	*a = p;
	return 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -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);

	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)
+1 −1
Original line number Diff line number Diff line
@@ -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);

	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)
+1 −1
Original line number Diff line number Diff line
@@ -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);

	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)
Loading