Skip to main content

Linux DMA-BUF Debugging Guide

1. Introduction​

DMA-BUF is a solution provided by Linux kernel for the issue: how to efficiently and securely share large memory buffers between different drivers and subsystems. Before the advent of DMA-BUF, every driver that required shared memory (e.g. graphics driver, video codec, camera driver) had its private sharing mechanism. This resulted in massive redundant development and compatibility issues.

For example, the DMA-BUF architecture in drm_gem is as follows:

DMA-BUF Architecture

2. Core Mechanism​

By providing a standard set of APIs and objects, the DMA-BUF framework separates buffer "ownership" and "usage rights" to establish a unified sharing model.

  • File descriptor abstraction:
    DMA-BUF binds physical buffers and file descriptors (FDs), enabling shared transfer across processes or devices via FDs.
  • Role-separated architecture:
    • Exporter: It allocates memory and implements the dma_buf_ops operations, including interfaces such as map_dma_buf, begin_cpu_access.
    • Importer: It obtains buffers' device address (e.g. IOVA) via dma_buf_attach and dma_buf_map_attachment, enabling direct hardware access.
  • Synchronization Mechanism:
    Asynchronous operations are synchronized via dma-fence and dma-resv to ensure data consistency during multi-device access.

3. Usage Method​

3.1 Kernel Configuration​

CONFIG_DMA_SHARED_BUFFER=y

3.2 Exporter​

static struct dma_buf *jpu_exp_alloc(struct jpu_alloc_dma_buf *alloc_data)
{
// Calculate the required pages
size = alloc_data->size;
npages = PAGE_ALIGN(size) / PAGE_SIZE;

// Allocate the data structure
data = kmalloc(sizeof(*data) + npages * sizeof(struct page *), GFP_KERNEL);

// Allocate the physical pages
for (i = 0; i < npages; i++) {
data->pages[i] = alloc_page(GFP_KERNEL);
}

// Configure the export information
exp_info.ops = &jpu_dmabuf_ops;
exp_info.size = npages * PAGE_SIZE;
exp_info.priv = data;

// export dma-buf
dmabuf = dma_buf_export(&exp_info);
return dmabuf;
}

The above example implements JPU memory allocation logic, allocating the corresponding physical pages according to requirement size. After allocation, it calls dma_buf_export to encapsulate these pages into a dma-buf object and then export it to the system.

3.3 Importer​

static int get_addr_from_dmabuf(struct v2d_info *v2dinfo,
struct v2d_dma_buf_info *pInfo,
dma_addr_t *paddr)
{
// Attach dma-buf to device
pInfo->attach = dma_buf_attach(pInfo->dmabuf, dev);

// Map attachment
pInfo->sgtable = dma_buf_map_attachment_unlocked(pInfo->attach, DMA_BIDIRECTIONAL);

if (sgt->nents == 1) {
addr = sg_dma_address(sgt->sgl); // Contiguous memory
} else {
// Multi-segment memory use IOMMU
addr = V2D_TBU_BASE_VA + (dma_addr_t)(pInfo->tbu_id)*V2D_TBU_VA_STEP;
size = v2d_iommu_map_sg(addr, sgt->sgl, sgt->orig_nents, flags);
}

*paddr = addr;
return 0;
}

V2D receives a dma-buf, attaches it to its own device, and then maps it to obtain a physical address (or IOMMU address) accessible to its hardware.

3.4 Interaction Logic​

DMA-BUF Interaction flow

The core of dma-buf is to achieve "zero-copy" memory sharing between different drivers through a file descriptor (fd).

  • Export and Transfer: JPU (exporter) allocates memory and exports an fd to a userspace application. The application then transfers it to the V2D (importer).
  • Import and Usage: V2D uses the FD to locate and map the memory, obtaining a physical address (or IOVA generated by the IOMMU) directly accessible by its hardware to process data directly.
  • Release: When both V2D and the userspace application have released their reference to the fd, the JPU automatically calls back and releases the original allocated memory.

4. Debugging Method​

4.1 /sys/kernel/dmabuf/buffers/​

Usage Method​

After enabling CONFIG_DMABUF_SYSFS_STATS, an interface will be created under '/sys/kernel/dmabuf/buffer/'.

  • Each subdirectory includes two files:
    • exporter_name: Records the driver name that exported the dma-buf (e.g. dma-buf-heap or i915).
    • size: Records the size of the dma-buf (in bytes)
  • When a dma-buf is destroyed, its corresponding directory is automatically removed.

Troubleshooting​

  • You can inspect the number of entries under /sys/kernel/dmabuf/buffers/ to confirm whether there is a dma-buf leak.
  • Count the number of dma-buf created by each exporter to identify the source of leak.

4.2 /sys/kernel/debug/dma_buf/bufinfo​

Example Export​

size flags mode count exp_name ino name
08847360 00000002 00080007 00000003 drm 00000089 1769-gnome-shell
write fence:drm_sched gfx seq 12146 signalled
Attached Devices:
Total 0 devices attached
  • size: buffer size;
  • flags: flags for the file descriptor (00000002 corresponds to O_RDWR, representing the buffer is opened in read-write mode);
  • mode: access authority mode of the file;
  • count: reference count of the buffer;
  • exp_name: name of the driver that exported this DMA-BUF;
  • ino: inode number of the file;
  • name: Name set for this buffer by Userspace;
  • write fence: ... signalled: indicates a write fence. signalled means the corresponding asynchronous operation (such as GPU rendering) has completed. If it remains unsignalled for a long time, a GPU hang may exist.
  • Attached Devices: lists all devices attached to this DMA-BUF. (The value is 0 in the example.)

Troubleshooting​

  • Debugging system freezes or application hangs: When the write fence on a display buffer remains unsignalled for an extended period, it typically indicates a GPU hang.