From: Mingming Cao <mmc@linux.ibm.com>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, kuba@kernel.org, edumazet@google.com,
pabeni@redhat.com, andrew+netdev@lunn.ch, nnac123@linux.ibm.com,
maddy@linux.ibm.com, mpe@ellerman.id.au,
linuxppc-dev@lists.ozlabs.org, haren@linux.ibm.com,
ricklind@linux.ibm.com, davemarq@linux.ibm.com,
bjking1@linux.ibm.com, shaik.abdulla1@ibm.com,
Mingming Cao <mmc@linux.ibm.com>
Subject: [PATCH net-next v5 06/15] ibmveth: Refactor TX resource allocation in open/close paths
Date: Fri, 14 Aug 2026 00:36:33 -0700 [thread overview]
Message-ID: <20260814073642.24630-7-mmc@linux.ibm.com> (raw)
In-Reply-To: <20260814073642.24630-1-mmc@linux.ibm.com>
Same story as the RX refactor: pull TX LTB alloc/free out of open/close
into helpers and wire them in this patch.
ibmveth_alloc_tx_resources()
ibmveth_free_tx_resources()
They wrap the existing per-queue allocate_tx_ltb() / free_tx_ltb()
primitives. alloc_tx_resources() allocates every TX queue and unwinds
partial failure itself; free_tx_resources() walks real_num_tx_queues.
The helpers remove dependence on shared open/close loop indices and
match the RX helper structure. TX was already multi-queue capable via
ethtool -L.
Also tighten TX LTB lifetime: free_tx_ltb() keys off tx_ltb_ptr[]
presence (not a dma==0 sentinel) and clears tx_ltb_dma[] after unmap;
allocate_tx_ltb() clears tx_ltb_dma[] after DMA-map failure.
Move TX LTB allocation to the end of open(), after LAN registration,
RX pools, RX interrupt setup, and the initial replenish kick. A late
alloc_tx_resources() failure jumps to out_cleanup_rx_interrupts and
must not call free_tx_resources() again: alloc already freed any
partial TX LTBs. start_xmit() bails if tx_ltb_ptr[] is gone so RX can
be live while TX LTB alloc still runs (and so close/failed-reopen with
IFF_UP set cannot UAF).
After LAN registration, open-fail teardown frees the logical LAN before
tearing down RX pool DMA (intentional safer order than leaving the LAN
registered while unmapping RX memory).
close() quiesces TX with netif_tx_disable() (stop_all_queues does not
wait for in-flight ndo_start_xmit), then frees LTBs after
h_free_logical_lan() via free_tx_resources() - required because direct
close() callers bypass synchronize_net().
Signed-off-by: Mingming Cao <mmc@linux.ibm.com>
Reviewed-by: Dave Marquardt <davemarq@linux.ibm.com>
Tested-by: Shaik Abdulla <shaik.abdulla1@ibm.com>
---
Changes in v5:
- Quiesce TX with netif_tx_disable before free (stop_all_queues does not
wait for in-flight xmit); free LTBs after h_free_logical_lan - direct
close() callers bypass synchronize_net()
- Guard start_xmit if tx_ltb_ptr gone so open can leave RX live while TX
LTB alloc still runs (also covers close/failed-reopen with IFF_UP set)
- Drop fake mid-open TX-leak / Fixes: motivation; reword as helper
extraction matching RX (shared loop-index independence)
- Free TX LTB by pointer presence (drop dma==0 sentinel; dma_mapping_error
already cleared the slot on map failure)
- Document intentional open-fail LAN-first unwind (free_lan before RX
pool/DMA teardown) rather than leaving it silent in a TX-only refactor
- Drop drive-by blank-line cosmetics (header / start_xmit)
Changes in v4:
- Introduce the TX resource helpers in the same patch that wires their
first open/close callers.
- Do not free TX LTBs again after a failed alloc_tx_resources();
harden free_tx_ltb() against unset slots.
- Move TX allocation after RX IRQ setup / replenish kick so open()
failure unwind no longer depends on a shared loop index (also fixes
a mid-open TX LTB leak).
drivers/net/ethernet/ibm/ibmveth.c | 98 +++++++++++++++++++++++-------
1 file changed, 75 insertions(+), 23 deletions(-)
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 99eeb6ef51bf..b39e8c53cbfd 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1183,8 +1183,12 @@ static int ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter,
static void ibmveth_free_tx_ltb(struct ibmveth_adapter *adapter, int idx)
{
+ if (!adapter->tx_ltb_ptr[idx])
+ return;
+
dma_unmap_single(&adapter->vdev->dev, adapter->tx_ltb_dma[idx],
adapter->tx_ltb_size, DMA_TO_DEVICE);
+ adapter->tx_ltb_dma[idx] = 0;
kfree(adapter->tx_ltb_ptr[idx]);
adapter->tx_ltb_ptr[idx] = NULL;
}
@@ -1207,12 +1211,54 @@ static int ibmveth_allocate_tx_ltb(struct ibmveth_adapter *adapter, int idx)
"unable to DMA map tx long term buffer\n");
kfree(adapter->tx_ltb_ptr[idx]);
adapter->tx_ltb_ptr[idx] = NULL;
+ adapter->tx_ltb_dma[idx] = 0;
return -ENOMEM;
}
return 0;
}
+/**
+ * ibmveth_alloc_tx_resources - Allocate TX resources for all queues
+ * @adapter: ibmveth adapter structure
+ *
+ * Allocates TX Long Term Buffers (LTBs) for all TX queues.
+ *
+ * Return: 0 on success, -ENOMEM on failure
+ */
+static int ibmveth_alloc_tx_resources(struct ibmveth_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i;
+
+ for (i = 0; i < netdev->real_num_tx_queues; i++) {
+ if (ibmveth_allocate_tx_ltb(adapter, i))
+ goto err_free_ltbs;
+ }
+
+ return 0;
+
+err_free_ltbs:
+ while (--i >= 0)
+ ibmveth_free_tx_ltb(adapter, i);
+ return -ENOMEM;
+}
+
+/**
+ * ibmveth_free_tx_resources - Free TX resources for all queues
+ * @adapter: ibmveth adapter structure
+ *
+ * Frees TX Long Term Buffers (LTBs) for all TX queues.
+ */
+static void ibmveth_free_tx_resources(struct ibmveth_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i;
+
+ for (i = 0; i < netdev->real_num_tx_queues; i++)
+ ibmveth_free_tx_ltb(adapter, i);
+}
+
static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter,
union ibmveth_buf_desc rxq_desc, u64 mac_address)
{
@@ -1263,12 +1309,6 @@ static int ibmveth_open(struct net_device *netdev)
if (rc)
goto out_free_filter_list;
- rc = -ENOMEM;
- for (i = 0; i < netdev->real_num_tx_queues; i++) {
- if (ibmveth_allocate_tx_ltb(adapter, i))
- goto out_free_tx_ltb;
- }
-
mac_address = ether_addr_to_u64(netdev->dev_addr);
rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
@@ -1290,24 +1330,24 @@ 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;
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);
adapter->opened = true;
@@ -1315,11 +1355,14 @@ static int ibmveth_open(struct net_device *netdev)
return 0;
-out_free_buffer_pools:
+out_cleanup_rx_interrupts:
+ ibmveth_cleanup_rx_interrupts(adapter);
+out_unregister_lan:
+ do {
+ lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+ } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
ibmveth_free_buffer_pools(adapter);
-out_free_tx_ltb:
- while (--i >= 0)
- ibmveth_free_tx_ltb(adapter, i);
+out_free_queue_mem:
ibmveth_cleanup_rx_resources(adapter);
out_free_filter_list:
ibmveth_free_filter_list(adapter);
@@ -1331,7 +1374,6 @@ static int ibmveth_close(struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev_priv(netdev);
long lpar_rc;
- int i;
/* Gate on opened, not IFF_UP: pool_store/change_mtu close+open can
* leave IFF_UP set after a failed reopen.
@@ -1343,7 +1385,10 @@ static int ibmveth_close(struct net_device *netdev)
netdev_dbg(netdev, "close starting\n");
- netif_tx_stop_all_queues(netdev);
+ /* Disable and wait for in-flight ndo_start_xmit (stop_all_queues
+ * alone does not). Direct close() callers bypass synchronize_net().
+ */
+ netif_tx_disable(netdev);
ibmveth_cleanup_rx_interrupts(adapter);
/* Wait for softirq/poll that already passed shutdown checks. */
@@ -1359,13 +1404,14 @@ static int ibmveth_close(struct net_device *netdev)
"h_free_logical_lan failed with %lx, continuing\n",
lpar_rc);
}
+ /* Free TX LTBs after quiesce and after H_FREE_LOGICAL_LAN so xmit
+ * cannot touch unmapped bounce buffers while the LAN is live.
+ */
+ ibmveth_free_tx_resources(adapter);
ibmveth_free_buffer_pools(adapter);
ibmveth_cleanup_rx_resources(adapter);
ibmveth_free_filter_list(adapter);
- for (i = 0; i < netdev->real_num_tx_queues; i++)
- ibmveth_free_tx_ltb(adapter, i);
-
netdev_dbg(netdev, "close complete\n");
return 0;
@@ -1789,6 +1835,12 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
int i, queue_num = skb_get_queue_mapping(skb);
unsigned long mss = 0;
+ /* Close / failed reopen can free LTBs while IFF_UP is still set. */
+ if (unlikely(!adapter->tx_ltb_ptr[queue_num])) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
if (ibmveth_is_packet_unsupported(skb, netdev))
goto out;
/* veth can't checksum offload UDP */
--
2.50.1 (Apple Git-155)
next prev parent reply other threads:[~2026-08-14 7:38 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 7:36 [PATCH net-next v5 00/15] ibmveth: Add multi-queue RX support Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 01/15] ibmveth: Add MQ RX hypercall wrappers and call definitions Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 02/15] ibmveth: Prepare MQ RX adapter data structures Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 03/15] ibmveth: Refactor RX resource allocation for MQ RX bring-up Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 04/15] ibmveth: Refactor buffer pool management for per-queue MQ RX Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 05/15] ibmveth: Refactor RX interrupt control for MQ RX queues Mingming Cao
2026-08-14 7:36 ` Mingming Cao [this message]
2026-08-14 7:36 ` [PATCH net-next v5 07/15] ibmveth: Add RX queue register helpers for MQ Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 08/15] ibmveth: Add queue-aware RX buffer submit helper " Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 09/15] ibmveth: Harden RX poll path with helpers Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 10/15] ibmveth: Enable multi-queue RX receive path Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 11/15] ibmveth: Add per-queue RX and TX statistics collection Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 12/15] ibmveth: Report MQ-aware RX counts in ethtool get_channels Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 13/15] ibmveth: Expose per-queue buffer pool details via debugfs Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 14/15] ibmveth: Implement incremental MQ RX queue resize Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 15/15] ibmveth: Wire ethtool set_channels to " Mingming Cao
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=20260814073642.24630-7-mmc@linux.ibm.com \
--to=mmc@linux.ibm.com \
--cc=andrew+netdev@lunn.ch \
--cc=bjking1@linux.ibm.com \
--cc=davem@davemloft.net \
--cc=davemarq@linux.ibm.com \
--cc=edumazet@google.com \
--cc=haren@linux.ibm.com \
--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=nnac123@linux.ibm.com \
--cc=pabeni@redhat.com \
--cc=ricklind@linux.ibm.com \
--cc=shaik.abdulla1@ibm.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.