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