summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2015-01-13 16:03:19 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2015-01-13 16:03:19 +0000
commitf1f7085c2a28f8e0d1b498f95df67374782ec8eb (patch)
tree7efd6664494b11ef5c203ad81dc57fa35d368c25 /sys/dev
parent595c22cc6076ac139716da0a6961474458c121e1 (diff)
Always allow abort tasks to be scheduled, even if the device is beeing
detached, in order to prevent a deadlock situation. This situation can occur if the thread detaching a device is sleeping, waiting for all submitted transfers to finish, and the device's pipes have not yet been aborted. This can happen when a USB Ethernet device is being detached while a userland program is doing an ioctl(2). Abort tasks need to be able to run in such case since timed out transfers rely on them to be properly completed. ok deraadt@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/usb.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index ab8ce995603..ed8502a3642 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb.c,v 1.103 2014/12/18 10:44:17 mpi Exp $ */
+/* $OpenBSD: usb.c,v 1.104 2015/01/13 16:03:18 mpi Exp $ */
/* $NetBSD: usb.c,v 1.77 2003/01/01 00:10:26 thorpej Exp $ */
/*
@@ -298,8 +298,13 @@ usb_add_task(struct usbd_device *dev, struct usb_task *task)
{
int s;
- /* Don't add task if the device's root hub is dying. */
- if (usbd_is_dying(dev))
+ /*
+ * If the thread detaching ``dev'' is sleeping, waiting
+ * for all submitted transfers to finish, we must be able
+ * to enqueue abort tasks. Otherwise timeouts can't give
+ * back submitted transfers to the stack.
+ */
+ if (usbd_is_dying(dev) && (task->type != USB_TASK_TYPE_ABORT))
return;
DPRINTFN(2,("%s: task=%p state=%d type=%d\n", __func__, task,
@@ -455,12 +460,9 @@ usb_abort_task_thread(void *arg)
*/
task->state |= USB_TASK_STATE_RUN;
task->state &= ~USB_TASK_STATE_ONQ;
- /* Don't actually execute the task if dying. */
- if (!usbd_is_dying(task->dev)) {
- splx(s);
- task->fun(task->arg);
- s = splusb();
- }
+ splx(s);
+ task->fun(task->arg);
+ s = splusb();
task->state &= ~USB_TASK_STATE_RUN;
if (task->state == USB_TASK_STATE_NONE)
wakeup(task);