Linux-dma-buf-框架原理实现与应用详解
目录
Linux dma-buf 框架原理、实现与应用详解
1. 背景与意义
1.1 异构系统与缓冲区共享的挑战
在现代 SoC、嵌入式、图形和多媒体系统中,CPU、GPU、VPU、ISP、DMA 控制器等多个硬件单元需要高效地共享和传递大块数据(如图像帧、视频流、AI 张量等)。如果每个设备都维护独立的缓冲区,数据在设备间传递时就需要频繁拷贝,极大浪费带宽和内存,降低系统性能。
1.2 dma-buf 的目标
dma-buf 框架是 Linux 内核为解决“跨设备零拷贝缓冲区共享”而设计的通用机制。其核心目标包括:
- 跨驱动、跨设备共享物理缓冲区,避免冗余拷贝。
- 标准化缓冲区导出、导入、映射、同步等操作,简化驱动开发。
- 支持多种内存类型(系统内存、显存、专用区域等),适应复杂硬件架构。
- 支持同步机制(fence),保证多设备并发访问的数据一致性。
2. dma-buf 的核心原理
2.1 角色划分
- Exporter(导出者):负责分配和管理物理缓冲区的驱动(如 GPU、VPU、分配器等)。
- Importer(导入者):需要访问该缓冲区的其他驱动(如显示控制器、ISP、DMA 控制器等)。
- dma-buf 核心框架:为 exporter 和 importer 提供标准化的缓冲区共享、映射、同步等接口。
2.2 共享机制
- Exporter 通过
dma_buf_export()
导出一个物理缓冲区,获得一个struct dma_buf
对象,并为其分配一个匿名文件描述符(fd)。 - Importer 通过 fd 调用
dma_buf_get()
或dma_buf_attach()
,获得对该缓冲区的访问权。 - Importer 可通过
dma_buf_map_attachment()
将缓冲区映射到自己的设备地址空间,实现零拷贝访问。 - 多个 importer 可同时 attach 同一个 dma-buf,实现多设备并发访问。
dma-buf机制建立在 anon_inode之上,是 anon_inode技术一个重要应用示例。
2.3 同步机制
- dma-buf 支持 fence(同步栅栏)机制,保证多设备并发访问时的数据一致性。
- Exporter/Importer 可通过
dma_resv
对象管理读写 fence,协调访问时序。
3. 关键数据结构与实现
3.1 struct dma_buf_ops
dma_buf_ops
定义了 dma-buf 的所有操作接口,由 exporter 实现。
struct dma_buf_ops {
int (*attach)(struct dma_buf *, struct dma_buf_attachment *);
void (*detach)(struct dma_buf *, struct dma_buf_attachment *);
int (*pin)(struct dma_buf_attachment *attach);
void (*unpin)(struct dma_buf_attachment *attach);
struct sg_table *(*map_dma_buf)(struct dma_buf_attachment *, enum dma_data_direction);
void (*unmap_dma_buf)(struct dma_buf_attachment *, struct sg_table *, enum dma_data_direction);
void (*release)(struct dma_buf *);
int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction);
int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction);
int (*mmap)(struct dma_buf *, struct vm_area_struct *vma);
int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map);
void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map *map);
};
- attach/detach:设备 attach/detach 缓冲区时的回调。
- pin/unpin:锁定/解锁缓冲区,防止被移动。
- map/unmap_dma_buf:将缓冲区映射到设备地址空间。
- release:最后一个引用释放时的清理回调。
- begin/end_cpu_access:CPU 访问前后的同步操作(如 cache flush)。
- mmap/vmap/vunmap:内核/用户空间映射支持。
3.2 struct dma_buf
dma_buf
是 dma-buf 的核心对象,描述一个可共享的物理缓冲区。
struct dma_buf {
size_t size;
struct file *file;
struct list_head attachments;
const struct dma_buf_ops *ops;
unsigned vmapping_counter;
struct iosys_map vmap_ptr;
const char *exp_name;
const char *name;
spinlock_t name_lock;
struct module *owner;
struct list_head list_node;
void *priv;
struct dma_resv *resv;
wait_queue_head_t poll;
struct dma_buf_poll_cb_t cb_in, cb_out;
// ... 其他成员
};
- size:缓冲区大小。
- file:匿名文件,用于 fd 传递和引用计数。
- attachments:所有 attach 到该缓冲区的设备链表。
- ops:操作函数集。
- resv:同步对象,管理 fence。
- poll/cb_in/cb_out:支持用户空间 poll/epoll 事件通知。
3.3 struct dma_buf_attachment
描述一个设备与 dma-buf 的关联关系。
struct dma_buf_attachment {
struct dma_buf *dmabuf;
struct device *dev;
struct list_head node;
bool peer2peer;
const struct dma_buf_attach_ops *importer_ops;
void *importer_priv;
void *priv;
};
- dmabuf:关联的 dma-buf。
- dev:关联的设备。
- priv:exporter/importer 的私有数据。
3.4 struct dma_buf_export_info
导出 dma-buf 时的参数描述。
struct dma_buf_export_info {
const char *exp_name;
struct module *owner;
const struct dma_buf_ops *ops;
size_t size;
int flags;
struct dma_resv *resv;
void *priv;
};
4. 主要 API 及用法
4.1 Exporter 侧
4.1.1 导出缓冲区
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
exp_info.ops = &my_dma_buf_ops;
exp_info.size = buffer_size;
exp_info.priv = my_priv_data;
struct dma_buf *dmabuf = dma_buf_export(&exp_info);
4.1.2 获取 fd
int fd = dma_buf_fd(dmabuf, O_CLOEXEC);
4.1.3 释放缓冲区
dma_buf_put(dmabuf);
4.2 Importer 侧
4.2.1 通过 fd 获取 dma-buf
struct dma_buf *dmabuf = dma_buf_get(fd);
4.2.2 设备 attach
struct dma_buf_attachment *attach = dma_buf_attach(dmabuf, dev);
4.2.3 映射到设备地址空间
struct sg_table *sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
4.2.4 解除映射与 detach
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
dma_buf_detach(dmabuf, attach);
4.2.5 释放 dma-buf
dma_buf_put(dmabuf);
4.3 CPU 访问同步
dma_buf_begin_cpu_access(dmabuf, DMA_FROM_DEVICE);
// CPU 访问缓冲区
dma_buf_end_cpu_access(dmabuf, DMA_FROM_DEVICE);
4.4 用户空间 mmap
mmap(fd, ...); // 通过 fd 直接 mmap 到用户空间
5. dma-buf 的同步机制
5.1 dma_resv 与 fence
- dma-buf 通过
struct dma_resv
管理同步 fence,协调多设备并发访问。 - Exporter/Importer 在读写缓冲区前后添加/等待 fence,保证数据一致性。
- 支持隐式同步(如 GPU/显示管线)和显式同步(如用户空间 fence)。
5.2 begin_cpu_access/end_cpu_access
- 在 CPU 访问前后,需调用
begin_cpu_access
/end_cpu_access
,由 exporter 实现 cache flush、内存屏障等操作,保证数据一致性。
6. dma-buf 的典型应用场景
6.1 GPU-显示管线零拷贝
- GPU 渲染输出帧缓冲区,通过 dma-buf fd 传递给显示控制器(DRM/KMS),实现零拷贝显示。
6.2 摄像头-ISP-GPU 协作
- 摄像头驱动分配帧缓冲区,ISP 处理后通过 dma-buf fd 传递给 GPU 进行后处理或 AI 推理。
6.3 多媒体编解码
- VPU 解码器输出缓冲区,通过 dma-buf fd 传递给 GPU/显示/AI 单元,实现高效视频播放和处理。
6.4 用户空间跨进程共享
- 用户空间应用通过 dma-buf fd 在不同进程间共享大块数据(如图像、视频帧、AI 张量等)。
7. dma-buf 的内核实现细节
7.1 文件描述符与引用计数
- 每个 dma-buf 对象都对应一个匿名文件(anon_inode),通过 fd 传递和引用计数。anon_inode技术参见博文: 。
- 内核通过
get_dma_buf
/dma_buf_put
管理生命周期。
7.2 设备 attach/detach
- 每个 importer attach 时,exporter 可检查设备兼容性、DMA 约束等,拒绝不支持的设备。
- detach 时清理相关资源。
7.3 映射与同步
- map/unmap_dma_buf 负责将缓冲区映射到 importer 设备地址空间,支持多种内存类型和 DMA 方向。
- begin/end_cpu_access 负责 cache flush、内存屏障等同步操作。
7.4 poll/epoll 支持
- dma-buf 支持 poll/epoll 机制,用户空间可通过 poll/epoll 监控缓冲区 fence 状态,实现异步事件通知。
8. 总结
- dma-buf 是 Linux 内核支持异构系统、跨设备零拷贝缓冲区共享的核心机制。
- 通过标准化的导出、导入、映射、同步等接口,极大简化了驱动开发和系统集成。
- 支持多种内存类型、同步机制和异步事件通知,适应复杂硬件和高性能场景。
- 正确实现和使用 dma-buf 能显著提升系统性能、带宽利用率和开发效率。