Skip to content

Commit 5154561

Browse files
edumazetkuba-moo
authored andcommitted
net/sched: sch_pie: annotate data-races in pie_dump_stats()
pie_dump_stats() only runs with RTNL held, reading fields that can be changed in qdisc fast path. Add READ_ONCE()/WRITE_ONCE() annotations. Alternative would be to acquire the qdisc spinlock, but our long-term goal is to make qdisc dump operations lockless as much as we can. tc_pie_xstats fields don't need to be latched atomically, otherwise this bug would have been caught earlier. Fixes: edb09eb ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20260421142944.4009941-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent a6edf2c commit 5154561

2 files changed

Lines changed: 20 additions & 20 deletions

File tree

include/net/pie.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars)
104104
vars->dq_tstamp = DTIME_INVALID;
105105
vars->accu_prob = 0;
106106
vars->dq_count = DQCOUNT_INVALID;
107-
vars->avg_dq_rate = 0;
107+
WRITE_ONCE(vars->avg_dq_rate, 0);
108108
}
109109

110110
static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb)

net/sched/sch_pie.c

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
9090
bool enqueue = false;
9191

9292
if (unlikely(qdisc_qlen(sch) >= sch->limit)) {
93-
q->stats.overlimit++;
93+
WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1);
9494
goto out;
9595
}
9696

@@ -104,7 +104,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
104104
/* If packet is ecn capable, mark it if drop probability
105105
* is lower than 10%, else drop it.
106106
*/
107-
q->stats.ecn_mark++;
107+
WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1);
108108
enqueue = true;
109109
}
110110

@@ -114,15 +114,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
114114
if (!q->params.dq_rate_estimator)
115115
pie_set_enqueue_time(skb);
116116

117-
q->stats.packets_in++;
117+
WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1);
118118
if (qdisc_qlen(sch) > q->stats.maxq)
119-
q->stats.maxq = qdisc_qlen(sch);
119+
WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch));
120120

121121
return qdisc_enqueue_tail(skb, sch);
122122
}
123123

124124
out:
125-
q->stats.dropped++;
125+
WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1);
126126
q->vars.accu_prob = 0;
127127
return qdisc_drop_reason(skb, sch, to_free, reason);
128128
}
@@ -267,11 +267,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params,
267267
count = count / dtime;
268268

269269
if (vars->avg_dq_rate == 0)
270-
vars->avg_dq_rate = count;
270+
WRITE_ONCE(vars->avg_dq_rate, count);
271271
else
272-
vars->avg_dq_rate =
272+
WRITE_ONCE(vars->avg_dq_rate,
273273
(vars->avg_dq_rate -
274-
(vars->avg_dq_rate >> 3)) + (count >> 3);
274+
(vars->avg_dq_rate >> 3)) + (count >> 3));
275275

276276
/* If the queue has receded below the threshold, we hold
277277
* on to the last drain rate calculated, else we reset
@@ -381,7 +381,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,
381381
if (delta > 0) {
382382
/* prevent overflow */
383383
if (vars->prob < oldprob) {
384-
vars->prob = MAX_PROB;
384+
WRITE_ONCE(vars->prob, MAX_PROB);
385385
/* Prevent normalization error. If probability is at
386386
* maximum value already, we normalize it here, and
387387
* skip the check to do a non-linear drop in the next
@@ -392,7 +392,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,
392392
} else {
393393
/* prevent underflow */
394394
if (vars->prob > oldprob)
395-
vars->prob = 0;
395+
WRITE_ONCE(vars->prob, 0);
396396
}
397397

398398
/* Non-linear drop in probability: Reduce drop probability quickly if
@@ -403,7 +403,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,
403403
/* Reduce drop probability to 98.4% */
404404
vars->prob -= vars->prob / 64;
405405

406-
vars->qdelay = qdelay;
406+
WRITE_ONCE(vars->qdelay, qdelay);
407407
vars->backlog_old = backlog;
408408

409409
/* We restart the measurement cycle if the following conditions are met
@@ -502,21 +502,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
502502
struct pie_sched_data *q = qdisc_priv(sch);
503503
struct tc_pie_xstats st = {
504504
.prob = q->vars.prob << BITS_PER_BYTE,
505-
.delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) /
505+
.delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) /
506506
NSEC_PER_USEC,
507-
.packets_in = q->stats.packets_in,
508-
.overlimit = q->stats.overlimit,
509-
.maxq = q->stats.maxq,
510-
.dropped = q->stats.dropped,
511-
.ecn_mark = q->stats.ecn_mark,
507+
.packets_in = READ_ONCE(q->stats.packets_in),
508+
.overlimit = READ_ONCE(q->stats.overlimit),
509+
.maxq = READ_ONCE(q->stats.maxq),
510+
.dropped = READ_ONCE(q->stats.dropped),
511+
.ecn_mark = READ_ONCE(q->stats.ecn_mark),
512512
};
513513

514514
/* avg_dq_rate is only valid if dq_rate_estimator is enabled */
515515
st.dq_rate_estimating = q->params.dq_rate_estimator;
516516

517517
/* unscale and return dq_rate in bytes per sec */
518-
if (q->params.dq_rate_estimator)
519-
st.avg_dq_rate = q->vars.avg_dq_rate *
518+
if (st.dq_rate_estimating)
519+
st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) *
520520
(PSCHED_TICKS_PER_SEC) >> PIE_SCALE;
521521

522522
return gnet_stats_copy_app(d, &st, sizeof(st));

0 commit comments

Comments
 (0)