net_sched: sch_choke: implement lockless choke_dump()
authorEric Dumazet <edumazet@google.com>
Thu, 18 Apr 2024 07:32:38 +0000 (07:32 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 19 Apr 2024 10:34:07 +0000 (11:34 +0100)
Instead of relying on RTNL, choke_dump() can use READ_ONCE()
annotations, paired with WRITE_ONCE() ones in choke_change().

v2: added a WRITE_ONCE(p->Scell_log, Scell_log)
    per Simon feedback in V1
    Removed the READ_ONCE(q->limit) in choke_enqueue()

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/red.h
net/sched/sch_choke.c

index 425364d..802287d 100644 (file)
@@ -233,10 +233,10 @@ static inline void red_set_parms(struct red_parms *p,
        int delta = qth_max - qth_min;
        u32 max_p_delta;
 
-       p->qth_min      = qth_min << Wlog;
-       p->qth_max      = qth_max << Wlog;
-       p->Wlog         = Wlog;
-       p->Plog         = Plog;
+       WRITE_ONCE(p->qth_min, qth_min << Wlog);
+       WRITE_ONCE(p->qth_max, qth_max << Wlog);
+       WRITE_ONCE(p->Wlog, Wlog);
+       WRITE_ONCE(p->Plog, Plog);
        if (delta <= 0)
                delta = 1;
        p->qth_delta    = delta;
@@ -244,7 +244,7 @@ static inline void red_set_parms(struct red_parms *p,
                max_P = red_maxp(Plog);
                max_P *= delta; /* max_P = (qth_max - qth_min)/2^Plog */
        }
-       p->max_P = max_P;
+       WRITE_ONCE(p->max_P, max_P);
        max_p_delta = max_P / delta;
        max_p_delta = max(max_p_delta, 1U);
        p->max_P_reciprocal  = reciprocal_value(max_p_delta);
@@ -257,7 +257,7 @@ static inline void red_set_parms(struct red_parms *p,
        p->target_min = qth_min + 2*delta;
        p->target_max = qth_min + 3*delta;
 
-       p->Scell_log    = Scell_log;
+       WRITE_ONCE(p->Scell_log, Scell_log);
        p->Scell_max    = (255 << Scell_log);
 
        if (stab)
index ea10803..9107201 100644 (file)
@@ -405,8 +405,8 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt,
        } else
                sch_tree_lock(sch);
 
-       q->flags = ctl->flags;
-       q->limit = ctl->limit;
+       WRITE_ONCE(q->flags, ctl->flags);
+       WRITE_ONCE(q->limit, ctl->limit);
 
        red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
                      ctl->Plog, ctl->Scell_log,
@@ -431,15 +431,16 @@ static int choke_init(struct Qdisc *sch, struct nlattr *opt,
 static int choke_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
        struct choke_sched_data *q = qdisc_priv(sch);
+       u8 Wlog = READ_ONCE(q->parms.Wlog);
        struct nlattr *opts = NULL;
        struct tc_red_qopt opt = {
-               .limit          = q->limit,
-               .flags          = q->flags,
-               .qth_min        = q->parms.qth_min >> q->parms.Wlog,
-               .qth_max        = q->parms.qth_max >> q->parms.Wlog,
-               .Wlog           = q->parms.Wlog,
-               .Plog           = q->parms.Plog,
-               .Scell_log      = q->parms.Scell_log,
+               .limit          = READ_ONCE(q->limit),
+               .flags          = READ_ONCE(q->flags),
+               .qth_min        = READ_ONCE(q->parms.qth_min) >> Wlog,
+               .qth_max        = READ_ONCE(q->parms.qth_max) >> Wlog,
+               .Wlog           = Wlog,
+               .Plog           = READ_ONCE(q->parms.Plog),
+               .Scell_log      = READ_ONCE(q->parms.Scell_log),
        };
 
        opts = nla_nest_start_noflag(skb, TCA_OPTIONS);
@@ -447,7 +448,7 @@ static int choke_dump(struct Qdisc *sch, struct sk_buff *skb)
                goto nla_put_failure;
 
        if (nla_put(skb, TCA_CHOKE_PARMS, sizeof(opt), &opt) ||
-           nla_put_u32(skb, TCA_CHOKE_MAX_P, q->parms.max_P))
+           nla_put_u32(skb, TCA_CHOKE_MAX_P, READ_ONCE(q->parms.max_P)))
                goto nla_put_failure;
        return nla_nest_end(skb, opts);