Module Name: src
Committed By: riastradh
Date: Sun Mar 13 11:28:42 UTC 2022
Modified Files:
src/sys/dev/usb: usb_subr.c usbdi.c usbdivar.h
Log Message:
usbdi(9): Assert no concurrent aborts on a single pipe.
It is a driver bug to try to abort a pipe at the same time in two
different threads.
HCI drivers may release the bus lock to sleep in upm_abort while
waiting for the hardware to acknowledge an abort, so it won't try to,
e.g., scribble over a DMA buffer in the xfer that we've recycled
after usbd_abort_pipe returns.
If this happens, a concurrent usbd_abort_pipe might try to apply
upm_abort to the same xfer, which HCI drivers are not prepared for
and may wreak havoc.
To avoid this, allow only one usbd_abort_pipe in flight at any given
time.
To generate a diff of this commit:
cvs rdiff -u -r1.270 -r1.271 src/sys/dev/usb/usb_subr.c
cvs rdiff -u -r1.234 -r1.235 src/sys/dev/usb/usbdi.c
cvs rdiff -u -r1.135 -r1.136 src/sys/dev/usb/usbdivar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/usb/usb_subr.c
diff -u src/sys/dev/usb/usb_subr.c:1.270 src/sys/dev/usb/usb_subr.c:1.271
--- src/sys/dev/usb/usb_subr.c:1.270 Thu Mar 3 06:13:35 2022
+++ src/sys/dev/usb/usb_subr.c Sun Mar 13 11:28:42 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: usb_subr.c,v 1.270 2022/03/03 06:13:35 riastradh Exp $ */
+/* $NetBSD: usb_subr.c,v 1.271 2022/03/13 11:28:42 riastradh Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
/*
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.270 2022/03/03 06:13:35 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.271 2022/03/13 11:28:42 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_compat_netbsd.h"
@@ -948,6 +948,7 @@ usbd_setup_pipe_flags(struct usbd_device
SIMPLEQ_INIT(&p->up_queue);
p->up_callingxfer = NULL;
cv_init(&p->up_callingcv, "usbpipecb");
+ p->up_abortlwp = NULL;
err = dev->ud_bus->ub_methods->ubm_open(p);
if (err) {
@@ -967,6 +968,8 @@ usbd_setup_pipe_flags(struct usbd_device
err = USBD_NORMAL_COMPLETION;
out: if (p) {
+ KASSERT(p->up_abortlwp == NULL);
+ KASSERT(p->up_callingxfer == NULL);
cv_destroy(&p->up_callingcv);
kmem_free(p, dev->ud_bus->ub_pipesize);
}
Index: src/sys/dev/usb/usbdi.c
diff -u src/sys/dev/usb/usbdi.c:1.234 src/sys/dev/usb/usbdi.c:1.235
--- src/sys/dev/usb/usbdi.c:1.234 Sun Mar 13 11:28:33 2022
+++ src/sys/dev/usb/usbdi.c Sun Mar 13 11:28:42 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi.c,v 1.234 2022/03/13 11:28:33 riastradh Exp $ */
+/* $NetBSD: usbdi.c,v 1.235 2022/03/13 11:28:42 riastradh Exp $ */
/*
* Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.234 2022/03/13 11:28:33 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.235 2022/03/13 11:28:42 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -1020,6 +1020,16 @@ usbd_ar_pipe(struct usbd_pipe *pipe)
ASSERT_SLEEPABLE();
KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock));
+ /*
+ * Allow only one thread at a time to abort the pipe, so we
+ * don't get confused if upm_abort drops the lock in the middle
+ * of the abort to wait for hardware completion softints to
+ * stop using the xfer before returning.
+ */
+ KASSERTMSG(pipe->up_abortlwp == NULL, "pipe->up_abortlwp=%p",
+ pipe->up_abortlwp);
+ pipe->up_abortlwp = curlwp;
+
#ifdef USB_DEBUG
if (usbdebug > 5)
usbd_dump_queue(pipe);
@@ -1051,6 +1061,12 @@ usbd_ar_pipe(struct usbd_pipe *pipe)
/* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
}
}
+
+ KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock));
+ KASSERTMSG(pipe->up_abortlwp == NULL, "pipe->up_abortlwp=%p",
+ pipe->up_abortlwp);
+ pipe->up_abortlwp = NULL;
+
SDT_PROBE1(usb, device, pipe, abort__done, pipe);
}
Index: src/sys/dev/usb/usbdivar.h
diff -u src/sys/dev/usb/usbdivar.h:1.135 src/sys/dev/usb/usbdivar.h:1.136
--- src/sys/dev/usb/usbdivar.h:1.135 Wed Mar 9 22:17:41 2022
+++ src/sys/dev/usb/usbdivar.h Sun Mar 13 11:28:42 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdivar.h,v 1.135 2022/03/09 22:17:41 riastradh Exp $ */
+/* $NetBSD: usbdivar.h,v 1.136 2022/03/13 11:28:42 riastradh Exp $ */
/*
* Copyright (c) 1998, 2012 The NetBSD Foundation, Inc.
@@ -257,6 +257,8 @@ struct usbd_pipe {
struct usbd_xfer *up_callingxfer; /* currently in callback */
kcondvar_t up_callingcv;
+ struct lwp *up_abortlwp; /* lwp currently aborting */
+
/* Filled by HC driver. */
const struct usbd_pipe_methods
*up_methods;