mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									b233504033
								
							
						
					
					
						commit
						eec94fdb04
					
				
					 3 changed files with 32 additions and 15 deletions
				
			
		| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue