diff options
author | Maximilain Schneider <max@schneidersoft.net> | 2016-02-22 20:17:28 -0500 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2016-02-26 02:36:33 -0500 |
commit | e9a2d81b1761093386a0bb8a4f51642ac785ef63 (patch) | |
tree | fc98a26a18092acc4d2086fe0116accd10aa85a5 /drivers/net/can | |
parent | 4c0b6eaf373a5323f03a3a20c42fc435715b073d (diff) |
can: gs_usb: fixed disconnect bug by removing erroneous use of kfree()
gs_destroy_candev() erroneously calls kfree() on a struct gs_can *, which is
allocated through alloc_candev() and should instead be freed using
free_candev() alone.
The inappropriate use of kfree() causes the kernel to hang when
gs_destroy_candev() is called.
Only the struct gs_usb * which is allocated through kzalloc() should be freed
using kfree() when the device is disconnected.
Signed-off-by: Maximilian Schneider <max@schneidersoft.net>
Cc: linux-stable <stable@vger.kernel.org>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can')
-rw-r--r-- | drivers/net/can/usb/gs_usb.c | 24 |
1 files changed, 11 insertions, 13 deletions
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 5eee62badf45..cbc99d5649af 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c | |||
@@ -826,9 +826,8 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface | |||
826 | static void gs_destroy_candev(struct gs_can *dev) | 826 | static void gs_destroy_candev(struct gs_can *dev) |
827 | { | 827 | { |
828 | unregister_candev(dev->netdev); | 828 | unregister_candev(dev->netdev); |
829 | free_candev(dev->netdev); | ||
830 | usb_kill_anchored_urbs(&dev->tx_submitted); | 829 | usb_kill_anchored_urbs(&dev->tx_submitted); |
831 | kfree(dev); | 830 | free_candev(dev->netdev); |
832 | } | 831 | } |
833 | 832 | ||
834 | static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) | 833 | static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) |
@@ -913,12 +912,15 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id * | |||
913 | for (i = 0; i < icount; i++) { | 912 | for (i = 0; i < icount; i++) { |
914 | dev->canch[i] = gs_make_candev(i, intf); | 913 | dev->canch[i] = gs_make_candev(i, intf); |
915 | if (IS_ERR_OR_NULL(dev->canch[i])) { | 914 | if (IS_ERR_OR_NULL(dev->canch[i])) { |
915 | /* save error code to return later */ | ||
916 | rc = PTR_ERR(dev->canch[i]); | ||
917 | |||
916 | /* on failure destroy previously created candevs */ | 918 | /* on failure destroy previously created candevs */ |
917 | icount = i; | 919 | icount = i; |
918 | for (i = 0; i < icount; i++) { | 920 | for (i = 0; i < icount; i++) |
919 | gs_destroy_candev(dev->canch[i]); | 921 | gs_destroy_candev(dev->canch[i]); |
920 | dev->canch[i] = NULL; | 922 | |
921 | } | 923 | usb_kill_anchored_urbs(&dev->rx_submitted); |
922 | kfree(dev); | 924 | kfree(dev); |
923 | return rc; | 925 | return rc; |
924 | } | 926 | } |
@@ -939,16 +941,12 @@ static void gs_usb_disconnect(struct usb_interface *intf) | |||
939 | return; | 941 | return; |
940 | } | 942 | } |
941 | 943 | ||
942 | for (i = 0; i < GS_MAX_INTF; i++) { | 944 | for (i = 0; i < GS_MAX_INTF; i++) |
943 | struct gs_can *can = dev->canch[i]; | 945 | if (dev->canch[i]) |
944 | 946 | gs_destroy_candev(dev->canch[i]); | |
945 | if (!can) | ||
946 | continue; | ||
947 | |||
948 | gs_destroy_candev(can); | ||
949 | } | ||
950 | 947 | ||
951 | usb_kill_anchored_urbs(&dev->rx_submitted); | 948 | usb_kill_anchored_urbs(&dev->rx_submitted); |
949 | kfree(dev); | ||
952 | } | 950 | } |
953 | 951 | ||
954 | static const struct usb_device_id gs_usb_table[] = { | 952 | static const struct usb_device_id gs_usb_table[] = { |