Commit 7f1ee826 authored by Michal Nazarewicz's avatar Michal Nazarewicz Committed by Greg Kroah-Hartman

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: default avatarMichal Nazarewicz <m.nazarewicz@samsung.com>
Reviewed-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 9f445cb2
...@@ -368,7 +368,7 @@ struct fsg_common { ...@@ -368,7 +368,7 @@ struct fsg_common {
struct task_struct *thread_task; struct task_struct *thread_task;
/* Callback function to call when thread exits. */ /* Callback function to call when thread exits. */
void (*thread_exits)(struct fsg_common *common); int (*thread_exits)(struct fsg_common *common);
/* Gadget's private data. */ /* Gadget's private data. */
void *private_data; void *private_data;
...@@ -392,8 +392,12 @@ struct fsg_config { ...@@ -392,8 +392,12 @@ struct fsg_config {
const char *lun_name_format; const char *lun_name_format;
const char *thread_name; const char *thread_name;
/* Callback function to call when thread exits. */ /* Callback function to call when thread exits. If no
void (*thread_exits)(struct fsg_common *common); * callback is set or it returns value lower then zero MSF
* will force eject all LUNs it operates on (including those
* marked as non-removable or with prevent_medium_removal flag
* set). */
int (*thread_exits)(struct fsg_common *common);
/* Gadget's private data. */ /* Gadget's private data. */
void *private_data; void *private_data;
...@@ -2615,8 +2619,20 @@ static int fsg_main_thread(void *common_) ...@@ -2615,8 +2619,20 @@ static int fsg_main_thread(void *common_)
common->thread_task = NULL; common->thread_task = NULL;
spin_unlock_irq(&common->lock); spin_unlock_irq(&common->lock);
if (common->thread_exits) if (!common->thread_exits || common->thread_exits(common) < 0) {
common->thread_exits(common); struct fsg_lun *curlun = common->luns;
unsigned i = common->nluns;
down_write(&common->filesem);
for (; i--; ++curlun) {
if (!fsg_lun_is_open(curlun))
continue;
fsg_lun_close(curlun);
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
}
up_write(&common->filesem);
}
/* Let the unbind and cleanup routines know the thread has exited */ /* Let the unbind and cleanup routines know the thread has exited */
complete_and_exit(&common->thread_notifier, 0); complete_and_exit(&common->thread_notifier, 0);
......
...@@ -135,6 +135,12 @@ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data); ...@@ -135,6 +135,12 @@ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
static unsigned long msg_registered = 0; static unsigned long msg_registered = 0;
static void msg_cleanup(void); static void msg_cleanup(void);
static int msg_thread_exits(struct fsg_common *common)
{
msg_cleanup();
return 0;
}
static int __init msg_do_config(struct usb_configuration *c) static int __init msg_do_config(struct usb_configuration *c)
{ {
struct fsg_common *common; struct fsg_common *common;
...@@ -147,7 +153,7 @@ static int __init msg_do_config(struct usb_configuration *c) ...@@ -147,7 +153,7 @@ static int __init msg_do_config(struct usb_configuration *c)
} }
fsg_config_from_params(&config, &mod_data); fsg_config_from_params(&config, &mod_data);
config.thread_exits = (void(*)(struct fsg_common*))&msg_cleanup; config.thread_exits = msg_thread_exits;
common = fsg_common_init(0, c->cdev, &config); common = fsg_common_init(0, c->cdev, &config);
if (IS_ERR(common)) if (IS_ERR(common))
return PTR_ERR(common); return PTR_ERR(common);
......
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