From 91960c2ef095c4b0744349e80a933921cbdcfd6e Mon Sep 17 00:00:00 2001 From: Yauheni Kaliuta Date: Thu, 13 Oct 2011 14:19:05 +0300 Subject: usb: gadget: file_storage: fix race on unloading There is a race, reproduced rarely if you unload the module when host finishes mass storage device initialization (reading partition table and so on): fsg_unbind() code first closes lun files then waits for worker thread to finish its work, as the result the thread may operate on already closed device with an oops and backtrace: [ 484.937225] [] (touch_atime+0x4/0x140) from [] (generic_file_aio_read+0x678/0x6f0) [ 484.946563] [] (generic_file_aio_read+0x678/0x6f0) from [] (do_sync_read+0xb0/0xf4) [ 484.955963] [] (do_sync_read+0xb0/0xf4) from [] (vfs_read+0xac/0x144) [ 484.964172] [] (vfs_read+0xac/0x144) from [] (fsg_setup+0x7f4/0x900 [g_file_storage]) [ 484.973785] [] (fsg_setup+0x7f4/0x900 [g_file_storage]) from [] (fsg_main_thread+0x85c/0x175c [g_file_storage]) [ 484.985626] [] (fsg_main_thread+0x85c/0x175c [g_file_storage]) from [] (kthread+0x7c/0x84) [ 484.995666] [] (kthread+0x7c/0x84) from [] (kernel_thread_exit+0x0/0x8) [ 485.004028] Code: eaffffd0 e28dd008 e8bd8df0 e92d40f7 (e591400c) Change the order in unbind: wait for the thread first, then close the files. Signed-off-by: Yauheni Kaliuta Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/usb/gadget/file_storage.c') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 5779549d7dc6..3ac4f51cd0bb 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3153,6 +3153,15 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) DBG(fsg, "unbind\n"); clear_bit(REGISTERED, &fsg->atomic_bitflags); + /* If the thread isn't already dead, tell it to exit now */ + if (fsg->state != FSG_STATE_TERMINATED) { + raise_exception(fsg, FSG_STATE_EXIT); + wait_for_completion(&fsg->thread_notifier); + + /* The cleanup routine waits for this completion also */ + complete(&fsg->thread_notifier); + } + /* Unregister the sysfs attribute files and the LUNs */ for (i = 0; i < fsg->nluns; ++i) { curlun = &fsg->luns[i]; @@ -3166,15 +3175,6 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) } } - /* If the thread isn't already dead, tell it to exit now */ - if (fsg->state != FSG_STATE_TERMINATED) { - raise_exception(fsg, FSG_STATE_EXIT); - wait_for_completion(&fsg->thread_notifier); - - /* The cleanup routine waits for this completion also */ - complete(&fsg->thread_notifier); - } - /* Free the data buffers */ for (i = 0; i < fsg_num_buffers; ++i) kfree(fsg->buffhds[i].buf); -- cgit v1.2.2