Re: [PATCH v3 04/11] dmaengine: switchtec-dma: fix channel leak on registration failure
From: Frank Li
Date: Mon Jul 27 2026 - 16:59:29 EST
On Mon, Jul 27, 2026 at 12:15:19PM -0600, Logan Gunthorpe wrote:
> switchtec_dma_chans_release() is called in three places but the
> underlying memory is not freed in all of those places. In order to
> clean this up, introduce a switchtec_dma_chans_free() helper that
> will free the memory.
>
> Ensure each call to switchtec_dma_chans_release() has a corresponding
> switchtec_dma_chans_free() call. (The release in switchtec_dma_remove()
> pairs with the free in switchtec_dma_release()).
>
> swdma_dev->chan_cnt is now set to the number of channels that succeeded
> when one fails to initialise, so switchtec_dma_chans_free() can still
> be used if not all channels succeed in being allocated.
>
> Fixes: 30eba9df76ad ("dmaengine: switchtec-dma: Implement hardware initialization and cleanup")
> Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
> Link: https://lore.kernel.org/dmaengine/20260717223024.9BB8A1F000E9@xxxxxxxxxxxxxxx
> Signed-off-by: Logan Gunthorpe <logang@xxxxxxxxxxxx>
> ---
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
> drivers/dma/switchtec_dma.c | 25 +++++++++++++++----------
> 1 file changed, 15 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/dma/switchtec_dma.c b/drivers/dma/switchtec_dma.c
> index 107769cca772..13efd4189bbb 100644
> --- a/drivers/dma/switchtec_dma.c
> +++ b/drivers/dma/switchtec_dma.c
> @@ -1176,6 +1176,16 @@ static int switchtec_dma_chans_release(struct pci_dev *pdev,
> return 0;
> }
>
> +static void switchtec_dma_chans_free(struct switchtec_dma_dev *swdma_dev)
> +{
> + int i;
> +
> + for (i = 0; i < swdma_dev->chan_cnt; i++)
> + kfree(swdma_dev->swdma_chans[i]);
> +
> + kfree(swdma_dev->swdma_chans);
> +}
> +
> static int switchtec_dma_chans_enumerate(struct switchtec_dma_dev *swdma_dev,
> struct pci_dev *pdev, int chan_cnt)
> {
> @@ -1201,7 +1211,7 @@ static int switchtec_dma_chans_enumerate(struct switchtec_dma_dev *swdma_dev,
> if (rc) {
> dev_err(&pdev->dev, "Channel %d: init channel failed\n",
> i);
> - chan_cnt = i;
> + swdma_dev->chan_cnt = i;
> goto err_exit;
> }
> }
> @@ -1209,10 +1219,8 @@ static int switchtec_dma_chans_enumerate(struct switchtec_dma_dev *swdma_dev,
> return chan_cnt;
>
> err_exit:
> - for (i = 0; i < chan_cnt; i++)
> - switchtec_dma_chan_free(pdev, swdma_dev->swdma_chans[i]);
> -
> - kfree(swdma_dev->swdma_chans);
> + switchtec_dma_chans_release(pdev, swdma_dev);
> + switchtec_dma_chans_free(swdma_dev);
>
> return rc;
> }
> @@ -1221,12 +1229,8 @@ static void switchtec_dma_release(struct dma_device *dma_dev)
> {
> struct switchtec_dma_dev *swdma_dev =
> container_of(dma_dev, struct switchtec_dma_dev, dma_dev);
> - int i;
>
> - for (i = 0; i < swdma_dev->chan_cnt; i++)
> - kfree(swdma_dev->swdma_chans[i]);
> -
> - kfree(swdma_dev->swdma_chans);
> + switchtec_dma_chans_free(swdma_dev);
>
> put_device(dma_dev->dev);
> kfree(swdma_dev);
> @@ -1317,6 +1321,7 @@ static int switchtec_dma_create(struct pci_dev *pdev)
>
> err_chans_release_exit:
> switchtec_dma_chans_release(pdev, swdma_dev);
> + switchtec_dma_chans_free(swdma_dev);
>
> err_exit:
> if (swdma_dev->chan_status_irq)
> --
> 2.47.3
>