| From 035b0fcf02707d3c9c2890dc1484b11aa5335eb1 Mon Sep 17 00:00:00 2001 |
| From: Vincent Mailhol <mailhol.vincent@wanadoo.fr> |
| Date: Tue, 15 Feb 2022 08:48:14 +0900 |
| Subject: can: gs_usb: change active_channels's type from atomic_t to u8 |
| |
| From: Vincent Mailhol <mailhol.vincent@wanadoo.fr> |
| |
| commit 035b0fcf02707d3c9c2890dc1484b11aa5335eb1 upstream. |
| |
| The driver uses an atomic_t variable: gs_usb:active_channels to keep |
| track of the number of opened channels in order to only allocate |
| memory for the URBs when this count changes from zero to one. |
| |
| However, the driver does not decrement the counter when an error |
| occurs in gs_can_open(). This issue is fixed by changing the type from |
| atomic_t to u8 and by simplifying the logic accordingly. |
| |
| It is safe to use an u8 here because the network stack big kernel lock |
| (a.k.a. rtnl_mutex) is being hold. For details, please refer to [1]. |
| |
| [1] https://lore.kernel.org/linux-can/CAMZ6Rq+sHpiw34ijPsmp7vbUpDtJwvVtdV7CvRZJsLixjAFfrg@mail.gmail.com/T/#t |
| |
| Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices") |
| Link: https://lore.kernel.org/all/20220214234814.1321599-1-mailhol.vincent@wanadoo.fr |
| Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr> |
| Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/can/usb/gs_usb.c | 10 +++++----- |
| 1 file changed, 5 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/net/can/usb/gs_usb.c |
| +++ b/drivers/net/can/usb/gs_usb.c |
| @@ -190,8 +190,8 @@ struct gs_can { |
| struct gs_usb { |
| struct gs_can *canch[GS_MAX_INTF]; |
| struct usb_anchor rx_submitted; |
| - atomic_t active_channels; |
| struct usb_device *udev; |
| + u8 active_channels; |
| }; |
| |
| /* 'allocate' a tx context. |
| @@ -588,7 +588,7 @@ static int gs_can_open(struct net_device |
| if (rc) |
| return rc; |
| |
| - if (atomic_add_return(1, &parent->active_channels) == 1) { |
| + if (!parent->active_channels) { |
| for (i = 0; i < GS_MAX_RX_URBS; i++) { |
| struct urb *urb; |
| u8 *buf; |
| @@ -689,6 +689,7 @@ static int gs_can_open(struct net_device |
| |
| dev->can.state = CAN_STATE_ERROR_ACTIVE; |
| |
| + parent->active_channels++; |
| if (!(dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) |
| netif_start_queue(netdev); |
| |
| @@ -704,7 +705,8 @@ static int gs_can_close(struct net_devic |
| netif_stop_queue(netdev); |
| |
| /* Stop polling */ |
| - if (atomic_dec_and_test(&parent->active_channels)) |
| + parent->active_channels--; |
| + if (!parent->active_channels) |
| usb_kill_anchored_urbs(&parent->rx_submitted); |
| |
| /* Stop sending URBs */ |
| @@ -983,8 +985,6 @@ static int gs_usb_probe(struct usb_inter |
| |
| init_usb_anchor(&dev->rx_submitted); |
| |
| - atomic_set(&dev->active_channels, 0); |
| - |
| usb_set_intfdata(intf, dev); |
| dev->udev = interface_to_usbdev(intf); |
| |