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

Linux dma_resv机制原理、实现与应用详解

1. 原理

1.1 背景与需求

在现代Linux内核的显卡、视频、存储等子系统中,设备间共享内存缓冲区已成为常态。多个驱动、多个硬件单元可能并发访问同一缓冲区,且每个访问可能是异步的。如何在保证高性能的前提下,实现跨设备、跨驱动的同步与访问控制,是内核设计的难点。

传统的同步原语(如mutex、semaphore、completion等)主要用于进程/线程间同步,难以满足以下需求:

  • 跨设备/驱动同步:如GPU渲染、显示、视频编解码等场景,多个驱动需安全共享同一缓冲区。

  • 异步操作管理:如DMA传输、硬件加速等,操作完成时机不可预测。

  • 多种访问类型:如读、写、内核管理等,需区分不同类型的同步需求。

  • 高性能:避免不必要的阻塞和轮询,支持批量操作和回调机制。

为此,Linux内核引入了dma_resv(reservation object)机制,作为DMA-BUF等缓冲区的同步管理核心。dma_resv通过集成dma_fence机制,实现了高效、灵活的异步同步和访问控制

1.2 dma_resv的基本概念

dma_resv的核心思想是:为每个共享缓冲区维护一个“预留对象”,统一管理所有相关的同步栅栏(dma_fence),并区分不同的访问类型(如读、写、内核管理等)

主要目标:

  • 支持多种访问类型的同步(读、写、内核、bookkeep)

  • 支持批量管理多个dma_fence对象

  • 支持高效的迭代、查询和等待操作

  • 支持RCU安全访问和并发读写

  • 支持死锁保护和优先级继承(通过ww_mutex)

1.3 dma_resv与dma_fence的关系

dma_resv本质上是一个dma_fence的容器和管理者。每个dma_resv对象可包含多个dma_fence,分别表示不同类型的同步依赖。dma_fence负责异步操作的完成通知和回调,dma_resv负责整体的同步管理和访问控制。

dma_resv的典型应用场景:

  • DMA-BUF缓冲区的跨设备同步

  • TTM/DRM内存管理的访问控制

  • 显卡驱动的命令提交与依赖管理

  • 多媒体管线的异步协作

实现

2.1 核心数据结构

2.1.1 struct dma_resv
struct dma_resv {struct ww_mutex lock;                // 写侧锁,支持死锁保护struct dma_resv_list __rcu *fences;  // fence数组,RCU保护
};
  • lock:用于保护写操作,采用ww_mutex(wound-wait mutex),支持死锁检测和优先级继承。

  • fences:RCU保护的dma_fence数组,支持并发读写和安全迭代。

2.1.2 enum dma_resv_usage
enum dma_resv_usage {DMA_RESV_USAGE_KERNEL,   // 内核管理DMA_RESV_USAGE_WRITE,    // 隐式写同步DMA_RESV_USAGE_READ,     // 隐式读同步DMA_RESV_USAGE_BOOKKEEP  // 不参与隐式同步
};
  • 区分不同类型的同步需求,支持访问类型的优先级和升级。

2.1.3 struct dma_resv_iter
struct dma_resv_iter {struct dma_resv *obj;           // 关联的dma_resv对象enum dma_resv_usage usage;      // 当前迭代的usage类型struct dma_fence *fence;        // 当前处理的fenceenum dma_resv_usage fence_usage;// 当前fence的usageunsigned int index;             // 当前索引struct dma_resv_list *fences;   // fence数组unsigned int num_fences;        // fence数量bool is_restarted;              // 是否重启迭代
};
  • 支持高效的fence迭代和查询,兼容RCU和锁保护。

2.2 访问类型与优先级

dma_resv通过usage类型区分不同的同步需求,并定义了严格的优先级关系:

  • KERNEL < WRITE < READ < BOOKKEEP

  • 查询某一usage类型时,返回该类型及更低优先级的所有fence

  • fence可升级usage,但不可降级

这保证了写操作需等待所有读/写/内核操作完成,读操作只需等待写操作完成,bookkeep类型不参与隐式同步。

2.3 锁定与并发控制

2.3.1 写侧锁定

dma_resv采用ww_mutex作为写侧锁,支持死锁检测和优先级继承。典型用法:

dma_resv_lock(&obj, ctx); // ctx为死锁保护上下文
// ... 修改fences ...
dma_resv_unlock(&obj);
  • 支持trylock、interruptible lock、slowpath lock等多种模式

  • 支持多线程/多驱动并发写操作

