[Bug 278569] DMA bounce pages are not freed when DMA tag is destroyed

From: <bugzilla-noreply_at_freebsd.org>
Date: Wed, 24 Apr 2024 15:39:02 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=278569

            Bug ID: 278569
           Summary: DMA bounce pages are not freed when DMA tag is
                    destroyed
           Product: Base System
           Version: CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: dgorecki@sii.pl

Created attachment 250209
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=250209&action=edit
Kernel module reproducing the issue

The bounce pages for allocated DMA maps are never freed properly and leak when
destroying DMA tags.

The kernel sometimes needs to allocate bounce pages for DMA maps. When
unloading the DMA maps with bounce pages those bounce pages are returned to the
pool associated with DMA tag for later reuse when new maps are being loaded.
The kernel should free the pages when destroying the DMA tag, but this never
happens.

The issue is quite easy to reproduce by creating a kernel module, in which a
DMA tag is created and mapping the memory that does not meet the alignment
restrictions set in DMA tag. After this the map should be unloaded and DMA tag
destroyed. Doing this in a loop should soon crash the system.

The code allocating bounce pages can be seen in [1], when grepping the source I
can see that this is the only place when malloc with M_BOUNCE is called, but
there is no corresponding free anywhere.

I'm attaching a kernel module source for easy reproduction of the issue. The
module creates a dma tag which requires 64 alignment, allocates memory aligned
to 64 bytes and then immediately moves the pointer by 4 bytes to misalign it
and loads the DMA map with misaligned pointer. This forces the bounce page to
be created. Everything, including the DMA tag is then cleaned up. This
allocation/deallocation loop happens every second. When the module is loaded,
calling `vmstat -m | grep bounce` should show that M_BOUNCE malloc usage is
rising, even though everything should be freed properly. Additionally, one can
observe the bounce page malloc by using dtrace with one-liner `dtrace -n
'dtmalloc::bounce: {}'`. Dtrace should print malloc calls but no frees will be
visible.

I've seen the issue on arm64 and amd64, but it should be present on every
hardware platform.

[1] https://cgit.freebsd.org/src/tree/sys/kern/subr_busdma_bounce.c#n293

-- 
You are receiving this mail because:
You are the assignee for the bug.