diff options
author | Michal Nazarewicz <m.nazarewicz@samsung.com> | 2010-01-28 07:05:26 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-02 17:54:49 -0500 |
commit | 7f1ee82695654faf0a93fc0abf3b08eb354ef1f6 (patch) | |
tree | 4bae5a33bf617e72e8e255a0832871fce9547cf4 /drivers/usb/gadget | |
parent | 9f445cb29918dc488b7a9a92ef018599cce33df7 (diff) |
USB: mass_storage: eject LUNs on thread exit
Adds a fallback which forces all LUNs ejection (including
non-removable and with prevent_medium_removal flag) when mass storage
function (MSF) worker thread exits and gadget fails to handle the
situation.
Previously, if thread_exits was not specified mass storage function
(MSF) did nothing when exiting thread as it's unclear for *function*
what to do when it's thread terminates so responsibility of handling
this situation was left to the *gadget* using the function.
The g_mass_storage handled the situation by unregistering itself (the
same thing that file storage gadget does). However, g_multi did
nothing and so MSF did not eject LUNs which prevented file system
unmounting.
Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 26 | ||||
-rw-r--r-- | drivers/usb/gadget/mass_storage.c | 8 |
2 files changed, 28 insertions, 6 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index a37640eba434..0a18d446e9dd 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c | |||
@@ -368,7 +368,7 @@ struct fsg_common { | |||
368 | struct task_struct *thread_task; | 368 | struct task_struct *thread_task; |
369 | 369 | ||
370 | /* Callback function to call when thread exits. */ | 370 | /* Callback function to call when thread exits. */ |
371 | void (*thread_exits)(struct fsg_common *common); | 371 | int (*thread_exits)(struct fsg_common *common); |
372 | /* Gadget's private data. */ | 372 | /* Gadget's private data. */ |
373 | void *private_data; | 373 | void *private_data; |
374 | 374 | ||
@@ -392,8 +392,12 @@ struct fsg_config { | |||
392 | const char *lun_name_format; | 392 | const char *lun_name_format; |
393 | const char *thread_name; | 393 | const char *thread_name; |
394 | 394 | ||
395 | /* Callback function to call when thread exits. */ | 395 | /* Callback function to call when thread exits. If no |
396 | void (*thread_exits)(struct fsg_common *common); | 396 | * callback is set or it returns value lower then zero MSF |
397 | * will force eject all LUNs it operates on (including those | ||
398 | * marked as non-removable or with prevent_medium_removal flag | ||
399 | * set). */ | ||
400 | int (*thread_exits)(struct fsg_common *common); | ||
397 | /* Gadget's private data. */ | 401 | /* Gadget's private data. */ |
398 | void *private_data; | 402 | void *private_data; |
399 | 403 | ||
@@ -2615,8 +2619,20 @@ static int fsg_main_thread(void *common_) | |||
2615 | common->thread_task = NULL; | 2619 | common->thread_task = NULL; |
2616 | spin_unlock_irq(&common->lock); | 2620 | spin_unlock_irq(&common->lock); |
2617 | 2621 | ||
2618 | if (common->thread_exits) | 2622 | if (!common->thread_exits || common->thread_exits(common) < 0) { |
2619 | common->thread_exits(common); | 2623 | struct fsg_lun *curlun = common->luns; |
2624 | unsigned i = common->nluns; | ||
2625 | |||
2626 | down_write(&common->filesem); | ||
2627 | for (; i--; ++curlun) { | ||
2628 | if (!fsg_lun_is_open(curlun)) | ||
2629 | continue; | ||
2630 | |||
2631 | fsg_lun_close(curlun); | ||
2632 | curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; | ||
2633 | } | ||
2634 | up_write(&common->filesem); | ||
2635 | } | ||
2620 | 2636 | ||
2621 | /* Let the unbind and cleanup routines know the thread has exited */ | 2637 | /* Let the unbind and cleanup routines know the thread has exited */ |
2622 | complete_and_exit(&common->thread_notifier, 0); | 2638 | complete_and_exit(&common->thread_notifier, 0); |
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 19619fbf20ac..705cc1f76327 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c | |||
@@ -135,6 +135,12 @@ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data); | |||
135 | static unsigned long msg_registered = 0; | 135 | static unsigned long msg_registered = 0; |
136 | static void msg_cleanup(void); | 136 | static void msg_cleanup(void); |
137 | 137 | ||
138 | static int msg_thread_exits(struct fsg_common *common) | ||
139 | { | ||
140 | msg_cleanup(); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
138 | static int __init msg_do_config(struct usb_configuration *c) | 144 | static int __init msg_do_config(struct usb_configuration *c) |
139 | { | 145 | { |
140 | struct fsg_common *common; | 146 | struct fsg_common *common; |
@@ -147,7 +153,7 @@ static int __init msg_do_config(struct usb_configuration *c) | |||
147 | } | 153 | } |
148 | 154 | ||
149 | fsg_config_from_params(&config, &mod_data); | 155 | fsg_config_from_params(&config, &mod_data); |
150 | config.thread_exits = (void(*)(struct fsg_common*))&msg_cleanup; | 156 | config.thread_exits = msg_thread_exits; |
151 | common = fsg_common_init(0, c->cdev, &config); | 157 | common = fsg_common_init(0, c->cdev, &config); |
152 | if (IS_ERR(common)) | 158 | if (IS_ERR(common)) |
153 | return PTR_ERR(common); | 159 | return PTR_ERR(common); |