summaryrefslogtreecommitdiff
path: root/net/sched/sch_mqprio_lib.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2026-08-12 08:54:38 +0000
committerJakub Kicinski <kuba@kernel.org>2026-08-17 10:27:48 -0700
commit21ef2d065ad3f0cfbf2ae51260bf962a9fa2c643 (patch)
treeffe5d117639fd24ef2082686cae6cc7d00e00071 /net/sched/sch_mqprio_lib.c
parente6a5d573d24cd375e09d24f136523cb3cc85c9d3 (diff)
downloadlinux-next-21ef2d065ad3f0cfbf2ae51260bf962a9fa2c643.tar.gz
linux-next-21ef2d065ad3f0cfbf2ae51260bf962a9fa2c643.zip
net: prevent torn reads in netdev_tc_txq
netdev_set_tc_queue() (and related helpers/drivers such as netdev_bind_sb_channel_queue(), netdev_reset_tc(), and netdev_unbind_sb_channel()) perform separate 16-bit writes to dev->tc_to_txq[tc].count and dev->tc_to_txq[tc].offset. Furthermore, memset() in netdev_reset_tc() and netdev_unbind_sb_channel() provides no guarantee of performing full 32-bit word stores. Concurrent lockless readers (e.g. skb_tx_hash(), netdev_txq_to_tc(), ixgbe_select_queue(), taprio, mqprio, FPE drivers) can observe torn values where offset and count belong to inconsistent configurations. Redefine struct netdev_tc_txq to embed count and offset inside a union with a u32 combined field, allowing atomic manipulation via READ_ONCE() and WRITE_ONCE(). Update all lockless readers and writers across the kernel to use READ_ONCE() and WRITE_ONCE() on the combined field. Signed-off-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260812085440.3917924-2-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/sched/sch_mqprio_lib.c')
-rw-r--r--net/sched/sch_mqprio_lib.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/net/sched/sch_mqprio_lib.c b/net/sched/sch_mqprio_lib.c
index b3a5572c167b..b60e130c7078 100644
--- a/net/sched/sch_mqprio_lib.c
+++ b/net/sched/sch_mqprio_lib.c
@@ -108,8 +108,11 @@ void mqprio_qopt_reconstruct(struct net_device *dev, struct tc_mqprio_qopt *qopt
memcpy(qopt->prio_tc_map, dev->prio_tc_map, sizeof(qopt->prio_tc_map));
for (tc = 0; tc < num_tc; tc++) {
- qopt->count[tc] = dev->tc_to_txq[tc].count;
- qopt->offset[tc] = dev->tc_to_txq[tc].offset;
+ struct netdev_tc_txq res;
+
+ res.combined = READ_ONCE(dev->tc_to_txq[tc].combined);
+ qopt->count[tc] = res.count;
+ qopt->offset[tc] = res.offset;
}
}
EXPORT_SYMBOL_GPL(mqprio_qopt_reconstruct);