2.3.2 读侧RCU保护

读操作采用RCU机制保护,支持并发读写和安全迭代。典型用法:

struct dma_resv_iter cursor;
dma_resv_iter_begin(&cursor, &obj, usage);
for (fence = dma_resv_iter_first_unlocked(&cursor); fence; fence = dma_resv_iter_next_unlocked(&cursor)) {// 处理fence
}
dma_resv_iter_end(&cursor);
  • fence数组采用RCU指针,支持安全替换和延迟释放

  • fence对象本身采用引用计数,避免UAF

2.4 fence的管理与操作

2.4.1 fence的添加与替换

dma_resv支持批量添加和替换fence:

dma_resv_reserve_fences(&obj, num_fences); // 预留空间
dma_resv_add_fence(&obj, fence, usage);    // 添加fence
dma_resv_replace_fences(&obj, context, fence, usage); // 替换指定context的fence
  • fence添加不可失败,保证命令提交的原子性
  • 支持按context和usage类型替换fence,灵活管理依赖关系
2.4.2 fence的查询与迭代

支持多种查询方式:

  • 获取所有fence:dma_resv_get_fences()
  • 获取单个fence:dma_resv_get_singleton()
  • 迭代所有fence:dma_resv_for_each_fence()dma_resv_for_each_fence_unlocked()
2.4.3 fence的等待与同步

支持批量等待和超时:

long dma_resv_wait_timeout(&obj, usage, intr, timeout);
  • 等待指定usage类型及更低优先级的所有fence完成

  • 支持中断和超时

  • 支持deadline hint优化

2.4.4 fence的升级与降级

fence可通过重复添加升级usage类型,但不可降级。这保证了同步语义的正确性。

2.5 RCU安全与内存管理

dma_resv的fence数组采用RCU指针,支持安全替换和延迟释放。fence对象本身采用引用计数,自动管理生命周期。

  • fence数组替换时,旧数组延迟释放,避免并发访问UAF

  • fence对象销毁时,自动释放所有引用

2.6 死锁保护与优先级继承

写侧锁采用ww_mutex,支持wound-wait死锁检测和优先级继承。多驱动/多线程并发写时,自动检测死锁并优雅恢复。

  • ctx为死锁保护上下文,支持多级锁定

  • 支持slowpath锁定,保证系统健壮性

2.7 典型API接口

dma_resv_init() / dma_resv_fini()://初始化/销毁对象dma_resv_lock() / dma_resv_unlock()://写侧锁定/解锁dma_resv_reserve_fences() / dma_resv_add_fence()://预留/添加fencedma_resv_replace_fences()://替换fencedma_resv_get_fences() / dma_resv_get_singleton(): //查询fencedma_resv_wait_timeout()://等待fence完成dma_resv_set_deadline()://设置deadline hintdma_resv_test_signaled()://测试fence是否完成dma_resv_describe()://调试信息输出

3. 应用

3.1 DMA-BUF跨设备同步

3.1.1 隐式同步

DMA-BUF机制通过dma_resv实现跨设备的隐式同步。每个DMA-BUF对象关联一个dma_resv对象,所有生产者/消费者设备通过添加/等待fence实现同步。

  • 生产者设备提交写fence

  • 消费者设备等待写fence完成后再读

  • 支持多种usage类型,灵活管理依赖关系

示例:

struct dma_buf *dmabuf = ...;
struct dma_resv *resv = dmabuf->resv;
dma_resv_lock(resv, NULL);
dma_resv_add_fence(resv, fence, DMA_RESV_USAGE_WRITE);
dma_resv_unlock(resv);
3.1.2 显式同步

用户空间可通过sync_file机制将fence导出为文件描述符,实现显式同步。内核通过dma_resv管理所有fence,实现高效的同步和错误传播。

3.2 GPU/DRM内存管理

3.2.1 TTM/DRM对象的访问控制

TTM/DRM内存管理采用dma_resv对象管理每个buffer的访问依赖。命令提交时,驱动通过添加fence实现依赖管理,后续操作通过等待fence保证数据一致性。

3.2.2 多设备协作

在多GPU、多显示、多视频协作场景,dma_resv实现了跨设备的同步和访问控制。每个buffer的所有依赖通过dma_resv统一管理,避免死锁和性能瓶颈。

3.3 多媒体管线异步协作

