Re: [PATCH v3 04/11] dmaengine: switchtec-dma: fix channel leak on registration failure

Frank Li <[email protected]> Mon, 27 Jul 2026 16:52:59 -0400
Newsgroups org.kernel.vger.dmaengine,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci
Message-ID <amfFK5x1k1G3HQ-4@lizhi-Precision-Tower-5810>
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 <[email protected]>
> Link: https://lore.kernel.org/dmaengine/[email protected]
> Signed-off-by: Logan Gunthorpe <[email protected]>
> ---

Reviewed-by: Frank Li <[email protected]>

>  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
>