当前位置: 首页 > news >正文

Linux dma-buf核心函数实现分析

1. 前言

Linux dma-buf 框架原理、实现与应用 一文中,介绍了dma-buf的框架和应用场景,这里再啰嗦一句:

DMA-BUF 允许一个驱动(Exporter,导出者)将自己管理的物理内存缓冲区以文件描述符(fd)的形式导出,其他驱动(Importer,导入者)通过 fd 获取该缓冲区的访问权,实现跨设备的高效数据共享。其核心思想是:

  • 以文件描述符为统一接口,屏蔽底层物理内存的分配与管理细节。

  • 通过引用计数、同步机制(如 fence)、附件(attachment)等,保证多方安全、同步地访问同一块物理内存。

  • 支持 mmap、vmap、CPU/GPU 访问、同步等多种操作。

2. 导出与导入的完整流程示例

2.1 导出(Exporter)流程

  1. 驱动分配物理缓冲区

    例如 GPU 驱动分配一块显存或系统内存。最常见的就是分配一个drm_gem_object。

  2. 填充 dma_buf_export_info

    • 设置 priv 指向私有缓冲区对象。

    • 设置 ops 为导出者实现的操作函数表。

    • 设置 sizeownerexp_name 等。

  3. 调用 dma_buf_export

    根据dma_buf_export_info,返回 struct dma_buf *dmabuf

  4. 调用 dma_buf_fd

    获得 fd,返回给用户空间。

  5. 用户空间传递 fd 给其他驱动/进程

2.2 导入(Importer)流程

  1. 用户空间将 fd 传递给导入驱动(如通过 IOCTL)

  2. 导入驱动调用 dma_buf_get

    通过dma_buf_get(fd) 获取 struct dma_buf *,增加引用计数。

  3. 调用 dma_buf_attach

    在 dma_buf 上创建 attachment,加入 attachments 链表。

  4. 调用 dma_buf_map_attachment

    获取物理页表(sg_table),进行 DMA 映射。

  5. 数据传输/处理

  6. 完成后 detach、put

    调用 dma_buf_detach、dma_buf_put,释放引用。

2.3 代码示例(伪代码)

导出端:

struct my_buffer *buf = my_buffer_alloc(...);DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
exp_info.priv = buf;
exp_info.ops = &my_dma_buf_ops;
exp_info.size = buf->size;
exp_info.owner = THIS_MODULE;
exp_info.exp_name = "my_exporter";struct dma_buf *dmabuf = dma_buf_export(&exp_info);int fd = dma_buf_fd(dmabuf, O_CLOEXEC);
return fd; // 返回给用户空间

导入端:

int fd = ...; // 用户空间传入struct dma_buf *dmabuf = dma_buf_get(fd);
struct dma_buf_attachment *attach = dma_buf_attach(dmabuf, my_device);
struct sg_table *sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
// 进行 DMA 操作
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);dma_buf_detach(dmabuf, attach);
dma_buf_put(dmabuf);

3. 导出端核心函数分析

核心函数入口dma_buf_export。关键调用路径和函数如下:

dma_buf_exportdma_buf_getfilealloc_anon_inodealloc_file_pseudo
struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
{struct dma_buf *dmabuf;struct dma_resv *resv = exp_info->resv;struct file *file;size_t alloc_size = sizeof(struct dma_buf);int ret;...//1. 生成filefile = dma_buf_getfile(exp_info->size, exp_info->flags);//2. 创建dmabufdmabuf = kzalloc(alloc_size, GFP_KERNEL);//3. 把传入的参数设置给dmabufdmabuf->priv = exp_info->priv;dmabuf->ops = exp_info->ops;dmabuf->size = exp_info->size;dmabuf->exp_name = exp_info->exp_name;dmabuf->owner = exp_info->owner;spin_lock_init(&dmabuf->name_lock);init_waitqueue_head(&dmabuf->poll);dmabuf->cb_in.poll = dmabuf->cb_out.poll = &dmabuf->poll;dmabuf->cb_in.active = dmabuf->cb_out.active = 0;INIT_LIST_HEAD(&dmabuf->attachments);if (!resv) {dmabuf->resv = (struct dma_resv *)&dmabuf[1];dma_resv_init(dmabuf->resv);} else dmabuf->resv = resv;ret = dma_buf_stats_setup(dmabuf, file);//4. 设置双向关联file->private_data = dmabuf;dmabuf->file = file;__dma_buf_list_add(dmabuf);return dmabuf;
}

有个dma_buf(这时已经是一个buf[存储在dmabuf的priv里]和file结合体了),就可以用dma_buf_fd来关联fd了。

int dma_buf_fd(struct dma_buf *dmabuf, int flags)
{int fd;if (!dmabuf || !dmabuf->file)return -EINVAL;fd = get_unused_fd_flags(flags);fd_install(fd, dmabuf->file);return fd;
}

4. 导入端核心函数分析

importer侧做的关键动作就是拿到fd后找到对应的dmabuf。这个动作的实现是dma_buf_get。

struct dma_buf *dma_buf_get(int fd)
{struct file *file;file = fget(fd);if (!file)return ERR_PTR(-EBADF);if (!is_dma_buf_file(file)) {fput(file);return ERR_PTR(-EINVAL);}//exporter时已经把dmabuf放到了file->private_datareturn file->private_data;
}

