Thank you.

It seems we need to handle two additional early exits from the loop when 
hn_flush_txagg(), something like this?

diff --git a/drivers/net/netvsc/hn_rxtx.c b/drivers/net/netvsc/hn_rxtx.c
   index 72dab26ede..example 100644
   --- a/drivers/net/netvsc/hn_rxtx.c
   +++ b/drivers/net/netvsc/hn_rxtx.c
   @@ -1589,8 +1589,10 @@ hn_xmit_pkts(void *ptxq, struct rte_mbuf **tx_pkts, 
uint16_t nb_pkts)
                        if (txq->agg_pktleft == 0 ||
                            RTE_ALIGN(pkt_size, txq->agg_align) > 
txq->agg_szleft) {
   -                            if (hn_flush_txagg(txq, &need_sig))
   +                            if (hn_flush_txagg(txq, &need_sig)) {
   +                                    hn_txd_put(txq, txd);
                                        goto fail;
   +                            }
                        }


                        pkt = hn_try_txagg(hv, txq, txd, pkt_size);
   -                    if (unlikely(!pkt))
   +                    if (unlikely(!pkt)) {
   +                            hn_txd_put(txq, txd);
                                break;
   +                    }

                        hn_encap(pkt, queue_id, m);
   @@ -1611,8 +1615,10 @@ hn_xmit_pkts(void *ptxq, struct rte_mbuf **tx_pkts, 
uint16_t nb_pkts)
                } else {
                        /* Send any outstanding packets in buffer */
   -                    if (txq->agg_txd && hn_flush_txagg(txq, &need_sig))
   +                    if (txq->agg_txd && hn_flush_txagg(txq, &need_sig)) {
   +                            hn_txd_put(txq, txd);
                                goto fail;
   +                    }

                        pkt = txd->rndis_pkt;


> -----Original Message-----
> From: Stephen Hemminger <[email protected]>
> Sent: Wednesday, February 18, 2026 5:45 PM
> To: [email protected]
> Cc: Stephen Hemminger <[email protected]>; [email protected];
> Long Li <[email protected]>; Wei Hu <[email protected]>; Haiyang
> Zhang <[email protected]>
> Subject: [EXTERNAL] [RFT] net/netvsc: fix txd leak on chimney buffer alloc
> failure
> 
> Audit of tx_pkt_burst() code path in drivers found this related bug.
> 
> When hn_try_txagg() fails because hn_chim_alloc() cannot allocate a chimney
> buffer slot, it returns NULL without freeing the txd descriptor that was 
> obtained
> earlier from the txd pool. The caller then breaks out of the transmit loop
> without returning the txd either.
> 
> Each occurrence leaks one txd descriptor. Under sustained chimney buffer
> pressure this eventually exhausts the txd pool and blocks all transmit on the
> queue.
> 
> Add hn_txd_put() before the break to return the txd to the pool.
> 
> Fixes: 4e9c73e96e83 ("net/netvsc: add Hyper-V network device")
> Cc: [email protected]
> 
> Signed-off-by: Stephen Hemminger <[email protected]>
> ---
>  drivers/net/netvsc/hn_rxtx.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/netvsc/hn_rxtx.c b/drivers/net/netvsc/hn_rxtx.c index
> 72dab26ede..3fc54e76b9 100644
> --- a/drivers/net/netvsc/hn_rxtx.c
> +++ b/drivers/net/netvsc/hn_rxtx.c
> @@ -1595,8 +1595,10 @@ hn_xmit_pkts(void *ptxq, struct rte_mbuf
> **tx_pkts, uint16_t nb_pkts)
> 
> 
>                       pkt = hn_try_txagg(hv, txq, txd, pkt_size);
> -                     if (unlikely(!pkt))
> +                     if (unlikely(!pkt)) {
> +                             hn_txd_put(txq, txd);
>                               break;
> +                     }
> 
>                       hn_encap(pkt, queue_id, m);
>                       hn_append_to_chim(txq, pkt, m);
> --
> 2.51.0

Reply via email to