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

Configure Feed

Select the types of activity you want to include in your feed.

net_sched: sch_hhf: annotate data-races in hhf_dump_stats()

hhf_dump_stats() only runs with RTNL held,
reading fields that can be changed in qdisc fast path.

Add READ_ONCE()/WRITE_ONCE() annotations.

Fixes: edb09eb17ed8 ("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/20260421143349.4052215-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
a6edf2cd 9d146a5d

+10 -9
+10 -9
net/sched/sch_hhf.c
··· 198 198 return NULL; 199 199 list_del(&flow->flowchain); 200 200 kfree(flow); 201 - q->hh_flows_current_cnt--; 201 + WRITE_ONCE(q->hh_flows_current_cnt, 202 + q->hh_flows_current_cnt - 1); 202 203 } else if (flow->hash_id == hash) { 203 204 return flow; 204 205 } ··· 227 226 } 228 227 229 228 if (q->hh_flows_current_cnt >= q->hh_flows_limit) { 230 - q->hh_flows_overlimit++; 229 + WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1); 231 230 return NULL; 232 231 } 233 232 /* Create new entry. */ ··· 235 234 if (!flow) 236 235 return NULL; 237 236 238 - q->hh_flows_current_cnt++; 237 + WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1); 239 238 INIT_LIST_HEAD(&flow->flowchain); 240 239 list_add_tail(&flow->flowchain, head); 241 240 ··· 310 309 return WDRR_BUCKET_FOR_NON_HH; 311 310 flow->hash_id = hash; 312 311 flow->hit_timestamp = now; 313 - q->hh_flows_total_cnt++; 312 + WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1); 314 313 315 314 /* By returning without updating counters in q->hhf_arrays, 316 315 * we implicitly implement "shielding" (see Optimization O1). ··· 404 403 return NET_XMIT_SUCCESS; 405 404 406 405 prev_backlog = sch->qstats.backlog; 407 - q->drop_overlimit++; 406 + WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1); 408 407 /* Return Congestion Notification only if we dropped a packet from this 409 408 * bucket. 410 409 */ ··· 687 686 { 688 687 struct hhf_sched_data *q = qdisc_priv(sch); 689 688 struct tc_hhf_xstats st = { 690 - .drop_overlimit = q->drop_overlimit, 691 - .hh_overlimit = q->hh_flows_overlimit, 692 - .hh_tot_count = q->hh_flows_total_cnt, 693 - .hh_cur_count = q->hh_flows_current_cnt, 689 + .drop_overlimit = READ_ONCE(q->drop_overlimit), 690 + .hh_overlimit = READ_ONCE(q->hh_flows_overlimit), 691 + .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt), 692 + .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt), 694 693 }; 695 694 696 695 return gnet_stats_copy_app(d, &st, sizeof(st));