mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net_sched: act_connmark: use RCU in tcf_connmark_dump()
Also storing tcf_action into struct tcf_connmark_parms makes sure there is no discrepancy in tcf_connmark_act(). Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20250709090204.797558-3-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
		
							parent
							
								
									30dbb2d0e1
								
							
						
					
					
						commit
						0d75287770
					
				
					 2 changed files with 11 additions and 8 deletions
				
			
		| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
struct tcf_connmark_parms {
 | 
					struct tcf_connmark_parms {
 | 
				
			||||||
	struct net *net;
 | 
						struct net *net;
 | 
				
			||||||
	u16 zone;
 | 
						u16 zone;
 | 
				
			||||||
 | 
						int action;
 | 
				
			||||||
	struct rcu_head rcu;
 | 
						struct rcu_head rcu;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,7 +88,7 @@ TC_INDIRECT_SCOPE int tcf_connmark_act(struct sk_buff *skb,
 | 
				
			||||||
	/* using overlimits stats to count how many packets marked */
 | 
						/* using overlimits stats to count how many packets marked */
 | 
				
			||||||
	tcf_action_inc_overlimit_qstats(&ca->common);
 | 
						tcf_action_inc_overlimit_qstats(&ca->common);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return READ_ONCE(ca->tcf_action);
 | 
						return parms->action;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct nla_policy connmark_policy[TCA_CONNMARK_MAX + 1] = {
 | 
					static const struct nla_policy connmark_policy[TCA_CONNMARK_MAX + 1] = {
 | 
				
			||||||
| 
						 | 
					@ -167,6 +167,8 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		goto release_idr;
 | 
							goto release_idr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nparms->action = parm->action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_bh(&ci->tcf_lock);
 | 
						spin_lock_bh(&ci->tcf_lock);
 | 
				
			||||||
	goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
 | 
						goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
 | 
				
			||||||
	oparms = rcu_replace_pointer(ci->parms, nparms, lockdep_is_held(&ci->tcf_lock));
 | 
						oparms = rcu_replace_pointer(ci->parms, nparms, lockdep_is_held(&ci->tcf_lock));
 | 
				
			||||||
| 
						 | 
					@ -190,20 +192,20 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
 | 
				
			||||||
static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
 | 
					static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
 | 
				
			||||||
				    int bind, int ref)
 | 
									    int bind, int ref)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						const struct tcf_connmark_info *ci = to_connmark(a);
 | 
				
			||||||
	unsigned char *b = skb_tail_pointer(skb);
 | 
						unsigned char *b = skb_tail_pointer(skb);
 | 
				
			||||||
	struct tcf_connmark_info *ci = to_connmark(a);
 | 
						const struct tcf_connmark_parms *parms;
 | 
				
			||||||
	struct tc_connmark opt = {
 | 
						struct tc_connmark opt = {
 | 
				
			||||||
		.index   = ci->tcf_index,
 | 
							.index   = ci->tcf_index,
 | 
				
			||||||
		.refcnt  = refcount_read(&ci->tcf_refcnt) - ref,
 | 
							.refcnt  = refcount_read(&ci->tcf_refcnt) - ref,
 | 
				
			||||||
		.bindcnt = atomic_read(&ci->tcf_bindcnt) - bind,
 | 
							.bindcnt = atomic_read(&ci->tcf_bindcnt) - bind,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct tcf_connmark_parms *parms;
 | 
					 | 
				
			||||||
	struct tcf_t t;
 | 
						struct tcf_t t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_bh(&ci->tcf_lock);
 | 
						rcu_read_lock();
 | 
				
			||||||
	parms = rcu_dereference_protected(ci->parms, lockdep_is_held(&ci->tcf_lock));
 | 
						parms = rcu_dereference(ci->parms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opt.action = ci->tcf_action;
 | 
						opt.action = parms->action;
 | 
				
			||||||
	opt.zone = parms->zone;
 | 
						opt.zone = parms->zone;
 | 
				
			||||||
	if (nla_put(skb, TCA_CONNMARK_PARMS, sizeof(opt), &opt))
 | 
						if (nla_put(skb, TCA_CONNMARK_PARMS, sizeof(opt), &opt))
 | 
				
			||||||
		goto nla_put_failure;
 | 
							goto nla_put_failure;
 | 
				
			||||||
| 
						 | 
					@ -212,12 +214,12 @@ static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
 | 
				
			||||||
	if (nla_put_64bit(skb, TCA_CONNMARK_TM, sizeof(t), &t,
 | 
						if (nla_put_64bit(skb, TCA_CONNMARK_TM, sizeof(t), &t,
 | 
				
			||||||
			  TCA_CONNMARK_PAD))
 | 
								  TCA_CONNMARK_PAD))
 | 
				
			||||||
		goto nla_put_failure;
 | 
							goto nla_put_failure;
 | 
				
			||||||
	spin_unlock_bh(&ci->tcf_lock);
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return skb->len;
 | 
						return skb->len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nla_put_failure:
 | 
					nla_put_failure:
 | 
				
			||||||
	spin_unlock_bh(&ci->tcf_lock);
 | 
						rcu_read_unlock();
 | 
				
			||||||
	nlmsg_trim(skb, b);
 | 
						nlmsg_trim(skb, b);
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue