From: mingming cao <mmc@linux.ibm.com>
To: Jakub Kicinski <kuba@kernel.org>
Cc: netdev@vger.kernel.org, horms@kernel.org, bjking1@linux.ibm.com,
haren@linux.ibm.com, ricklind@linux.ibm.com, edumazet@google.com,
pabeni@redhat.com, davem@davemloft.net,
linuxppc-dev@lists.ozlabs.org, maddy@linux.ibm.com,
mpe@ellerman.id.au, simon.horman@corigine.com,
shaik.abdulla1@ibm.com, davemarq@linux.ibm.com
Subject: Re: [PATCH net-next v4 06/14] ibmveth: Refactor TX resource allocation in open/close paths
Date: Mon, 10 Aug 2026 15:21:04 -0700 [thread overview]
Message-ID: <4650ce59-eeec-49f9-bd05-c06904fe9f62@linux.ibm.com> (raw)
In-Reply-To: <20260806183705.3175367-1-kuba@kernel.org>
On 8/6/26 11:37 AM, Jakub Kicinski wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> ibmveth: Refactor TX resource allocation in open/close paths
>
> This moves the per-queue TX long term buffer alloc/free loops out of
> ibmveth_open() and ibmveth_close() into ibmveth_alloc_tx_resources() and
> ibmveth_free_tx_resources(), relocates the TX allocation to the end of
> open(), and reworks the open() error unwind labels.
>
> A few questions on the changelog and on the new ordering below.
Hi Jakub,
Thanks for the review.
> [Severity: Medium]
> The changelog says:
>
> That also retires a mid-open TX leak where the old index-based
> while (--i) free could skip successfully allocated LTBs.
>
> Is that leak real? In the parent commit the TX loop re-initializes the
> shared index before allocating anything:
>
> rc = -ENOMEM;
> for (i = 0; i < netdev->real_num_tx_queues; i++) {
> if (ibmveth_allocate_tx_ltb(adapter, i))
> goto out_free_tx_ltb;
> }
>
> and nothing between that loop and the later gotos (mac_address/rxq_desc
> setup, ibmveth_register_logical_lan(), ibmveth_alloc_buffer_pools(),
> ibmveth_setup_rx_interrupts()) reassigns i. On every path that reaches
> out_free_tx_ltb, i is either the failing index or real_num_tx_queues, so
> while (--i >= 0) frees exactly what was allocated. Paths taken before the
> TX loop jump to out_free_filter_list, which is below the TX label.
>
> The new helper also uses the same index-based unwind that the changelog
> calls broken:
>
> err_free_ltbs:
> while (--i >= 0)
> ibmveth_free_tx_ltb(adapter, i);
>
> Could this paragraph be dropped or reworded to describe the actual
> motivation (removing the dependence on a shared loop index and matching
> the RX helpers)? As written it reads like a leak fix that a stable
> maintainer might want to backport, and there is no Fixes: tag.
Agreed for this patch. I will drop that paragraph and reword the
motivation in terms of helper extraction, avoiding dependence on shared
open-path loop state, and matching the RX helper structure, rather than
presenting it as a leak fix here.
>> diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
>> index 664169c4d27a4..131c1a61d9e7e 100644
>> --- a/drivers/net/ethernet/ibm/ibmveth.c
>> +++ b/drivers/net/ethernet/ibm/ibmveth.c
>> @@ -1077,8 +1077,14 @@ static int ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter,
>>
>> static void ibmveth_free_tx_ltb(struct ibmveth_adapter *adapter, int idx)
>> {
>> - dma_unmap_single(&adapter->vdev->dev, adapter->tx_ltb_dma[idx],
>> - adapter->tx_ltb_size, DMA_TO_DEVICE);
>> + if (!adapter->tx_ltb_ptr[idx])
>> + return;
>> +
>> + if (adapter->tx_ltb_dma[idx]) {
>> + dma_unmap_single(&adapter->vdev->dev, adapter->tx_ltb_dma[idx],
>> + adapter->tx_ltb_size, DMA_TO_DEVICE);
>> + adapter->tx_ltb_dma[idx] = 0;
>> + }
> [Severity: Low]
> Is the inner test on tx_ltb_dma[idx] wanted here? It treats DMA address 0
> as a "not mapped" sentinel, and the only architecturally valid check for a
> bad handle is dma_mapping_error() at map time. If a mapping ever
> legitimately returned IOVA 0, the TCE entry would leak while kfree() below
> still released the buffer.
>
> On pseries this cannot happen today, since
> arch/powerpc/kernel/iommu.c:iommu_table_reserve_pages() reserves entry 0:
>
> if (tbl->it_offset == 0)
> set_bit(0, tbl->it_map);
>
> The test also looks redundant: ibmveth_allocate_tx_ltb() already kfree()s
> the buffer and clears tx_ltb_ptr[idx] on dma_mapping_error(), so
> tx_ltb_ptr[idx] != NULL already implies a valid mapping and the new early
> return covers the stated "safe on an unallocated slot" goal. Would
> dropping the zero test and relying on the pointer check be simpler?
Agreed. In v5 I will just key the free path off allocation state instead
of treating DMA address 0 as a sentinel.
>> kfree(adapter->tx_ltb_ptr[idx]);
>> adapter->tx_ltb_ptr[idx] = NULL;
>> }
> [ ... ]
>
>> @@ -1184,35 +1226,38 @@ static int ibmveth_open(struct net_device *netdev)
>> rxq_desc.desc,
>> mac_address);
>> rc = -ENONET;
>> - goto out_free_tx_ltb;
>> + goto out_free_queue_mem;
>> }
>>
>> rc = ibmveth_alloc_buffer_pools(adapter);
>> if (rc)
>> - goto out_free_tx_ltb;
>> + goto out_unregister_lan;
> [Severity: Low]
> This changes hypervisor-visible behaviour on an RX error path, which the
> changelog does not mention while stating "there is no MQ RX behaviour
> change here".
>
> In the parent commit an ibmveth_alloc_buffer_pools() failure went to
> out_free_tx_ltb and then to ibmveth_cleanup_rx_resources(), leaving the
> logical LAN registered with PHYP while the RX ring was freed and the
> buffer list unmapped. With the new label the h_free_logical_lan() loop
> runs first, which is the safer order.
>
> Is this an intentional fix folded into a TX-only refactor? If so, could
> it be split out with its own changelog text (the next patch in the series
> reorders open() so this path disappears entirely, so the fix becomes hard
> to find later).
Yes, that change was intentional, and I agree it needs to be called out
more clearly. Freeing the LAN before tearing down the RX resources is
the safer order on that failure path, so in v5 I will say that
explicitly in the changelog instead of letting it read like a pure TX
refactor.
>>
>> rc = ibmveth_setup_rx_interrupts(adapter);
>> - if (rc) {
>> - do {
>> - lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
>> - } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
>> - goto out_free_buffer_pools;
>> - }
>> + if (rc)
>> + goto out_unregister_lan;
>>
>> netdev_dbg(netdev, "initial replenish cycle\n");
>> ibmveth_schedule_rx_queue(adapter, 0);
>>
>> + rc = ibmveth_alloc_tx_resources(adapter);
>> + if (rc)
>> + goto out_cleanup_rx_interrupts;
>> +
>> netif_tx_start_all_queues(netdev);
> [ ... ]
>
>> @@ -1224,13 +1269,13 @@ static int ibmveth_close(struct net_device *netdev)
>> {
>> struct ibmveth_adapter *adapter = netdev_priv(netdev);
>> long lpar_rc;
>> - int i;
>>
>> netdev_dbg(netdev, "close starting\n");
>>
>> netif_tx_stop_all_queues(netdev);
>>
>> /* PHYP mask + napi_disable + free_irq live in cleanup_rx_interrupts */
>> + ibmveth_free_tx_resources(adapter);
>> ibmveth_cleanup_rx_interrupts(adapter);
> [Severity: High]
> Can a transmit already in flight write into the TX LTB after it has been
> unmapped and freed here?
>
> netif_tx_stop_all_queues() only sets __QUEUE_STATE_DRV_XOFF. It does not
> take __netif_tx_lock and does not wait for an ndo_start_xmit that is
> already running on another CPU (netif_tx_disable() would). ibmveth_close()
> is also called directly, bypassing dev_close() -> dev_deactivate_many()
> and its synchronize_net() / some_qdisc_is_busy() wait, from:
>
> ibmveth_set_csum_offload()
> ibmveth_set_tso()
> ibmveth_change_mtu()
> veth_pool_store()
>
> all of which do:
>
> if (netif_running(dev)) {
> restart = 1;
> ibmveth_close(dev);
> }
>
> So a transmitter that already passed netif_xmit_stopped() can be inside
> ibmveth_start_xmit(), which copies into the LTB with no NULL check and no
> lock:
>
> memcpy(adapter->tx_ltb_ptr[queue_num], skb->data, skb_headlen(skb));
> ...
> memcpy(adapter->tx_ltb_ptr[queue_num] + total_bytes,
> skb_frag_address_safe(frag), skb_frag_size(frag));
> ...
> desc.fields.address = adapter->tx_ltb_dma[queue_num];
>
> while ibmveth_free_tx_ltb() concurrently does:
>
> dma_unmap_single(...);
> adapter->tx_ltb_dma[idx] = 0;
> kfree(adapter->tx_ltb_ptr[idx]);
> adapter->tx_ltb_ptr[idx] = NULL;
>
> That looks like either a write of up to tx_ltb_size bytes into freed heap
> memory, or a NULL dereference on the cleared pointer.
>
> A second question on the same move: the DMA unmap now happens before the
> h_free_logical_lan() loop below, so a racing ibmveth_send() can hand PHYP
> a descriptor whose address is 0 or an already unmapped TCE while the
> logical LAN is still registered. Previously the TX LTBs were freed at the
> very end of close(), after h_free_logical_lan(), free_irq()/napi_disable()
> and the buffer pool teardown, which incidentally left a large gap between
> the XOFF and the free. Was the inversion intended?
>
> Would keeping ibmveth_free_tx_resources() after the h_free_logical_lan()
> loop, switching to netif_tx_disable(), and/or adding an
>
> if (unlikely(!adapter->tx_ltb_ptr[queue_num]))
>
> bail-out in ibmveth_start_xmit() be preferable?
Agreed. This is the main correctness issue in the patch. In v5 I will
quiesce TX before freeing the LTB state and move the TX free back after
`h_free_logical_lan()`. I will also add the `!tx_ltb_ptr[q]` guard in
`ibmveth_start_xmit()`, but I think it reads better as the answer to
your open-side mirror-window point below.
> The last one would also
> cover the mirror window that the new open() ordering creates, where the
> LAN is registered and RX interrupts/NAPI are live while tx_ltb_ptr[] is
> still NULL during the sleeping GFP_KERNEL allocation in
> ibmveth_alloc_tx_resources():
>
> ibmveth_schedule_rx_queue(adapter, 0);
>
> rc = ibmveth_alloc_tx_resources(adapter);
Yes, and that is how I plan to cover the open-side window for this
series. `netif_tx_start_all_queues()` still runs only after
`ibmveth_alloc_tx_resources()` succeeds, and the `!tx_ltb_ptr[q]` guard
in `ibmveth_start_xmit()` closes the remaining mirror case without
needing to reorder open in this patch.
>
> [Severity: Low]
> The comment about PHYP mask, napi_disable and free_irq now sits above
> ibmveth_free_tx_resources() instead of above the
> ibmveth_cleanup_rx_interrupts() call it describes, so it reads as
> documentation of the TX free. Could it move below the TX free?
Agreed. I will clean up that misplaced comment so the code and
commentary match.
Thanks,
Mingming
>
>>
>> do {
> [ ... ]
>
>> - for (i = 0; i < netdev->real_num_tx_queues; i++)
>> - ibmveth_free_tx_ltb(adapter, i);
>> -
>> netdev_dbg(netdev, "close complete\n");
>>
>> return 0;
next prev parent reply other threads:[~2026-08-10 22:21 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-31 0:47 [PATCH net-next v4 00/14] ibmveth: Add multi-queue RX support Mingming Cao
2026-07-31 0:47 ` [PATCH net-next v4 01/14] ibmveth: Add MQ RX hypercall wrappers and call definitions Mingming Cao
2026-08-06 18:36 ` Jakub Kicinski
2026-08-10 19:19 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 02/14] ibmveth: Prepare MQ RX adapter data structures Mingming Cao
2026-08-06 18:36 ` Jakub Kicinski
2026-08-10 19:40 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 03/14] ibmveth: Refactor RX resource allocation for MQ RX bring-up Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-10 20:44 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 04/14] ibmveth: Refactor buffer pool management for per-queue MQ RX Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-10 21:11 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 05/14] ibmveth: Refactor RX interrupt control for MQ RX queues Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-10 22:07 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 06/14] ibmveth: Refactor TX resource allocation in open/close paths Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-10 22:21 ` mingming cao [this message]
2026-07-31 0:47 ` [PATCH net-next v4 07/14] ibmveth: Add RX queue register/deregister helpers for MQ Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-10 22:32 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 08/14] ibmveth: Add queue-aware RX buffer submit helper " Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-10 22:51 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 09/14] ibmveth: Enable multi-queue RX receive path Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-10 23:28 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 10/14] ibmveth: Add per-queue RX and TX statistics collection Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-10 23:42 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 11/14] ibmveth: Expose per-queue buffer pool details via debugfs Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-10 23:53 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 12/14] ibmveth: Implement incremental MQ RX queue resize Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-11 1:21 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 13/14] ibmveth: Wire ethtool set_channels to " Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-11 2:47 ` mingming cao
2026-07-31 0:47 ` [PATCH net-next v4 14/14] ibmveth: Fix MQ RX poll and shutdown hangs after " Mingming Cao
2026-08-06 18:37 ` Jakub Kicinski
2026-08-06 18:49 ` Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4650ce59-eeec-49f9-bd05-c06904fe9f62@linux.ibm.com \
--to=mmc@linux.ibm.com \
--cc=bjking1@linux.ibm.com \
--cc=davem@davemloft.net \
--cc=davemarq@linux.ibm.com \
--cc=edumazet@google.com \
--cc=haren@linux.ibm.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=maddy@linux.ibm.com \
--cc=mpe@ellerman.id.au \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=ricklind@linux.ibm.com \
--cc=shaik.abdulla1@ibm.com \
--cc=simon.horman@corigine.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.