Commit c0fd0fe7 authored by Yufan Chen's avatar Yufan Chen Committed by Jakub Kicinski
Browse files

net: ftgmac100: fix ring allocation unwind on open failure



ftgmac100_alloc_rings() allocates rx_skbs, tx_skbs, rxdes, txdes, and
rx_scratch in stages. On intermediate failures it returned -ENOMEM
directly, leaking resources allocated earlier in the function.

Rework the failure path to use staged local unwind labels and free
allocated resources in reverse order before returning -ENOMEM. This
matches common netdev allocation cleanup style.

Fixes: d72e01a0 ("ftgmac100: Use a scratch buffer for failed RX allocations")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarYufan Chen <yufan.chen@linux.dev>
Link: https://patch.msgid.link/20260328163257.60836-1-yufan.chen@linux.dev


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 5dd8025a
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -977,19 +977,19 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
	priv->tx_skbs = kcalloc(MAX_TX_QUEUE_ENTRIES, sizeof(void *),
				GFP_KERNEL);
	if (!priv->tx_skbs)
		return -ENOMEM;
		goto err_free_rx_skbs;

	/* Allocate descriptors */
	priv->rxdes = dma_alloc_coherent(priv->dev,
					 MAX_RX_QUEUE_ENTRIES * sizeof(struct ftgmac100_rxdes),
					 &priv->rxdes_dma, GFP_KERNEL);
	if (!priv->rxdes)
		return -ENOMEM;
		goto err_free_tx_skbs;
	priv->txdes = dma_alloc_coherent(priv->dev,
					 MAX_TX_QUEUE_ENTRIES * sizeof(struct ftgmac100_txdes),
					 &priv->txdes_dma, GFP_KERNEL);
	if (!priv->txdes)
		return -ENOMEM;
		goto err_free_rxdes;

	/* Allocate scratch packet buffer */
	priv->rx_scratch = dma_alloc_coherent(priv->dev,
@@ -997,9 +997,29 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
					      &priv->rx_scratch_dma,
					      GFP_KERNEL);
	if (!priv->rx_scratch)
		return -ENOMEM;
		goto err_free_txdes;

	return 0;

err_free_txdes:
	dma_free_coherent(priv->dev,
			  MAX_TX_QUEUE_ENTRIES *
			  sizeof(struct ftgmac100_txdes),
			  priv->txdes, priv->txdes_dma);
	priv->txdes = NULL;
err_free_rxdes:
	dma_free_coherent(priv->dev,
			  MAX_RX_QUEUE_ENTRIES *
			  sizeof(struct ftgmac100_rxdes),
			  priv->rxdes, priv->rxdes_dma);
	priv->rxdes = NULL;
err_free_tx_skbs:
	kfree(priv->tx_skbs);
	priv->tx_skbs = NULL;
err_free_rx_skbs:
	kfree(priv->rx_skbs);
	priv->rx_skbs = NULL;
	return -ENOMEM;
}

static void ftgmac100_init_rings(struct ftgmac100 *priv)