On Tue, Oct 27, 2026 at 11:40:17AM +0530, Shaiq Wani wrote:
> Observed on ACC while running NVMe traffic tests: under sustained
> high-throughput split-queue Tx, payload bytes on the wire did not
> match what the application submitted, while headers and checksums
> looked valid.
>
> The RS-completion path freed mbufs by walking sw_ring[] slots between
> first_id and the EOP sw_id. RE reclaims and reuses those slots before
> RS lands, so the walker freed mbufs still in flight for later packets,
> whose buffers were then recycled and overwritten mid-DMA.
>
> Track completion ownership in a shadow ring indexed by a software-
> defined compl_tag written to all data descriptors of a packet (per the
> IDPF spec) and echoed back by HW on RS. The shadow ring is the sole
> owner of in-flight mbufs, so sw_ring[].mbuf is no longer touched and
> queue stop/release drain only the shadow ring. Size it to nb_tx_desc
> and stop Tx when the next compl_tag slot is still occupied, since RE
> runs ahead of RS and nb_tx_free does not bound pending completions.
> Allocate it at queue setup (failing on -ENOMEM) and free it on all
> setup-error and release paths.
>
> Remove the now unused ci_tx_entry.first_id field.
>
> The scalar shadow ring and the vector sw_ring_vec are both nb_tx_desc
> arrays of mbuf pointers and are never used at the same time, so place
> the shadow ring in the sw_ring/sw_ring_vec union and allocate a single
> nb_tx_desc-sized ring for split queues instead of the old
> 2 * nb_tx_desc ci_tx_entry ring. This drops split-queue ring storage
> from 40 KiB to 8 KiB per queue at 1024 descriptors and keeps
> ci_tx_queue from growing. Split-queue mbuf drain now follows
> use_vec_entry: the vector path reclaims via ci_txq_release_all_mbufs(),
> the scalar path drains the shadow ring by completion tag.
>
> Fixes: 96cc9b6ea60c ("net/idpf: fix multi-segment mbuf leak in split Tx path")
> Cc: [email protected]
>
> Signed-off-by: Shaiq Wani <[email protected]>
> ---
> v4: fold in the reviewer's split-queue footprint optimisation:
> * Move tx_pending_pkts into the sw_ring/sw_ring_vec union; for split
> queues allocate one nb_tx_desc mbuf-pointer ring instead of the
> 2 * nb_tx_desc ci_tx_entry ring (40 KiB -> 8 KiB at 1024 descs).
> * Drop the now-dead sw_ring next_id chain init in descq_reset and the
> 2 * nb_tx_desc sw_ring sizing; split queues no longer allocate the
> scalar sw_ring/rs_last_id.
> * Set use_vec_entry for split queues and route mbuf drain through it
> (vector: ci_txq_release_all_mbufs(); scalar: shadow-ring drain).
> Rename idpf_qc_split_tx_pending_free() to
> idpf_qc_split_tx_release_mbufs() to reflect it no longer frees the
> ring (freed once via the union pointer).
>
Acked-by: Bruce Richardson <[email protected]>