Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb usbdi(9): Assert no concurrent aborts on a singl...



details:   https://anonhg.NetBSD.org/src/rev/1c8285880501
branches:  trunk
changeset: 363462:1c8285880501
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sun Mar 13 11:28:42 2022 +0000

description:
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.

diffstat:

 sys/dev/usb/usb_subr.c |   7 +++++--
 sys/dev/usb/usbdi.c    |  20 ++++++++++++++++++--
 sys/dev/usb/usbdivar.h |   4 +++-
 3 files changed, 26 insertions(+), 5 deletions(-)

diffs (101 lines):

diff -r 7fb86d1c863c -r 1c8285880501 sys/dev/usb/usb_subr.c
--- a/sys/dev/usb/usb_subr.c    Sun Mar 13 11:28:33 2022 +0000
+++ b/sys/dev/usb/usb_subr.c    Sun Mar 13 11:28:42 2022 +0000
@@ -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 @@
        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 @@
        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);
        }
diff -r 7fb86d1c863c -r 1c8285880501 sys/dev/usb/usbdi.c
--- a/sys/dev/usb/usbdi.c       Sun Mar 13 11:28:33 2022 +0000
+++ b/sys/dev/usb/usbdi.c       Sun Mar 13 11:28:42 2022 +0000
@@ -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 @@
        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 @@
                        /* 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);
 }
 
diff -r 7fb86d1c863c -r 1c8285880501 sys/dev/usb/usbdivar.h
--- a/sys/dev/usb/usbdivar.h    Sun Mar 13 11:28:33 2022 +0000
+++ b/sys/dev/usb/usbdivar.h    Sun Mar 13 11:28:42 2022 +0000
@@ -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_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;



Home | Main Index | Thread Index | Old Index