Commit d73b7aff authored by Pete Zaitcev's avatar Pete Zaitcev Committed by Greg Kroah-Hartman

ub: stub pre_reset and post_reset to fix oops

Due to recent changes to usb_reset_device, the following hang occurs:

events/0      D 0000000000000000     0     6      2
 ffff880037477cc0 0000000000000046 ffff880037477c50 ffffffff80237434
 ffffffff80574c80 00000001000a015c 0000000000000286 ffff8800374757d0
 ffff88002a31c860 ffff880037475a00 0000000036779140 ffff880037475a00
Call Trace:
 [<ffffffff80237434>] try_to_del_timer_sync+0x52/0x5b
 [<ffffffff8026f86c>] dma_pool_free+0x1a7/0x1ec
 [<ffffffffa02a928a>] ub_disconnect+0x8e/0x1ad [ub]
 [<ffffffff802407c9>] autoremove_wake_function+0x0/0x2e
 [<ffffffff80378959>] usb_unbind_interface+0x5c/0xb7
 [<ffffffff8036ab70>] __device_release_driver+0x95/0xbd
 [<ffffffff8036ac70>] device_release_driver+0x21/0x2d
 [<ffffffff803789f8>] usb_driver_release_interface+0x44/0x83
 [<ffffffff80378ab9>] usb_forced_unbind_intf+0x17/0x1d
 [<ffffffff80371ba4>] usb_reset_device+0x7d/0x114
 [<ffffffffa02aaffd>] ub_reset_task+0x0/0x293 [ub]
 [<ffffffffa02ab1c1>] ub_reset_task+0x1c4/0x293 [ub]
 [<ffffffff8033dd1e>] flush_to_ldisc+0x0/0x1cd
 [<ffffffffa02aaffd>] ub_reset_task+0x0/0x293 [ub]
 [<ffffffff8023d302>] run_workqueue+0x87/0x114
 [<ffffffff8023d467>] worker_thread+0xd8/0xe7
 [<ffffffff802407c9>] autoremove_wake_function+0x0/0x2e
 [<ffffffff8023d38f>] worker_thread+0x0/0xe7
 [<ffffffff802404c1>] kthread+0x47/0x73
 [<ffffffff8022c8dd>] schedule_tail+0x27/0x60
 [<ffffffff8020c249>] child_rip+0xa/0x11
 [<ffffffff8024047a>] kthread+0x0/0x73
 [<ffffffff8020c23f>] child_rip+0x0/0x11

This is because usb_reset_device now unbinds, and that calls disconnect,
which in case of ub waits until the reset completes... which deadlocks.
Worse, this deadlocks keventd and this takes whole box down.

I'm going to fix this properly later, but let's unbreak the driver
quickly for non-composite devices at least.
Signed-off-by: default avatarPete Zaitcev <zaitcev@redhat.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 859ff407
...@@ -1546,8 +1546,6 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) ...@@ -1546,8 +1546,6 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
/* /*
* Reset management * Reset management
* XXX Move usb_reset_device to khubd. Hogging kevent is not a good thing.
* XXX Make usb_sync_reset asynchronous.
*/ */
static void ub_reset_enter(struct ub_dev *sc, int try) static void ub_reset_enter(struct ub_dev *sc, int try)
...@@ -1632,6 +1630,22 @@ static void ub_reset_task(struct work_struct *work) ...@@ -1632,6 +1630,22 @@ static void ub_reset_task(struct work_struct *work)
spin_unlock_irqrestore(sc->lock, flags); spin_unlock_irqrestore(sc->lock, flags);
} }
/*
* XXX Reset brackets are too much hassle to implement, so just stub them
* in order to prevent forced unbinding (which deadlocks solid when our
* ->disconnect method waits for the reset to complete and this kills keventd).
*
* XXX Tell Alan to move usb_unlock_device inside of usb_reset_device,
* or else the post_reset is invoked, and restats I/O on a locked device.
*/
static int ub_pre_reset(struct usb_interface *iface) {
return 0;
}
static int ub_post_reset(struct usb_interface *iface) {
return 0;
}
/* /*
* This is called from a process context. * This is called from a process context.
*/ */
...@@ -2446,6 +2460,8 @@ static struct usb_driver ub_driver = { ...@@ -2446,6 +2460,8 @@ static struct usb_driver ub_driver = {
.probe = ub_probe, .probe = ub_probe,
.disconnect = ub_disconnect, .disconnect = ub_disconnect,
.id_table = ub_usb_ids, .id_table = ub_usb_ids,
.pre_reset = ub_pre_reset,
.post_reset = ub_post_reset,
}; };
static int __init ub_init(void) static int __init ub_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment