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;