diff options
author | Thomas Pugliese | 2013-08-09 09:25:37 -0500 |
---|---|---|
committer | Greg Kroah-Hartman | 2013-08-12 15:41:08 -0700 |
commit | c654ecbbfefbeec8fbf202e117364bff48ecaea3 (patch) | |
tree | 262c335c73b088ef1851c926f7bfe5f95f8cf33c /drivers/uwb | |
parent | 6dd433e6cf2475ce8abec1b467720858c24450eb (diff) |
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>
Diffstat (limited to 'drivers/uwb')
-rw-r--r-- | drivers/uwb/hwa-rc.c | 16 |
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; } /** |