From nobody Wed Oct 06 16:09:47 2021 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4BB8212BD926; Wed, 6 Oct 2021 16:09:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4HPfY81fqsz3v71; Wed, 6 Oct 2021 16:09:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 18B0F23203; Wed, 6 Oct 2021 16:09:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 196G9mMe047782; Wed, 6 Oct 2021 16:09:48 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 196G9lA4047781; Wed, 6 Oct 2021 16:09:47 GMT (envelope-from git) Date: Wed, 6 Oct 2021 16:09:47 GMT Message-Id: <202110061609.196G9lA4047781@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Ian Lepore Subject: git: 6fea4b82e7b8 - stable/12 - Fix busdma resource leak on usb device detach. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: ian X-Git-Repository: src X-Git-Refname: refs/heads/stable/12 X-Git-Reftype: branch X-Git-Commit: 6fea4b82e7b86ac680d5615f8361863353737325 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/12 has been updated by ian: URL: https://cgit.FreeBSD.org/src/commit/?id=6fea4b82e7b86ac680d5615f8361863353737325 commit 6fea4b82e7b86ac680d5615f8361863353737325 Author: Ian Lepore AuthorDate: 2021-09-28 19:29:10 +0000 Commit: Ian Lepore CommitDate: 2021-10-06 16:08:34 +0000 Fix busdma resource leak on usb device detach. When a usb device is detached, usb_pc_dmamap_destroy() called bus_dmamap_destroy() while the map was still loaded. That's harmless on x86 architectures, but on all other platforms it causes bus_dmamap_destroy() to return EBUSY and leak away any memory resources (including bounce buffers) associated with the mapping, as well as any allocated map structure itself. This change introduces a new is_loaded flag to the usb_page_cache struct to track whether a map is loaded or not. If the map is loaded, bus_dmamap_unload() is called before bus_dmamap_destroy() to avoid leaking away resources. Differential Revision: https://reviews.freebsd.org/D32208 (cherry picked from commit dc91a9715f8fda4b3633388830a28a99f73cbe59) --- sys/dev/usb/usb_busdma.c | 17 +++++++++++++---- sys/dev/usb/usb_busdma.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/sys/dev/usb/usb_busdma.c b/sys/dev/usb/usb_busdma.c index b7f0464c1767..9df2b243d232 100644 --- a/sys/dev/usb/usb_busdma.c +++ b/sys/dev/usb/usb_busdma.c @@ -611,6 +611,7 @@ usb_pc_alloc_mem(struct usb_page_cache *pc, struct usb_page *pg, bus_dmamem_free(utag->tag, ptr, map); goto error; } + pc->isloaded = 1; memset(ptr, 0, size); usb_pc_cpu_flush(pc); @@ -623,6 +624,7 @@ error: pc->page_start = NULL; pc->page_offset_buf = 0; pc->page_offset_end = 0; + pc->isloaded = 0; pc->map = NULL; pc->tag = NULL; return (1); @@ -637,12 +639,13 @@ void usb_pc_free_mem(struct usb_page_cache *pc) { if (pc && pc->buffer) { - - bus_dmamap_unload(pc->tag, pc->map); + if (pc->isloaded) + bus_dmamap_unload(pc->tag, pc->map); bus_dmamem_free(pc->tag, pc->buffer, pc->map); pc->buffer = NULL; + pc->isloaded = 0; } } @@ -674,7 +677,8 @@ usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t sync) * We have to unload the previous loaded DMA * pages before trying to load a new one! */ - bus_dmamap_unload(pc->tag, pc->map); + if (pc->isloaded) + bus_dmamap_unload(pc->tag, pc->map); /* * Try to load memory into DMA. @@ -687,6 +691,7 @@ usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t sync) err = 0; } if (err || uptag->dma_error) { + pc->isloaded = 0; return (1); } } else { @@ -695,7 +700,8 @@ usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t sync) * We have to unload the previous loaded DMA * pages before trying to load a new one! */ - bus_dmamap_unload(pc->tag, pc->map); + if (pc->isloaded) + bus_dmamap_unload(pc->tag, pc->map); /* * Try to load memory into DMA. The callback @@ -706,6 +712,7 @@ usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t sync) &usb_pc_load_mem_cb, pc, BUS_DMA_WAITOK)) { } } + pc->isloaded = 1; } else { if (!sync) { /* @@ -798,6 +805,8 @@ void usb_pc_dmamap_destroy(struct usb_page_cache *pc) { if (pc && pc->tag) { + if (pc->isloaded) + bus_dmamap_unload(pc->tag, pc->map); bus_dmamap_destroy(pc->tag, pc->map); pc->tag = NULL; pc->map = NULL; diff --git a/sys/dev/usb/usb_busdma.h b/sys/dev/usb/usb_busdma.h index d75e67eee8fe..d55ab5c00af0 100644 --- a/sys/dev/usb/usb_busdma.h +++ b/sys/dev/usb/usb_busdma.h @@ -102,6 +102,7 @@ struct usb_page_cache { * from the memory. Else write. */ uint8_t ismultiseg:1; /* set if we can have multiple * segments */ + uint8_t isloaded:1; /* Set if map is currently loaded. */ #endif };