在Camera-ISP-GPU等多设备协作场景,dma_resv结合dma_fence实现了异步操作的串联和同步。每个环节的完成通过fence通知下游设备,保证数据流正确同步。

3.4 错误处理与超时恢复

dma_resv支持错误码传播和超时处理。驱动可在硬件异常、超时等场景下强制信号所有fence,并设置错误码,通知所有依赖者。

long ret = dma_resv_wait_timeout(resv, DMA_RESV_USAGE_WRITE, true, timeout);
if (ret == 0) {// 超时处理dma_fence_set_error(fence, -ETIMEDOUT);dma_fence_signal(fence);
}

3.5 性能优化与最佳实践

  • 优先使用批量操作和回调机制,避免轮询等待

  • 合理设置usage类型,提升并发性能

  • 正确管理引用计数和RCU,避免内存泄漏和UAF

  • 避免在持锁/中断上下文中等待fence,防止死锁

  • 利用deadline hint优化功耗和调度

3.6 与其他同步原语的对比

特性dma_resvmutexspinlockcompletionsemaphore
基本用途异步跨设备同步互斥临界区保护一次性事件计数资源
支持异步部分部分
支持批量
支持回调
支持RCU
支持优先级继承✓(RT)
典型场景DMA-BUF, GPU, 多媒体进程同步内核临界区事件通知资源管理

4. 总结

dma_resv作为Linux内核专门设计的异步同步管理机制,具备以下优势:

  • 高效的跨设备、跨驱动同步管理

  • 灵活的访问类型和优先级控制

  • 深度集成dma_fence机制,实现异步完成通知和回调

  • 支持批量操作、RCU安全、死锁保护和优先级继承

  • 丰富的调试和监控接口,便于系统调优和问题定位

在GPU、显示、视频、DMA-BUF等现代异构计算场景中,dma_resv已成为不可或缺的核心组件。

Synchronization of access is necessary precisely because the object is shared. 因为共享,所以同步。

推荐的学习路线为:

1. 先理解共享机制。参见博文:dma-buf机制。留意同步机制的使用即可;

2. 理解单个同步对象的机制和实现。参见博文:dma-fence机制;

3. 单个同步对象并不足以控制对共享对象多需求的异步访问,因此需要多个同步对象来控制,这就是本文的dma_resv。

如有帮助,请三连:点赞、收藏、加关注。

http://www.dtcms.com/a/389564.html

相关文章:

  • LangGraph 进阶学习
  • Alibaba Cloud Linux与 RHEL/CentOS版本对应关系
  • Python实现PDF文本与表格转换
  • 医疗行业数字化转型:构建安全合规、高效协同的智慧医疗文档管理新范式
  • 怎么看一个网址是否安全?
  • 【LLM】RAG架构如何重塑大模型
  • 企业级数据库管理实战(四):从 C/S 到 B/S架构,数据库管理工具的演进
  • 基于AI的PDF复杂表格结构识别与智能解析(方案1)
  • CS336第三课
  • 云蝠智能大模型呼叫对话延迟无限接近1秒
  • Datax-web安装 | 配置环境
  • 算法<java>——查找(顺序、二分、插值、分块、斐波那契)
  • Mysql杂志(十九)——InnoDB的索引结构
  • CrowdStrike推出AI驱动新工具 聚焦补丁管理与威胁情报短板
  • 收集飞花令碎片——C语言指针
  • MySQL 初识:架构定位与整体组成
  • 【开发者导航】规范驱动且开源的 AI 时代开发流程工具:GitHub Spec-Kit
  • 区块链加速器:Redis优化以太坊交易池性能方案
  • 资源分布的均衡性(Poisson Disk Sampling)探索
  • STM32开发(中断模式)
  • Qt QPieSlice详解
  • C++多线程编程
  • LangChain 父文档检索器:解决 “文档块匹配准” 与 “信息全” 的矛盾
  • COI实验室技能:基于几何光学的物空间与像空间的映射关系
  • springboot-security安全插件使用故障解析
  • 企业移动化管理(EMM)实战:如何一站式解决设备、应用与安全管控难题?
  • 高频面试题——深入掌握栈和队列的数据结构技巧
  • 【C++ qml】qml页面加载配置文件信息的两种方式
  • 运维笔记:神卓 N600 解决企业远程访问 NAS 的 3 个核心痛点
  • GitHub 热榜项目 - 日榜(2025-09-18)