[Intel-wired-lan][PATCH net v2 2/3] idpf: fix next_to_clean data races
From: Joshua Hay <hidden>
Date: 2026-06-02 17:09:38
Also in:
intel-wired-lan
Subsystem:
intel ethernet drivers, networking drivers, the rest · Maintainers:
Tony Nguyen, Przemek Kitszel, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
As reported by Sashiko [1], IDPF_DESC_UNUSED() evaluates
txq->next_to_clean twice, and next_to_clean can be concurrently updated
by NAPI. next_to_clean can change between evaluations, resulting in a
miscalculated free descriptor count that is larger than the ring
capacity. Consequently, netif_subqueue_maybe_stop() could incorrectly
determine there is room in the queue, bypassing the stop mechanism and
allowing active in-flight descriptors to be overwritten.
This patch is based on commit 9eab46b7cb8d ("e1000: fix data race
between tx_ring->next_to_clean").
Fixes: 6818c4d5b3c2 ("idpf: add splitq start_xmit")
Signed-off-by: Joshua Hay <redacted>
Reviewed-by: Aleksandr Loktionov <redacted>
Link: https://sashiko.dev/#/patchset/20260504-jk-iwl-net-2026-05-04-v1-0-a222a88bd962%40intel.com [1]
---
drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c | 3 ++-
drivers/net/ethernet/intel/idpf/idpf_txrx.c | 9 ++++++---
drivers/net/ethernet/intel/idpf/idpf_txrx.h | 9 ++++++---
3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
index e3ddf18dcbf5..a0e3de3ed0a9 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c@@ -558,7 +558,8 @@ static bool idpf_tx_singleq_clean(struct idpf_tx_queue *tx_q, int napi_budget, } while (likely(budget)); ntc += tx_q->desc_count; - tx_q->next_to_clean = ntc; + /* Sync with IDPF_DESC_UNUSED called from idpf_tx_singleq_frame. */ + smp_store_release(&tx_q->next_to_clean, ntc); *cleaned += ss.packets;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 34fc85cbb3f4..9cc4fbd13313 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c@@ -2073,8 +2073,10 @@ static void idpf_tx_splitq_clean(struct idpf_tx_queue *tx_q, u16 end, struct idpf_tx_buf *tx_buf; if (descs_only) { - /* Bump ring index to mark as cleaned. */ - tx_q->next_to_clean = end; + /* Bump ring index to mark as cleaned and sync with + * IDPF_DESC_UNUSED called from idpf_txq_has_room. + */ + smp_store_release(&tx_q->next_to_clean, end); return; }
@@ -2111,7 +2113,8 @@ static void idpf_tx_splitq_clean(struct idpf_tx_queue *tx_q, u16 end, idpf_tx_splitq_clean_bump_ntc(tx_q, ntc, tx_desc, tx_buf); } - tx_q->next_to_clean = ntc; + /* Sync with IDPF_DESC_UNUSED called from idpf_txq_has_room. */ + smp_store_release(&tx_q->next_to_clean, ntc); } /**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index 4be5b3b6d3ed..8eadc2682c96 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h@@ -119,9 +119,12 @@ do { \ #define IDPF_RXD_EOF_SPLITQ VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_EOF_M #define IDPF_RXD_EOF_SINGLEQ VIRTCHNL2_RX_BASE_DESC_STATUS_EOF_M -#define IDPF_DESC_UNUSED(txq) \ - ((((txq)->next_to_clean > (txq)->next_to_use) ? 0 : (txq)->desc_count) + \ - (txq)->next_to_clean - (txq)->next_to_use - 1) +#define IDPF_DESC_UNUSED(txq) \ +({ \ + unsigned int ntc = smp_load_acquire(&(txq)->next_to_clean); \ + unsigned int ntu = READ_ONCE((txq)->next_to_use); \ + (ntc > ntu ? 0 : (txq)->desc_count) + ntc - ntu - 1; \ +}) #define IDPF_TX_COMPLQ_OVERFLOW_THRESH(txcq) ((txcq)->desc_count >> 1) /* Determine the absolute number of completions pending, i.e. the number of
--
2.39.2