mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 00:32:25 -04:00
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 dc91a9715f)
This commit is contained in:
parent
4747ec0839
commit
b1cca74367
2 changed files with 14 additions and 3 deletions
|
|
@ -600,6 +600,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);
|
||||
|
|
@ -612,6 +613,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);
|
||||
|
|
@ -626,11 +628,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -662,7 +666,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.
|
||||
|
|
@ -675,6 +680,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 {
|
||||
|
|
@ -682,7 +688,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
|
||||
|
|
@ -693,6 +700,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) {
|
||||
/*
|
||||
|
|
@ -785,6 +793,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;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,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
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue