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.
Showing the changes to include (1 of 11 files). Show all
Unified · Split
| @@ -832,8 +832,13 @@ struct xps_dev_maps { · 831 unmodified lines | ||
| 832 | 832 | #define TC_BITMASK 15 |
| 833 | 833 | /* HW offloaded queuing disciplines txq count and offset maps */ |
| 834 | 834 | struct netdev_tc_txq { |
| 835 | − u16 count; | |
| 836 | − u16 offset; | |
| 835 | + union { | |
| 836 | + struct { | |
| 837 | + u16 count; | |
| 838 | + u16 offset; | |
| 839 | + }; | |
| 840 | + u32 combined; | |
| 841 | + }; | |
| 837 | 842 | }; |
| 838 | 843 | |
| 839 | 844 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |