]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: ftgmac100: fix ring allocation unwind on open failure
authorYufan Chen <yufan.chen@linux.dev>
Sat, 28 Mar 2026 16:32:57 +0000 (00:32 +0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 1 Apr 2026 02:38:36 +0000 (19:38 -0700)
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: d72e01a0430f ("ftgmac100: Use a scratch buffer for failed RX allocations")
Cc: stable@vger.kernel.org
Signed-off-by: Yufan Chen <yufan.chen@linux.dev>
Link: https://patch.msgid.link/20260328163257.60836-1-yufan.chen@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/faraday/ftgmac100.c

index 1e91e79c81349d01fe29b88f82d8aaa08a4359e9..6d2fe5c2f3903e107f261b94ace08ed1252f6377 100644 (file)
@@ -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)