Skip to content

Commit a44be3e

Browse files
AlanSterngregkh
authored andcommitted
USB: g_mass_storage: Fix deadlock when driver is unbound
commit 1fbbb78f25d1291274f320462bf6908906f538db upstream. As a holdover from the old g_file_storage gadget, the g_mass_storage legacy gadget driver attempts to unregister itself when its main operating thread terminates (if it hasn't been unregistered already). This is not strictly necessary; it was never more than an attempt to have the gadget fail cleanly if something went wrong and the main thread was killed. However, now that the UDC core manages gadget drivers independently of UDC drivers, this scheme doesn't work any more. A simple test: modprobe dummy-hcd modprobe g-mass-storage file=... rmmod dummy-hcd ends up in a deadlock with the following backtrace: sysrq: SysRq : Show Blocked State task PC stack pid father file-storage D 0 1130 2 0x00000000 Call Trace: __schedule+0x53e/0x58c schedule+0x6e/0x77 schedule_preempt_disabled+0xd/0xf __mutex_lock.isra.1+0x129/0x224 ? _raw_spin_unlock_irqrestore+0x12/0x14 __mutex_lock_slowpath+0x12/0x14 mutex_lock+0x28/0x2b usb_gadget_unregister_driver+0x29/0x9b [udc_core] usb_composite_unregister+0x10/0x12 [libcomposite] msg_cleanup+0x1d/0x20 [g_mass_storage] msg_thread_exits+0xd/0xdd7 [g_mass_storage] fsg_main_thread+0x1395/0x13d6 [usb_f_mass_storage] ? __schedule+0x573/0x58c kthread+0xd9/0xdb ? do_set_interface+0x25c/0x25c [usb_f_mass_storage] ? init_completion+0x1e/0x1e ret_from_fork+0x19/0x24 rmmod D 0 1155 683 0x00000000 Call Trace: __schedule+0x53e/0x58c schedule+0x6e/0x77 schedule_timeout+0x26/0xbc ? __schedule+0x573/0x58c do_wait_for_common+0xb3/0x128 ? usleep_range+0x81/0x81 ? wake_up_q+0x3f/0x3f wait_for_common+0x2e/0x45 wait_for_completion+0x17/0x19 fsg_common_put+0x34/0x81 [usb_f_mass_storage] fsg_free_inst+0x13/0x1e [usb_f_mass_storage] usb_put_function_instance+0x1a/0x25 [libcomposite] msg_unbind+0x2a/0x42 [g_mass_storage] __composite_unbind+0x4a/0x6f [libcomposite] composite_unbind+0x12/0x14 [libcomposite] usb_gadget_remove_driver+0x4f/0x77 [udc_core] usb_del_gadget_udc+0x52/0xcc [udc_core] dummy_udc_remove+0x27/0x2c [dummy_hcd] platform_drv_remove+0x1d/0x31 device_release_driver_internal+0xe9/0x16d device_release_driver+0x11/0x13 bus_remove_device+0xd2/0xe2 device_del+0x19f/0x221 ? selinux_capable+0x22/0x27 platform_device_del+0x21/0x63 platform_device_unregister+0x10/0x1a cleanup+0x20/0x817 [dummy_hcd] SyS_delete_module+0x10c/0x197 ? ____fput+0xd/0xf ? task_work_run+0x55/0x62 ? prepare_exit_to_usermode+0x65/0x75 do_fast_syscall_32+0x86/0xc3 entry_SYSENTER_32+0x4e/0x7c What happens is that removing the dummy-hcd driver causes the UDC core to unbind the gadget driver, which it does while holding the udc_lock mutex. The unbind routine in g_mass_storage tells the main thread to exit and waits for it to terminate. But as mentioned above, when the main thread exits it tries to unregister the mass-storage function driver. Via the composite framework this ends up calling usb_gadget_unregister_driver(), which tries to acquire the udc_lock mutex. The result is deadlock. The simplest way to fix the problem is not to be so clever: The main thread doesn't have to unregister the function driver. The side effects won't be so terrible; if the gadget is still attached to a USB host when the main thread is killed, it will appear to the host as though the gadget's firmware has crashed -- a reasonably accurate interpretation, and an all-too-common occurrence for USB mass-storage devices. In fact, the code to unregister the driver when the main thread exits is specific to g-mass-storage; it is not used when f-mass-storage is included as a function in a larger composite device. Therefore the entire mechanism responsible for this (the fsg_operations structure with its ->thread_exits method, the fsg_common_set_ops() routine, and the msg_thread_exits() callback routine) can all be eliminated. Even the msg_registered bitflag can be removed, because now the driver is unregistered in only one place rather than in two places. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Felipe Balbi <felipe.balbi@linux.intel.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 2efab2c commit a44be3e

3 files changed

Lines changed: 10 additions & 57 deletions

File tree

drivers/usb/gadget/function/f_mass_storage.c

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,6 @@ struct fsg_common {
306306
struct completion thread_notifier;
307307
struct task_struct *thread_task;
308308

309-
/* Callback functions. */
310-
const struct fsg_operations *ops;
311309
/* Gadget's private data. */
312310
void *private_data;
313311

@@ -2504,6 +2502,7 @@ static void handle_exception(struct fsg_common *common)
25042502
static int fsg_main_thread(void *common_)
25052503
{
25062504
struct fsg_common *common = common_;
2505+
int i;
25072506

25082507
/*
25092508
* Allow the thread to be killed by a signal, but set the signal mask
@@ -2565,21 +2564,16 @@ static int fsg_main_thread(void *common_)
25652564
common->thread_task = NULL;
25662565
spin_unlock_irq(&common->lock);
25672566

2568-
if (!common->ops || !common->ops->thread_exits
2569-
|| common->ops->thread_exits(common) < 0) {
2570-
int i;
2567+
/* Eject media from all LUNs */
25712568

2572-
down_write(&common->filesem);
2573-
for (i = 0; i < ARRAY_SIZE(common->luns); --i) {
2574-
struct fsg_lun *curlun = common->luns[i];
2575-
if (!curlun || !fsg_lun_is_open(curlun))
2576-
continue;
2569+
down_write(&common->filesem);
2570+
for (i = 0; i < ARRAY_SIZE(common->luns); i++) {
2571+
struct fsg_lun *curlun = common->luns[i];
25772572

2573+
if (curlun && fsg_lun_is_open(curlun))
25782574
fsg_lun_close(curlun);
2579-
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
2580-
}
2581-
up_write(&common->filesem);
25822575
}
2576+
up_write(&common->filesem);
25832577

25842578
/* Let fsg_unbind() know the thread has exited */
25852579
complete_and_exit(&common->thread_notifier, 0);
@@ -2785,13 +2779,6 @@ void fsg_common_remove_luns(struct fsg_common *common)
27852779
}
27862780
EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
27872781

2788-
void fsg_common_set_ops(struct fsg_common *common,
2789-
const struct fsg_operations *ops)
2790-
{
2791-
common->ops = ops;
2792-
}
2793-
EXPORT_SYMBOL_GPL(fsg_common_set_ops);
2794-
27952782
void fsg_common_free_buffers(struct fsg_common *common)
27962783
{
27972784
_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);

drivers/usb/gadget/function/f_mass_storage.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,6 @@ struct fsg_module_parameters {
6060
struct fsg_common;
6161

6262
/* FSF callback functions */
63-
struct fsg_operations {
64-
/*
65-
* Callback function to call when thread exits. If no
66-
* callback is set or it returns value lower then zero MSF
67-
* will force eject all LUNs it operates on (including those
68-
* marked as non-removable or with prevent_medium_removal flag
69-
* set).
70-
*/
71-
int (*thread_exits)(struct fsg_common *common);
72-
};
73-
7463
struct fsg_lun_opts {
7564
struct config_group group;
7665
struct fsg_lun *lun;
@@ -141,9 +130,6 @@ void fsg_common_remove_lun(struct fsg_lun *lun);
141130

142131
void fsg_common_remove_luns(struct fsg_common *common);
143132

144-
void fsg_common_set_ops(struct fsg_common *common,
145-
const struct fsg_operations *ops);
146-
147133
int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
148134
unsigned int id, const char *name,
149135
const char **name_pfx);

drivers/usb/gadget/legacy/mass_storage.c

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,6 @@ static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
107107

108108
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
109109

110-
static unsigned long msg_registered;
111-
static void msg_cleanup(void);
112-
113-
static int msg_thread_exits(struct fsg_common *common)
114-
{
115-
msg_cleanup();
116-
return 0;
117-
}
118-
119110
static int msg_do_config(struct usb_configuration *c)
120111
{
121112
struct fsg_opts *opts;
@@ -154,9 +145,6 @@ static struct usb_configuration msg_config_driver = {
154145

155146
static int msg_bind(struct usb_composite_dev *cdev)
156147
{
157-
static const struct fsg_operations ops = {
158-
.thread_exits = msg_thread_exits,
159-
};
160148
struct fsg_opts *opts;
161149
struct fsg_config config;
162150
int status;
@@ -173,8 +161,6 @@ static int msg_bind(struct usb_composite_dev *cdev)
173161
if (status)
174162
goto fail;
175163

176-
fsg_common_set_ops(opts->common, &ops);
177-
178164
status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
179165
if (status)
180166
goto fail_set_cdev;
@@ -256,18 +242,12 @@ MODULE_LICENSE("GPL");
256242

257243
static int __init msg_init(void)
258244
{
259-
int ret;
260-
261-
ret = usb_composite_probe(&msg_driver);
262-
set_bit(0, &msg_registered);
263-
264-
return ret;
245+
return usb_composite_probe(&msg_driver);
265246
}
266247
module_init(msg_init);
267248

268-
static void msg_cleanup(void)
249+
static void __exit msg_cleanup(void)
269250
{
270-
if (test_and_clear_bit(0, &msg_registered))
271-
usb_composite_unregister(&msg_driver);
251+
usb_composite_unregister(&msg_driver);
272252
}
273253
module_exit(msg_cleanup);

0 commit comments

Comments
 (0)