USB: mass_storage: eject LUNs on thread exit
[linux-2.6.git] / drivers / usb / gadget / f_mass_storage.c
index a37640e..0a18d44 100644 (file)
@@ -368,7 +368,7 @@ struct fsg_common {
        struct task_struct      *thread_task;
 
        /* 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. */
        void                    *private_data;
 
@@ -392,8 +392,12 @@ struct fsg_config {
        const char              *lun_name_format;
        const char              *thread_name;
 
-       /* Callback function to call when thread exits. */
-       void                    (*thread_exits)(struct fsg_common *common);
+       /* Callback function to call when thread exits.  If no
+        * 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. */
        void                    *private_data;
 
@@ -2615,8 +2619,20 @@ static int fsg_main_thread(void *common_)
        common->thread_task = NULL;
        spin_unlock_irq(&common->lock);
 
-       if (common->thread_exits)
-               common->thread_exits(common);
+       if (!common->thread_exits || common->thread_exits(common) < 0) {
+               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 */
        complete_and_exit(&common->thread_notifier, 0);