Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net_sched: act_skbmod: use RCU in tcf_skbmod_dump()

Also storing tcf_action into struct tcf_skbmod_params
makes sure there is no discrepancy in tcf_skbmod_act().

No longer block BH in tcf_skbmod_init() when acquiring tcf_lock.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250827125349.3505302-5-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
53df77e7 e97ae742

+13 -14
+1
include/net/tc_act/tc_skbmod.h
··· 12 12 struct tcf_skbmod_params { 13 13 struct rcu_head rcu; 14 14 u64 flags; /*up to 64 types of operations; extend if needed */ 15 + int action; 15 16 u8 eth_dst[ETH_ALEN]; 16 17 u16 eth_type; 17 18 u8 eth_src[ETH_ALEN];
+12 -14
net/sched/act_skbmod.c
··· 27 27 struct tcf_result *res) 28 28 { 29 29 struct tcf_skbmod *d = to_skbmod(a); 30 - int action, max_edit_len, err; 31 30 struct tcf_skbmod_params *p; 31 + int max_edit_len, err; 32 32 u64 flags; 33 33 34 34 tcf_lastuse_update(&d->tcf_tm); 35 35 bstats_update(this_cpu_ptr(d->common.cpu_bstats), skb); 36 36 37 - action = READ_ONCE(d->tcf_action); 38 - if (unlikely(action == TC_ACT_SHOT)) 37 + p = rcu_dereference_bh(d->skbmod_p); 38 + if (unlikely(p->action == TC_ACT_SHOT)) 39 39 goto drop; 40 40 41 41 max_edit_len = skb_mac_header_len(skb); 42 - p = rcu_dereference_bh(d->skbmod_p); 43 42 flags = p->flags; 44 43 45 44 /* tcf_skbmod_init() guarantees "flags" to be one of the following: ··· 84 85 INET_ECN_set_ce(skb); 85 86 86 87 out: 87 - return action; 88 + return p->action; 88 89 89 90 drop: 90 91 qstats_overlimit_inc(this_cpu_ptr(d->common.cpu_qstats)); ··· 192 193 } 193 194 194 195 p->flags = lflags; 195 - 196 + p->action = parm->action; 196 197 if (ovr) 197 - spin_lock_bh(&d->tcf_lock); 198 + spin_lock(&d->tcf_lock); 198 199 /* Protected by tcf_lock if overwriting existing action. */ 199 200 goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); 200 201 p_old = rcu_dereference_protected(d->skbmod_p, 1); ··· 208 209 209 210 rcu_assign_pointer(d->skbmod_p, p); 210 211 if (ovr) 211 - spin_unlock_bh(&d->tcf_lock); 212 + spin_unlock(&d->tcf_lock); 212 213 213 214 if (p_old) 214 215 kfree_rcu(p_old, rcu); ··· 247 248 opt.index = d->tcf_index; 248 249 opt.refcnt = refcount_read(&d->tcf_refcnt) - ref; 249 250 opt.bindcnt = atomic_read(&d->tcf_bindcnt) - bind; 250 - spin_lock_bh(&d->tcf_lock); 251 - opt.action = d->tcf_action; 252 - p = rcu_dereference_protected(d->skbmod_p, 253 - lockdep_is_held(&d->tcf_lock)); 251 + rcu_read_lock(); 252 + p = rcu_dereference(d->skbmod_p); 253 + opt.action = p->action; 254 254 opt.flags = p->flags; 255 255 if (nla_put(skb, TCA_SKBMOD_PARMS, sizeof(opt), &opt)) 256 256 goto nla_put_failure; ··· 267 269 if (nla_put_64bit(skb, TCA_SKBMOD_TM, sizeof(t), &t, TCA_SKBMOD_PAD)) 268 270 goto nla_put_failure; 269 271 270 - spin_unlock_bh(&d->tcf_lock); 272 + rcu_read_unlock(); 271 273 return skb->len; 272 274 nla_put_failure: 273 - spin_unlock_bh(&d->tcf_lock); 275 + rcu_read_unlock(); 274 276 nlmsg_trim(skb, b); 275 277 return -1; 276 278 }