Thread (45 messages) flat view 45 messages, 2 authors, 19m ago

Re: [PATCH net-next v4 03/14] ibmveth: Refactor RX resource allocation for MQ RX bring-up

From: mingming cao <hidden>
Date: 2026-08-10 20:45:08
Also in: netdev

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 RX resource allocation for MQ RX bring-up

This moves the filter list and per-queue RX ring allocation out of
ibmveth_open() into four new helpers, and wires them into both the
open error unwind and ibmveth_close().  Runtime behaviour is meant to
stay single-queue since num_rx_queues is still 1.
Hi Jakub,

Thanks for the review.
quoted
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 8e758362cb263..1007dd95cde02 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -151,6 +151,184 @@ static unsigned int ibmveth_real_max_tx_queues(void)
  	return min(n_cpu, IBMVETH_MAX_QUEUES);
  }
  
+/**
+ * ibmveth_alloc_filter_list - Allocate and map filter list
+ * @adapter: ibmveth adapter structure
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int
+ibmveth_alloc_filter_list(struct ibmveth_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	struct net_device *netdev = adapter->netdev;
+
+	adapter->filter_list_addr = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!adapter->filter_list_addr) {
+		netdev_err(netdev, "unable to allocate filter pages\n");
+		return -ENOMEM;
+	}
+
+	adapter->filter_list_dma = dma_map_single(dev,
+						  adapter->filter_list_addr,
+						  4096, DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, adapter->filter_list_dma)) {
+		netdev_err(netdev, "unable to map filter list pages\n");
+		free_page((unsigned long)adapter->filter_list_addr);
+		adapter->filter_list_addr = NULL;
+		return -ENOMEM;
+	}
[Severity: Medium]

Should this error path also clear adapter->filter_list_dma?  On failure
dma_map_single() has stored DMA_MAPPING_ERROR, which is ~(dma_addr_t)0 and
therefore non-zero, and only filter_list_addr is reset here.
Yes. In v5 I will clear `filter_list_dma` on mapping error, matching the
existing `buffer_list_dma` convention.
The sibling helper added in the same patch does zero the cookie in the
same situation:

	if (dma_mapping_error(dev, adapter->buffer_list_dma[i])) {
		...
		adapter->buffer_list_dma[i] = 0;
		goto err_cleanup;
	}

so the two new helpers appear to disagree on the convention.
quoted
+
+	netdev_dbg(netdev, "filter list @ 0x%p (DMA: 0x%llx)\n",
+		   adapter->filter_list_addr,
+		   (unsigned long long)adapter->filter_list_dma);
+
+	return 0;
+}
+
+/**
+ * ibmveth_free_filter_list - Free filter list resources
+ * @adapter: ibmveth adapter structure
+ */
+static void
+ibmveth_free_filter_list(struct ibmveth_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+
+	if (adapter->filter_list_dma) {
+		dma_unmap_single(dev, adapter->filter_list_dma, 4096,
+				 DMA_BIDIRECTIONAL);
+		adapter->filter_list_dma = 0;
+	}
[Severity: Medium]

Can this unmap the DMA_MAPPING_ERROR sentinel?  ibmveth_free_filter_list()
treats any non-zero filter_list_dma as a live mapping, and the mapping-error
branch of ibmveth_alloc_filter_list() leaves the sentinel behind.

The state looks reachable without dev_close().  ibmveth_set_csum_offload(),
ibmveth_set_tso(), ibmveth_change_mtu() and veth_pool_store() all call
ibmveth_close() and then ibmveth_open() directly while netif_running() is
still true:

	if (netif_running(dev)) {
		restart = 1;
		ibmveth_close(dev);
	}
	...
	if (restart)
		rc2 = ibmveth_open(dev);

If that re-open fails at the dma_mapping_error() check in
ibmveth_alloc_filter_list(), open() returns through the out: label without
calling ibmveth_free_filter_list(), so the adapter is left with
filter_list_addr == NULL and filter_list_dma == DMA_MAPPING_ERROR while the
netdev is still marked running.  A later "ip link set dev ethX down" then
reaches ndo_stop == ibmveth_close() -> ibmveth_free_filter_list() and unmaps
that invalid address.

On pseries the dma_iommu path catches this in iommu_free_check(), which emits
a ratelimited "iommu_free: invalid entry" message and a WARN_ON(1) (a panic
with panic_on_warn set), so no TCE state is changed, but the backtrace is
still user triggerable with CAP_NET_ADMIN plus a mapping failure.

Setting adapter->filter_list_dma = 0 in that error branch, matching
ibmveth_alloc_rx_queues(), would make the guard here reliable.

This is still present unchanged at the end of the series (a3781f4ae789), so
a later patch does not appear to address it.
Yes. The failure path here is:
- `dma_map_single()` fails for the filter page
- open/reopen leaves `filter_list_addr = NULL`
- `filter_list_dma` is still left at `DMA_MAPPING_ERROR`
- a later free path sees a non-zero DMA handle and calls
   `dma_unmap_single()` on the sentinel value

That leads to the later bad unmap/WARN.

In v5 I will free the page and set `adapter->filter_list_dma = 0` on
mapping error while keeping `filter_list_addr = NULL`, so the free path
remains consistent and only unmaps real mappings.
quoted
+
+	if (adapter->filter_list_addr) {
+		free_page((unsigned long)adapter->filter_list_addr);
+		adapter->filter_list_addr = NULL;
+	}
+}
+
[ ... ]
quoted
+		adapter->buffer_list_dma[i] =
+			dma_map_single(dev, adapter->buffer_list_addr[i],
+				       4096, DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(dev, adapter->buffer_list_dma[i])) {
+			netdev_err(netdev,
+				   "unable to map buffer list for queue %d\n",
+				   i);
+			adapter->buffer_list_dma[i] = 0;
+			goto err_cleanup;
+		}
+
[ ... ]
quoted
@@ -627,74 +805,34 @@ static int ibmveth_open(struct net_device *netdev)
  
-	rc = -ENOMEM;
-	adapter->buffer_list_addr[0] = (void *)get_zeroed_page(GFP_KERNEL);
-	if (!adapter->buffer_list_addr[0]) {
-		netdev_err(netdev, "unable to allocate list pages\n");
+	rc = ibmveth_alloc_filter_list(adapter);
+	if (rc)
  		goto out;
-	}
[ ... ]
quoted
@@ -753,26 +889,12 @@ static int ibmveth_open(struct net_device *netdev)
+	ibmveth_cleanup_rx_resources(adapter);
  out_free_filter_list:
-	free_page((unsigned long)adapter->filter_list_addr);
-out_free_buffer_list:
-	free_page((unsigned long)adapter->buffer_list_addr[0]);
+	ibmveth_free_filter_list(adapter);
  out:
  	napi_disable(&adapter->napi[0]);
  	return rc;
[ ... ]
Thanks again for the review,
Mingming

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help