summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Pugliese2013-08-09 16:25:37 +0200
committerGreg Kroah-Hartman2013-08-13 00:41:08 +0200
commitc654ecbbfefbeec8fbf202e117364bff48ecaea3 (patch)
tree262c335c73b088ef1851c926f7bfe5f95f8cf33c
parentUSB: cdc-wdm: fix race between interrupt handler and tasklet (diff)
downloadkernel-qcow2-linux-c654ecbbfefbeec8fbf202e117364bff48ecaea3.tar.gz
kernel-qcow2-linux-c654ecbbfefbeec8fbf202e117364bff48ecaea3.tar.xz
kernel-qcow2-linux-c654ecbbfefbeec8fbf202e117364bff48ecaea3.zip
HWA RC: fix a kernel panic when unplugging the HWA dongle
This patch fixes a kernel panic that can occur when unplugging the HWA dongle while a downstream device is in the process of disconnecting. This involved 2 changes. First, call usb_lock_device_for_reset before usb_reset_device to synchronize the HWA's post_rest and disconnect routines. Second, set the hwarc->neep_urb and hwarc->rd_buffer to NULL when they are freed in the error path in the post_reset routine. This prevents a double free when the disconnect routine is called and attempts to free those resources again. Signed-off-by: Thomas Pugliese <thomas.pugliese@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/uwb/hwa-rc.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c
index 0621abef9b4a..0257f35cfb9d 100644
--- a/drivers/uwb/hwa-rc.c
+++ b/drivers/uwb/hwa-rc.c
@@ -611,7 +611,16 @@ static
int hwarc_reset(struct uwb_rc *uwb_rc)
{
struct hwarc *hwarc = uwb_rc->priv;
- return usb_reset_device(hwarc->usb_dev);
+ int result;
+
+ /* device lock must be held when calling usb_reset_device. */
+ result = usb_lock_device_for_reset(hwarc->usb_dev, NULL);
+ if (result >= 0) {
+ result = usb_reset_device(hwarc->usb_dev);
+ usb_unlock_device(hwarc->usb_dev);
+ }
+
+ return result;
}
/**
@@ -709,8 +718,10 @@ static int hwarc_neep_init(struct uwb_rc *rc)
error_neep_submit:
usb_free_urb(hwarc->neep_urb);
+ hwarc->neep_urb = NULL;
error_urb_alloc:
free_page((unsigned long)hwarc->rd_buffer);
+ hwarc->rd_buffer = NULL;
error_rd_buffer:
return -ENOMEM;
}
@@ -723,7 +734,10 @@ static void hwarc_neep_release(struct uwb_rc *rc)
usb_kill_urb(hwarc->neep_urb);
usb_free_urb(hwarc->neep_urb);
+ hwarc->neep_urb = NULL;
+
free_page((unsigned long)hwarc->rd_buffer);
+ hwarc->rd_buffer = NULL;
}
/**