拿到dmabuf就可以继续访问dmabuf里的私有数据priv,可能就是一个drm_gem_object了。

5.设计哲学与安全性分析

5.1 统一接口与抽象

  • 以 fd 为统一抽象,简化用户空间与内核、驱动间的交互。
  • 通过 file_operations 实现多态,支持多种导出者/导入者。

5.2 引用计数与生命周期管理

  • 通过 file 的引用计数,自动管理 dma_buf 生命周期。
  • 导入者/导出者无需关心底层释放时机,防止悬挂指针。

5.3 同步与一致性

  • 通过 dma_resv、fence 等机制,保证多方访问的一致性与同步。
  • 支持隐式同步(poll、fence)与显式同步(ioctl、sync_file)。

5.4 安全性与隔离

  • 只暴露 fd,用户空间无法直接访问物理地址。
  • 通过权限、引用计数、锁等机制,防止资源泄漏与竞争。

DMA-BUF 框架通过 dma_buf_exportdma_buf_fddma_buf_getfile 等核心函数,实现了跨设备、跨驱动、跨进程的高效缓冲区共享。其设计充分利用了 Linux 文件系统、引用计数、同步等基础设施,既保证了高性能,又兼顾了安全性和易用性。

Everything is a file in Linux。好好理解这句话,建议读者去按下面的顺序去学习:

1. 理解linux里的file结构体以及与其相关的结构体;

2. 理解anon_inode,参见相关博文;

3. 理解本文dma_buf;

接下来理解DRM框架里的prime机制,该机制就是在dma-buf的机制上实现的。后续出一个专门介绍DRM prime机制是如何使用dma-buf的文章。

 


文章转载自:

http://Gjb9hJz2.jgykx.cn
http://5XsSgnBf.jgykx.cn
http://EqcmDD76.jgykx.cn
http://NPpxNyud.jgykx.cn
http://1w1lt8o1.jgykx.cn
http://HAqZTECQ.jgykx.cn
http://VB0r6NlP.jgykx.cn
http://2ydwPx2x.jgykx.cn
http://mdmXdVu3.jgykx.cn
http://41Ot3Wrh.jgykx.cn
http://eSz4Kqth.jgykx.cn
http://tg0BSjLQ.jgykx.cn
http://EsBZv88O.jgykx.cn
http://7xlBAUw4.jgykx.cn
http://N0tRUqXu.jgykx.cn
http://hbdkxUhu.jgykx.cn
http://h8GIJQdQ.jgykx.cn
http://QOiAyi23.jgykx.cn
http://zED6vJtQ.jgykx.cn
http://JC6lUvA9.jgykx.cn
http://6ziVIBeG.jgykx.cn
http://olDWOTTE.jgykx.cn
http://V6AAk8lH.jgykx.cn
http://JpfTNfAm.jgykx.cn
http://5VPb5Ckq.jgykx.cn
http://bqZpDBdz.jgykx.cn
http://ELHXJKOG.jgykx.cn
http://JnnegG14.jgykx.cn
http://AMSAI7fR.jgykx.cn
http://7P6D2bF8.jgykx.cn
http://www.dtcms.com/a/385637.html

相关文章:

  • vue3 实现前端生成水印效果
  • 手机上有哪些比较好用的待办事项提醒工具
  • 二维前缀和:模板+题目
  • 充电宝方案开发,充电宝MCU控制方案设计
  • 多品牌摄像机视频平台EasyCVR海康大华宇视视频平台统一接入方案
  • 香港云服务器数据盘可以挂载到多个实例吗?
  • 【C语言】用程序求1!+2!+3!+4!+...n!的和,来看看?
  • 【C++】浅谈智能指针
  • 第三章 神经网络入门笔记:从概念到实践全解析
  • 20250915在荣品RD-RK3588-MID开发板的Android13系统下使用TF卡刷机
  • 四元论的正确性数学原理
  • 你的第一个AI项目部署:用Flask快速搭建模型推理API
  • MyBatis-相关知识点
  • 【Nginx开荒攻略】Nginx配置文件语法规则:从基础语法到高级避坑指南
  • 【系统分析师】2024年下半年真题:论文及解题思路
  • Linux 标准输入 标准输出 标准错误
  • 【减少丢帧卡顿——状态管理】
  • pytest 常用方法介绍
  • 牛客周赛 Round 109 (小红的直角三角形
  • 【C++实战⑬】解锁C++文件操作:从基础到实战的进阶之路
  • 股票进阶之成交量买卖法
  • 【LangChain指南】Prompt templates
  • CSS基础 - 选择器备忘录 --笔记5
  • Vue-30-利用Vue3大模型对话框设计之切换主题时显示对应的session列表
  • 全光谱 LED 太阳光模拟器的原理
  • 权限更改centos中系统文件无法创建文件夹,使用命令让普通用户具备操作文件夹
  • 【WebGIS】Vue3使用 VueLeaflet + 天地图 搭建地图可视化平台(基础用法)
  • 69-SQLite应用
  • Day06 双指针扫描 | 11. 盛最多水的容器
  • LeetCode 刷题【77. 组合、78. 子集、79. 单词搜索】