summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2021-06-28 09:07:31 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-06-28 14:44:31 +0200
commit997cca0f15dcc8b8c96f542ac66c2eaad353f88e (patch)
tree941d04b2f898ecf622624feccb52d466413598fc /drivers/usb
parentc32343519de1774c09995118d0bae56999902a37 (diff)
downloadbarebox-997cca0f15dcc8b8c96f542ac66c2eaad353f88e.tar.gz
barebox-997cca0f15dcc8b8c96f542ac66c2eaad353f88e.tar.xz
bthread: replace blocking bthread_stop with nonblocking bthread_cancel
When bthread were first merged, they could be scheduled in any context and bthread_stop could just keep rescheduling until the bthread in question exits after which it would return the exit code. Now that bthreads are only scheduled in command context, bthread_stop also can only be scheduled in command context, making it much less useful and easier to shoot yourself in the foot with. Avoid this by introducing a bthread_cancel function instead that will asynchronously terminate the thread. For most purposes that should be fine, because bthread_stop is used to synchronize cleanup and we can move the cleanup into the thread instead. The only exception is the bthread command, which relies on being able to wait on bthreads to complete. For these __bthread_stop remains available, but should not be used in new code. This fixes a hang that is encountered when the usb mass storage gadget unbind is called from a poller leading barebox to wait indefinitely. Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Link: https://lore.barebox.org/20210628070732.16812-2-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/f_mass_storage.c51
1 files changed, 22 insertions, 29 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 0033a95f68..753042125d 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2335,9 +2335,12 @@ static void handle_exception(struct fsg_common *common)
/*-------------------------------------------------------------------------*/
-static void fsg_main_thread(void *common_)
+static void fsg_main_thread(void *fsg_)
{
- struct fsg_common *common = common_;
+ struct fsg_dev *fsg = fsg_;
+ struct fsg_common *common = fsg->common;
+ struct fsg_buffhd *bh;
+ unsigned i;
int ret = 0;
/* The main loop */
@@ -2376,6 +2379,21 @@ static void fsg_main_thread(void *common_)
if (ret && ret != -ERESTARTSYS)
pr_warn("%s: error %pe\n", __func__, ERR_PTR(ret));
+
+ usb_free_all_descriptors(&fsg->function);
+
+ for (i = 0; i < ums_count; i++)
+ close(ums[i].fd);
+
+ bh = common->buffhds;
+ i = FSG_NUM_BUFFERS;
+
+ do {
+ dma_free(bh->buf);
+ } while (++bh, --i);
+
+ ums_count = 0;
+ ums_files = NULL;
}
static void fsg_common_release(struct fsg_common *common);
@@ -2409,7 +2427,7 @@ static int fsg_common_init(struct fsg_common *common,
common->ep0 = gadget->ep0;
common->ep0req = cdev->req;
- thread_task = bthread_run(fsg_main_thread, common, "mass-storage-gadget");
+ thread_task = bthread_run(fsg_main_thread, common->fsg, "mass-storage-gadget");
if (IS_ERR(thread_task))
return PTR_ERR(thread_task);
@@ -2531,52 +2549,27 @@ close:
static void fsg_common_release(struct fsg_common *common)
{
- struct fsg_buffhd *bh;
- unsigned i;
-
/* If the thread isn't already dead, tell it to exit now */
if (common->state != FSG_STATE_TERMINATED) {
raise_exception(common, FSG_STATE_EXIT);
- __bthread_stop(thread_task);
- bthread_free(thread_task);
}
- bh = common->buffhds;
- i = FSG_NUM_BUFFERS;
-
- do {
- dma_free(bh->buf);
- } while (++bh, --i);
-
- ums_count = 0;
+ bthread_cancel(thread_task);
}
static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct fsg_dev *fsg = fsg_from_func(f);
- struct fsg_common *common = fsg->common;
- int i;
DBG(fsg, "unbind\n");
if (fsg->common->fsg == fsg) {
fsg->common->new_fsg = NULL;
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
-
- __bthread_stop(thread_task);
- while (common->fsg == fsg)
- bthread_reschedule();
}
- usb_free_all_descriptors(&fsg->function);
-
- for (i = 0; i < ums_count; i++)
- close(ums[i].fd);
-
fsg_common_release(fsg->common);
-
- ums_files = NULL;
}
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)