Module Name: src Committed By: riastradh Date: Sat Jun 12 15:41:22 UTC 2021
Modified Files: src/sys/dev/usb: usb_subr.c usbdi.c Log Message: usb(4): Make usbd_fill_iface_data atomic. Now either it replaces and frees the old endpoints array, or it leaves everything in place; it never leaves a partial update nor requires the caller to free the old array. To generate a diff of this commit: cvs rdiff -u -r1.258 -r1.259 src/sys/dev/usb/usb_subr.c cvs rdiff -u -r1.213 -r1.214 src/sys/dev/usb/usbdi.c 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.258 src/sys/dev/usb/usb_subr.c:1.259 --- src/sys/dev/usb/usb_subr.c:1.258 Sat Jun 12 15:39:57 2021 +++ src/sys/dev/usb/usb_subr.c Sat Jun 12 15:41:22 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: usb_subr.c,v 1.258 2021/06/12 15:39:57 riastradh Exp $ */ +/* $NetBSD: usb_subr.c,v 1.259 2021/06/12 15:41:22 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.258 2021/06/12 15:39:57 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.259 2021/06/12 15:41:22 riastradh Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -444,6 +444,7 @@ usbd_fill_iface_data(struct usbd_device ifaceidx, altidx, 0, 0); struct usbd_interface *ifc = &dev->ud_ifaces[ifaceidx]; usb_interface_descriptor_t *idesc; + struct usbd_endpoint *endpoints; char *p, *end; int endpt, nendpt; @@ -453,18 +454,16 @@ usbd_fill_iface_data(struct usbd_device idesc = usbd_find_idesc(dev->ud_cdesc, ifaceidx, altidx); if (idesc == NULL) return USBD_INVAL; - ifc->ui_idesc = idesc; - ifc->ui_index = ifaceidx; - ifc->ui_altindex = altidx; - nendpt = ifc->ui_idesc->bNumEndpoints; + + nendpt = idesc->bNumEndpoints; DPRINTFN(4, "found idesc nendpt=%jd", nendpt, 0, 0, 0); if (nendpt != 0) { - ifc->ui_endpoints = kmem_alloc(nendpt * sizeof(struct usbd_endpoint), - KM_SLEEP); + endpoints = kmem_alloc(nendpt * sizeof(struct usbd_endpoint), + KM_SLEEP); } else - ifc->ui_endpoints = NULL; - ifc->ui_priv = NULL; - p = (char *)ifc->ui_idesc + ifc->ui_idesc->bLength; + endpoints = NULL; + + p = (char *)idesc + idesc->bLength; end = (char *)dev->ud_cdesc + UGETW(dev->ud_cdesc->wTotalLength); #define ed ((usb_endpoint_descriptor_t *)p) for (endpt = 0; endpt < nendpt; endpt++) { @@ -495,7 +494,7 @@ usbd_fill_iface_data(struct usbd_device } goto bad; found: - ifc->ui_endpoints[endpt].ue_edesc = ed; + endpoints[endpt].ue_edesc = ed; if (dev->ud_speed == USB_SPEED_HIGH) { u_int mps; /* Control and bulk endpoints have max packet limits. */ @@ -518,18 +517,28 @@ usbd_fill_iface_data(struct usbd_device break; } } - ifc->ui_endpoints[endpt].ue_refcnt = 0; - ifc->ui_endpoints[endpt].ue_toggle = 0; + endpoints[endpt].ue_refcnt = 0; + endpoints[endpt].ue_toggle = 0; p += ed->bLength; } #undef ed + + /* Success! Free the old endpoints and commit the changes. */ + if (ifc->ui_endpoints) { + kmem_free(ifc->ui_endpoints, (sizeof(ifc->ui_endpoints[0]) * + ifc->ui_idesc->bNumEndpoints)); + } + + ifc->ui_idesc = idesc; + ifc->ui_index = ifaceidx; + ifc->ui_altindex = altidx; + ifc->ui_endpoints = endpoints; + return USBD_NORMAL_COMPLETION; bad: - if (ifc->ui_endpoints != NULL) { - kmem_free(ifc->ui_endpoints, nendpt * sizeof(struct usbd_endpoint)); - ifc->ui_endpoints = NULL; - } + if (endpoints) + kmem_free(endpoints, nendpt * sizeof(struct usbd_endpoint)); return USBD_INVAL; } Index: src/sys/dev/usb/usbdi.c diff -u src/sys/dev/usb/usbdi.c:1.213 src/sys/dev/usb/usbdi.c:1.214 --- src/sys/dev/usb/usbdi.c:1.213 Sat Jun 12 15:40:07 2021 +++ src/sys/dev/usb/usbdi.c Sat Jun 12 15:41:22 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: usbdi.c,v 1.213 2021/06/12 15:40:07 riastradh Exp $ */ +/* $NetBSD: usbdi.c,v 1.214 2021/06/12 15:41:22 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.213 2021/06/12 15:40:07 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.214 2021/06/12 15:41:22 riastradh Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -867,9 +867,9 @@ usbd_set_interface(struct usbd_interface { usb_device_request_t req; usbd_status err; - void *endpoints; USBHIST_FUNC(); + USBHIST_CALLARGS(usbdebug, "iface %#jx", (uintptr_t)iface, 0, 0, 0); mutex_enter(&iface->ui_pipelock); if (LIST_FIRST(&iface->ui_pipes) != NULL) { @@ -877,23 +877,10 @@ usbd_set_interface(struct usbd_interface goto out; } - endpoints = iface->ui_endpoints; - int nendpt = iface->ui_idesc->bNumEndpoints; - USBHIST_CALLARGS(usbdebug, "iface %#jx endpoints = %#jx nendpt %jd", - (uintptr_t)iface, (uintptr_t)endpoints, - iface->ui_idesc->bNumEndpoints, 0); err = usbd_fill_iface_data(iface->ui_dev, iface->ui_index, altidx); if (err) goto out; - /* new setting works, we can free old endpoints */ - if (endpoints != NULL) { - USBHIST_LOG(usbdebug, "iface %#jx endpoints = %#jx nendpt %jd", - (uintptr_t)iface, (uintptr_t)endpoints, nendpt, 0); - kmem_free(endpoints, nendpt * sizeof(struct usbd_endpoint)); - } - KASSERT(iface->ui_idesc != NULL); - req.bmRequestType = UT_WRITE_INTERFACE; req.bRequest = UR_SET_INTERFACE; USETW(req.wValue, iface->ui_idesc->bAlternateSetting);