diff options
author | Yauheni Kaliuta <yauheni.kaliuta@nokia.com> | 2011-10-13 07:19:05 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-10-18 16:49:17 -0400 |
commit | 91960c2ef095c4b0744349e80a933921cbdcfd6e (patch) | |
tree | 578cfcdd1d4de5d0e1d870a71bb6f6d264c39015 /drivers/usb/gadget/file_storage.c | |
parent | 1d749f9afa657f6ee9336b2bc1fcd750a647d157 (diff) |
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] [<b00e403c>] (touch_atime+0x4/0x140) from [<b00a1498>] (generic_file_aio_read+0x678/0x6f0)
[ 484.946563] [<b00a1498>] (generic_file_aio_read+0x678/0x6f0) from [<b00d08c4>] (do_sync_read+0xb0/0xf4)
[ 484.955963] [<b00d08c4>] (do_sync_read+0xb0/0xf4) from [<b00d1478>] (vfs_read+0xac/0x144)
[ 484.964172] [<b00d1478>] (vfs_read+0xac/0x144) from [<af24c6a8>] (fsg_setup+0x7f4/0x900 [g_file_storage])
[ 484.973785] [<af24c6a8>] (fsg_setup+0x7f4/0x900 [g_file_storage]) from [<af24da14>] (fsg_main_thread+0x85c/0x175c [g_file_storage])
[ 484.985626] [<af24da14>] (fsg_main_thread+0x85c/0x175c [g_file_storage]) from [<b0077c48>] (kthread+0x7c/0x84)
[ 484.995666] [<b0077c48>] (kthread+0x7c/0x84) from [<b002f950>] (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 <yauheni.kaliuta@nokia.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget/file_storage.c')
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 18 |
1 files changed, 9 insertions, 9 deletions
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) | |||
3153 | DBG(fsg, "unbind\n"); | 3153 | DBG(fsg, "unbind\n"); |
3154 | clear_bit(REGISTERED, &fsg->atomic_bitflags); | 3154 | clear_bit(REGISTERED, &fsg->atomic_bitflags); |
3155 | 3155 | ||
3156 | /* If the thread isn't already dead, tell it to exit now */ | ||
3157 | if (fsg->state != FSG_STATE_TERMINATED) { | ||
3158 | raise_exception(fsg, FSG_STATE_EXIT); | ||
3159 | wait_for_completion(&fsg->thread_notifier); | ||
3160 | |||
3161 | /* The cleanup routine waits for this completion also */ | ||
3162 | complete(&fsg->thread_notifier); | ||
3163 | } | ||
3164 | |||
3156 | /* Unregister the sysfs attribute files and the LUNs */ | 3165 | /* Unregister the sysfs attribute files and the LUNs */ |
3157 | for (i = 0; i < fsg->nluns; ++i) { | 3166 | for (i = 0; i < fsg->nluns; ++i) { |
3158 | curlun = &fsg->luns[i]; | 3167 | curlun = &fsg->luns[i]; |
@@ -3166,15 +3175,6 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) | |||
3166 | } | 3175 | } |
3167 | } | 3176 | } |
3168 | 3177 | ||
3169 | /* If the thread isn't already dead, tell it to exit now */ | ||
3170 | if (fsg->state != FSG_STATE_TERMINATED) { | ||
3171 | raise_exception(fsg, FSG_STATE_EXIT); | ||
3172 | wait_for_completion(&fsg->thread_notifier); | ||
3173 | |||
3174 | /* The cleanup routine waits for this completion also */ | ||
3175 | complete(&fsg->thread_notifier); | ||
3176 | } | ||
3177 | |||
3178 | /* Free the data buffers */ | 3178 | /* Free the data buffers */ |
3179 | for (i = 0; i < fsg_num_buffers; ++i) | 3179 | for (i = 0; i < fsg_num_buffers; ++i) |
3180 | kfree(fsg->buffhds[i].buf); | 3180 | kfree(fsg->buffhds[i].buf); |