NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/58643: bus_dma(9) fails to bounce misaligned inputs requiring extra segments
>Number: 58643
>Category: kern
>Synopsis: bus_dma(9) fails to bounce misaligned inputs requiring extra segments
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Aug 25 19:10:00 +0000 2024
>Originator: Taylor R Campbell
>Release: current, 10, 9, ...
>Organization:
The NetBounceDMA Foundation
>Environment:
>Description:
In the x86 bus_dma(9) implementation (and, I suspect, many others, but I haven't checked), bus_dmamap_load and its variants may fail with EFBIG when the transfer is not, in fact, too large to fit in the DMA map.
Specifically, create a DMA map with:
- size=PAGE_SIZE
- nseg=1
- maxsegsz=PAGE_SIZE
- boundary=PAGE_SIZE
And then load it with a page-sized transfer that's not page-aligned; say it starts at some address n*PAGE_SIZE + k where 0 < k < PAGE_SIZE.
What happens is that bus_dmamap_load tries to split the transfer into two segments, one of size k and one of size PAGE_SIZE - k. And it runs head first into the limit on the number of segments, which is 1.
At this point it could bounce, but bus_dmamap_create didn't consider that possibility so it didn't allocate a bounce buffer so it won't bounce -- it will just fail with EFBIG, because it thinks there are too many segments.
>How-To-Repeat:
as above
>Fix:
Yes, please!
This might not be a common problem. But I suspect it is common in NIC drivers, which often have a workaround of manually defragmenting the mbuf instead of using a bounce buffer. It's not clear what the right tradeoff is here -- maybe changing bus_dmamap_create so that it preallocates a bounce buffer if this situation is possible would waste a lot of wired kernel memory; maybe having the caller allocate a bounce buffer on the fly is better, if most of the time that buffer isn't needed. Or maybe that's what BUS_DMA_ALLOCNOW is for. In any case, it's very much not obvious from the bus_dma(9) documentation that this might happen -- it _sounds_ like bus_dma(9) is supposed to take care of these details internally.
Home |
Main Index |
Thread Index |
Old Index