linux-can.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
To: Rhett Aultman <rhett.aultman@samsara.com>
Cc: Vincent Mailhol <mailhol.vincent@wanadoo.fr>,
	wg@grandegger.com, Marc Kleine-Budde <mkl@pengutronix.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-can@vger.kernel.org, linux-usb@vger.kernel.org
Subject: Re: [PATCH] can: gs_usb: gs_usb_open/close( ) fix memory leak
Date: Sat,  4 Jun 2022 11:11:45 +0900	[thread overview]
Message-ID: <20220604021145.55484-1-mailhol.vincent@wanadoo.fr> (raw)
In-Reply-To: <alpine.DEB.2.22.394.2206031547001.1630869@thelappy>

+CC: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+CC: linux-usb@vger.kernel.org

Rhett Aultman <rhett.aultman@samsara.com> writes:
> The gs_usb driver appears to suffer from a malady common to many USB CAN
> adapter drivers in that it performs usb_alloc_coherent( ) to allocate a
> number of USB request blocks (URBs) for RX, and then later relies on
> usb_kill_anchored_urbs( ) to free them, but this doesn't actually free
> them.  As a result, this may be leaking DMA memory that's been used by the
> driver.
>
> This commit is an adaptation of the techniques found in the esd_usb2 driver
> where a similar design pattern led to a memory leak.  It explicitly frees
> the RX URBs and their DMA memory via a call to usb_free_coherent( ).  Since
> the RX URBs were allocated in the gs_can_open( ), we remove them in
> gs_can_close( ) rather than in the disconnect function as was done in
> esd_usb2.

Right. To be frank, I think that there is a gap in the current URB
interface. If you do a simple kmalloc(), you can just set
URB_FREE_BUFFER in urb::transfer_flags. usb_kill_anchored_urbs() would
then eventually call urb_destroy() and automatically free it for you.

As far as I understand, I am not aware of equivalent mechanism to
automatically call usb_free_coherent() in the case that the driver
uses DMA memory. And I think that this is the root cause of this
"malady".

For me, the natural fix would be:

diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 33d62d7e3929..1460fdac0b18 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -22,6 +22,9 @@ static void urb_destroy(struct kref *kref)
 
        if (urb->transfer_flags & URB_FREE_BUFFER)
                kfree(urb->transfer_buffer);
+       else if (urb->transfer_flags & URB_FREE_COHERENT)
+               usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+                                 urb->transfer_buffer, urb->transfer_dma);
 
        kfree(urb);
 }
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 200b7b79acb5..dfc348d56fed 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1328,6 +1328,7 @@ extern int usb_disabled(void);
 #define URB_NO_INTERRUPT       0x0080  /* HINT: no non-error interrupt
                                         * needed */
 #define URB_FREE_BUFFER                0x0100  /* Free transfer buffer with the URB */
+#define URB_FREE_COHERENT      0x0200  /* Free DMA memory of transfer buffer */
 
 /* The following flags are used internally by usbcore and HCDs */
 #define URB_DIR_IN             0x0200  /* Transfer from device to host */
---

After doing this, drivers only have to add the URB_FREE_COHERENT flag
and voila!

Reusing URB_NO_TRANSFER_DMA_MAP to force a call to usb_free_coherent()
would be a bad idea because it would result in a double free for all
the drivers which correctly free their DMA memory. This is why above
snippet introduces a new URB_FREE_COHERENT flag.

Maybe I missed something obvious, but if so, I would like to
understand what is wrong in above approach.

> 
> For more information, see the following:
> * https://www.spinics.net/lists/linux-can/msg08203.html
> * https://github.com/torvalds/linux
>     928150fad41 (can: esd_usb2: fix memory leak)
> 
> From: Rhett Aultman <rhett.aultman@samsara.com>

Nitpick: the From tag is redundant. You already have it in the e-mail
header. It is relevant to explicitly add the From tag when picking
someone's else patch, but if the author and the signer are the same,
you are good to go without.

> Signed-off-by: Rhett Aultman <rhett.aultman@samsara.com>
> ---
>  drivers/net/can/usb/gs_usb.c | 23 +++++++++++++++++++++--
>  1 file changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
> index b29ba9138866..d3a658b444b5 100644
> --- a/drivers/net/can/usb/gs_usb.c
> +++ b/drivers/net/can/usb/gs_usb.c
> @@ -268,6 +268,8 @@ struct gs_can {
> 
>  	struct usb_anchor tx_submitted;
>  	atomic_t active_tx_urbs;
> +	void *rxbuf[GS_MAX_RX_URBS];
> +	dma_addr_t rxbuf_dma[GS_MAX_RX_URBS];

I do not like how the driver has to keep in a local array a reference
to all DMA allocated memory. All this information is redundant because
already present in the URB. So I really hope that we can fix it on the
URB API side and remove such complexity on the driver side.

>  };
> 
>  /* usb interface struct */
> @@ -742,6 +744,7 @@ static int gs_can_open(struct net_device *netdev)
>  		for (i = 0; i < GS_MAX_RX_URBS; i++) {
>  			struct urb *urb;
>  			u8 *buf;
> +			dma_addr_t buf_dma;
> 
>  			/* alloc rx urb */
>  			urb = usb_alloc_urb(0, GFP_KERNEL);
> @@ -752,7 +755,7 @@ static int gs_can_open(struct net_device *netdev)
>  			buf = usb_alloc_coherent(dev->udev,
>  						 dev->parent->hf_size_rx,
>  						 GFP_KERNEL,
> -						 &urb->transfer_dma);
> +						 &buf_dma);
>  			if (!buf) {
>  				netdev_err(netdev,
>  					   "No memory left for USB buffer\n");
> @@ -760,6 +763,8 @@ static int gs_can_open(struct net_device *netdev)
>  				return -ENOMEM;
>  			}
> 
> +			urb->transfer_dma = buf_dma;
> +
>  			/* fill, anchor, and submit rx urb */
>  			usb_fill_bulk_urb(urb,
>  					  dev->udev,
> @@ -781,10 +786,17 @@ static int gs_can_open(struct net_device *netdev)
>  					   "usb_submit failed (err=%d)\n", rc);
> 
>  				usb_unanchor_urb(urb);
> +				usb_free_coherent(dev->udev,
> +						  sizeof(struct gs_host_frame),
> +						  buf,
> +						  buf_dma);
>  				usb_free_urb(urb);
>  				break;
>  			}
> 
> +			dev->rxbuf[i] = buf;
> +			dev->rxbuf_dma[i] = buf_dma;
> +
>  			/* Drop reference,
>  			 * USB core will take care of freeing it
>  			 */
> @@ -842,13 +854,20 @@ static int gs_can_close(struct net_device *netdev)
>  	int rc;
>  	struct gs_can *dev = netdev_priv(netdev);
>  	struct gs_usb *parent = dev->parent;
> +	unsigned int i;
> 
>  	netif_stop_queue(netdev);
> 
>  	/* Stop polling */
>  	parent->active_channels--;
> -	if (!parent->active_channels)
> +	if (!parent->active_channels) {
>  		usb_kill_anchored_urbs(&parent->rx_submitted);
> +		for (i = 0; i < GS_MAX_RX_URBS; i++)
> +			usb_free_coherent(dev->udev,
> +					  sizeof(struct gs_host_frame),
> +					  dev->rxbuf[i],
> +					  dev->rxbuf_dma[i]);
> +	}
> 
>  	/* Stop sending URBs */
>  	usb_kill_anchored_urbs(&dev->tx_submitted);
> -- 
> 2.30.2
> 

  reply	other threads:[~2022-06-04  2:12 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-03 19:52 [PATCH 001/001] can: gs_usb: gs_usb_open/close( ) fix memory leak Rhett Aultman
2022-06-04  2:11 ` Vincent Mailhol [this message]
2022-06-04  2:26   ` [PATCH] " Vincent MAILHOL
2022-06-04 14:08     ` Rhett Aultman
2022-06-04 14:41       ` [RFC PATCH] USB: core: urb: add new transfer flag URB_FREE_COHERENT Vincent Mailhol
2022-06-04 16:40         ` Alan Stern
2022-06-05  2:04           ` Vincent MAILHOL
2022-06-05  6:00           ` Oliver Neukum
2022-06-05 13:45             ` Vincent MAILHOL
2022-06-07  9:49               ` Oliver Neukum
2022-06-07 10:18                 ` Vincent MAILHOL
2022-06-07 11:46                   ` Oliver Neukum
2022-06-07 12:12                     ` Vincent MAILHOL
2022-06-05  2:15         ` [RFC PATCH v2] usb: " Vincent Mailhol
2022-06-04 14:53       ` [PATCH] can: gs_usb: gs_usb_open/close( ) fix memory leak Vincent MAILHOL
2022-06-09 20:47 ` [PATCH v2 0/3] URB_FREE_COHERENT gs_usb memory leak fix Rhett Aultman
2022-06-09 20:47   ` [PATCH v2 1/3] drivers: usb/core/urb: Add URB_FREE_COHERENT Rhett Aultman
2022-06-10  0:18     ` Vincent MAILHOL
2022-06-10 10:46       ` Marc Kleine-Budde
2022-06-09 20:47   ` [PATCH v2 2/3] drivers: usb/core/urb: allow URB_FREE_COHERENT Rhett Aultman
2022-06-09 23:18     ` Vincent Mailhol
2022-06-09 20:47   ` [PATCH v2 3/3] can: gs_usb: fix DMA memory leak on close Rhett Aultman
2022-06-10  0:05     ` Vincent Mailhol
2022-06-10  1:28       ` Vincent Mailhol
2022-06-10 21:33   ` [PATCH v3 0/2] URB_FREE_COHERENT gs_usb memory leak fix Rhett Aultman
2022-06-10 21:33     ` [PATCH v3 1/2] drivers: usb/core/urb: Add URB_FREE_COHERENT Rhett Aultman
2022-06-11 15:31       ` Marc Kleine-Budde
2022-06-11 16:06         ` Vincent MAILHOL
2022-06-21 13:51           ` Greg Kroah-Hartman
2022-06-21 14:59             ` Vincent MAILHOL
2022-06-21 15:03               ` Greg Kroah-Hartman
2022-06-21 15:54                 ` Vincent MAILHOL
2022-06-21 15:11               ` Alan Stern
2022-06-21 15:55                 ` Vincent MAILHOL
2022-06-21 16:14                   ` Alan Stern
2022-06-21 16:40                     ` Vincent MAILHOL
2022-06-21 17:00                       ` Greg Kroah-Hartman
2022-06-21 17:14                         ` Vincent MAILHOL
2022-06-21 17:46                           ` Greg Kroah-Hartman
2022-06-22  9:22                   ` David Laight
2022-06-22  9:41                     ` Greg Kroah-Hartman
2022-06-22 10:03                       ` David Laight
2022-06-22 11:11                         ` Oliver Neukum
2022-06-22 10:34                       ` Vincent MAILHOL
2022-06-22 12:23                         ` Greg Kroah-Hartman
2022-06-22 15:59                           ` Vincent MAILHOL
2022-06-22 18:11                             ` Rhett Aultman
2022-06-26  8:21                               ` Vincent MAILHOL
2022-06-27 19:24                                 ` Rhett Aultman
2022-06-28  1:09                                   ` Vincent MAILHOL
2022-07-04 13:02                                     ` Marc Kleine-Budde
2022-07-04 15:35                                       ` Rhett Aultman
2022-07-05  7:50                                         ` Marc Kleine-Budde
2022-06-23 17:30       ` Hongren Zenithal Zheng
2022-06-23 17:45         ` Shuah Khan
2022-06-24 14:43           ` Alan Stern
2022-06-24 16:01             ` Hongren Zenithal Zheng
2022-06-24 16:31             ` Shuah Khan
2022-06-24 18:07               ` Alan Stern
2022-06-27 22:54                 ` Shuah Khan
2022-06-28  1:35                   ` Alan Stern
2022-07-01  2:10                     ` Shuah Khan
2022-08-01 17:42                       ` Shuah Khan
2022-08-01 18:28                         ` Vincent MAILHOL
2022-08-03 23:44                           ` Shuah Khan
2022-06-10 21:33     ` [PATCH v3 2/2] can: gs_usb: fix DMA memory leak on close Rhett Aultman
2022-06-11 15:35       ` Marc Kleine-Budde
2022-06-11 16:03         ` Vincent MAILHOL
2022-06-12 21:28       ` David Laight
2022-06-12 21:33         ` Marc Kleine-Budde
2022-06-14 15:26     ` [PATCH v4 0/1] URB_FREE_COHERENT gs_usb memory leak fix Rhett Aultman
2022-06-14 15:26       ` [PATCH v4 1/1] can: gs_usb: fix DMA memory leak on close Rhett Aultman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220604021145.55484-1-mailhol.vincent@wanadoo.fr \
    --to=mailhol.vincent@wanadoo.fr \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-can@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mkl@pengutronix.de \
    --cc=rhett.aultman@samsara.com \
    --cc=wg@grandegger.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).