> -----Original Message-----
> From: Aleksandr Loktionov <[email protected]> 
> Sent: Friday, August 21, 2026 6:02 AM
> To: [email protected]; Nguyen, Anthony L 
> <[email protected]>; Loktionov, Aleksandr 
> <[email protected]>
> Cc: [email protected]; Simon Horman <[email protected]>
> Subject: [PATCH iwl-net v2 2/2] i40e: avoid resetting BQL state when freeing 
> temporary Tx rings in set_ringparam
> 
> Temporary Tx rings built by i40e_set_ringparam() while resizing descriptor 
> counts are shallow struct copies of the live vsi->tx_rings[] entries, so they 
> retain the same ring->netdev and ring->queue_index as the live ring they are 
> staged to replace.
> 
> If an error path frees one of these clones with
> i40e_free_tx_resources() before i40e_down() has run - either the
> i40e_setup_tx_descriptors() failure unwind loop, or the free_tx: error label 
> - i40e_clean_tx_ring() will call netdev_tx_reset_queue() on 
> txring_txq(tx_ring), which resolves to the *same* netdev_queue as the live > 
> ring because netdev/queue_index alias. That call resets the queue's BQL/dql 
> state (dql_reset(): num_queued = num_completed = 0) while the live ring is 
> still actively transmitting and completing Tx on that same > queue.
> 
> The next time the live ring reports completions for bytes that were queued 
> before the reset, dql_completed() can underflow its own sanity check and hit:
> 
>       BUG_ON(count > num_queued - dql->num_completed);
> 
> i.e. a guaranteed kernel panic, not just a warning, given a queue with 
> outstanding (queued but not yet completed) Tx traffic at the moment the clone 
> is freed.
> 
> Reproduced on real hardware by forcing i40e_setup_tx_descriptors() to fail 
> partway through building tx_rings[] while flooding real Tx traffic on the 
> affected queues:
> 
>     kernel BUG at lib/dynamic_queue_limits.c:99!
>     RIP: 0010:dql_completed+0x285/0x2a0
>     Call Trace:
>      <IRQ>
>      i40e_napi_poll+0x74b/0x1700 [i40e]
>      __napi_poll+0x10a/0x200
>      net_rx_action+0x2f7/0x380
>      handle_softirqs+0xcc/0x270
> 
> Confirmed the same trigger no longer panics with this fix applied, including 
> repeated resize/traffic cycles.
> 
> Clear the clone ring netdev before freeing it in both error paths, so 
> i40e_clean_tx_ring()'s existing `if (!tx_ring->netdev) return;` guard skips 
> the netdev_tx_reset_queue() call for the clone. This mirrors the same > idiom 
> i40e already uses for XDP Tx rings, which also have no netdev_queue of their 
> own (ring->netdev = NULL in i40e_vsi_setup_tx()).
> Only the temporary, about-to-be-freed clone is touched; the live ring in 
> vsi->tx_rings[] keeps its netdev.
> 
> Fixes: 9f65e15b4f98 ("i40e: Move rings from pointer to array to array of 
> pointers")
> Cc: [email protected]
> Cc: Simon Horman <[email protected]>
> Signed-off-by: Aleksandr Loktionov <[email protected]>
> ---
> v2: New patch, split out of the set_ringparam NULL-deref fix (1/2)
>     after review pointed out this related but distinct, older,
>     pre-existing hazard on the same error path. Trimmed the inline
>     comments to one line each.

Tested-by: Alexander Nowlin <[email protected]>

Reply via email to