]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net_sched: act_connmark: use RCU in tcf_connmark_dump()
authorEric Dumazet <edumazet@google.com>
Wed, 9 Jul 2025 09:01:54 +0000 (09:01 +0000)
committerJakub Kicinski <kuba@kernel.org>
Fri, 11 Jul 2025 23:01:15 +0000 (16:01 -0700)
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>
include/net/tc_act/tc_connmark.h
net/sched/act_connmark.c

index e8dd77a967480352f398f654f331016e2733a371..a5ce83f3eea4bfd5ab2b20071738c08f64d1cdf7 100644 (file)
@@ -7,6 +7,7 @@
 struct tcf_connmark_parms {
        struct net *net;
        u16 zone;
+       int action;
        struct rcu_head rcu;
 };
 
index 0fce631e7c91113e5559d12ddc4d0ebeef1237e4..3e89927d711647d75f31c8d80a3ddd102e3d2e36 100644 (file)
@@ -88,7 +88,7 @@ count:
        /* using overlimits stats to count how many packets marked */
        tcf_action_inc_overlimit_qstats(&ca->common);
 out:
-       return READ_ONCE(ca->tcf_action);
+       return parms->action;
 }
 
 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)
                goto release_idr;
 
+       nparms->action = parm->action;
+
        spin_lock_bh(&ci->tcf_lock);
        goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
        oparms = rcu_replace_pointer(ci->parms, nparms, lockdep_is_held(&ci->tcf_lock));
@@ -190,20 +192,20 @@ out_free:
 static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
                                    int bind, int ref)
 {
+       const struct tcf_connmark_info *ci = to_connmark(a);
        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 = {
                .index   = ci->tcf_index,
                .refcnt  = refcount_read(&ci->tcf_refcnt) - ref,
                .bindcnt = atomic_read(&ci->tcf_bindcnt) - bind,
        };
-       struct tcf_connmark_parms *parms;
        struct tcf_t t;
 
-       spin_lock_bh(&ci->tcf_lock);
-       parms = rcu_dereference_protected(ci->parms, lockdep_is_held(&ci->tcf_lock));
+       rcu_read_lock();
+       parms = rcu_dereference(ci->parms);
 
-       opt.action = ci->tcf_action;
+       opt.action = parms->action;
        opt.zone = parms->zone;
        if (nla_put(skb, TCA_CONNMARK_PARMS, sizeof(opt), &opt))
                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,
                          TCA_CONNMARK_PAD))
                goto nla_put_failure;
-       spin_unlock_bh(&ci->tcf_lock);
+       rcu_read_unlock();
 
        return skb->len;
 
 nla_put_failure:
-       spin_unlock_bh(&ci->tcf_lock);
+       rcu_read_unlock();
        nlmsg_trim(skb, b);
        return -1;
 }