ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Linux 内核 dma-buf 子系统详解:跨设备共享缓冲区与隐式/显式同步机制

Linux 内核 dma-buf 子系统详解:跨设备共享缓冲区与隐式/显式同步机制 Linux 内核 dma-buf 子系统详解跨设备共享缓冲区与隐式/显式同步机制【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linuxdma-buf 是 Linux 内核中用于在多个设备驱动与子系统之间共享 DMA 缓冲区、并同步异步硬件访问的核心框架。本文基于内核仓库中的 dma-buf 驱动 API 文档 及配套源码drivers/dma-buf/ 目录完整讲解 dma-buf 的三大原语dma-buf、dma-fence、dma-resv、导出者/导入者角色分工、用户态 fd 接口细节、CPU 访问与锁约定以及“无期限 fence”与可恢复页错误带来的同步设计约束。读完本文你将能够理解缓冲区如何跨进程、跨设备共享并知道在驱动开发中如何正确接入 dma-buf 框架。一、核心架构三大原语dma-buf 子系统为“多驱动共享同一块 DMA 内存、且各自可能异步地读写它”这一场景提供了统一解决方案。典型场景是 DRM 子系统用它在不同进程、不同上下文、同进程内不同库 API 之间交换缓冲区并与 V4L2 等其他子系统交换缓冲区。整个框架由三个相互配合的原语构成dma-buf本质上代表一个sg_table分散/聚集列表表对用户态暴露为文件描述符fd。正因为是 fd它可以借助sendmsg/SCM_RIGHTS等机制在进程间、子系统间、设备间传递。核心数据结构是struct dma_buf实现在 dma-buf.c。dma-fence提供“异步硬件操作已完成”的信号机制。每个 fence 对应一个硬件操作如一次 GPU 命令批、一次 DMA 传输完成时通过dma_fence_signal()置位。实现在 dma-fence.c。dma-resvreservation object预留对象管理附着在某个 dma-buf 上的一组 dma-fence通过“共享 fence 独占 fence”的语义实现隐式内核排序同步从而在多个使用者并发访问时维持“一致性访问”的假象。实现在 dma-resv.c。三者关系可以概括为dma-buf 解决“数据怎么共享”dma-resv 解决“多个使用者之间怎么排队”dma-fence 解决“怎么知道某次硬件操作干完了”。文档同时指出若要从用户态 API 设计角度即如何为子系统设计 dma-buf 的分配与交换接口格式/modifier 协商等应参考 像素缓冲区交换指南。该文档以 DRM、V4L2 以及 Vulkan/EGL/Wayland 为例规定了格式DRM_FORMAT_*、modifier如DRM_FORMAT_MOD_LINEAR、每平面 offset/stride 等元数据的协商流程是 dma-buf 用户侧设计规范的配套文档。二、导出者exporter与导入者importer任何想加入 DMA 缓冲区共享体系的设备驱动都要以两种角色之一参与其中若驱动 A 要使用驱动 B 创建的缓冲区则B 是导出者exporterA 是缓冲区使用者/导入者buffer-user/importer。导出者的职责导出者对缓冲区拥有完整控制权具体包括实现并管理struct dma_buf_ops中定义的操作回调见 include/linux/dma-buf.h通过 dma-buf 共享 API 让其他使用者共享该缓冲区将缓冲区分配的私有细节封装在struct dma_buf中决定底层后备存储backing storage实际放在哪里负责 scatterlist 的迁移——对缓冲区的所有共享使用者透明生效。导入者的职责是众多共享使用者之一不需要关心缓冲区如何分配、分配在哪里需要的只是一个机制能拿到构成该缓冲区的 scatterlist 并映射到自己设备的地址空间从而访问同一块物理内存。这个接口由struct dma_buf_attachment提供。配置前提文档明确任何 dma-buf 框架的导出者或使用者必须在各自的 Kconfig 中声明select DMA_SHARED_BUFFER。对应的配置选项定义在 drivers/dma-buf/Kconfig。忘记这一项会导致dma_buf_export()等接口不可用。三、用户态接口细节对大多数用户态程序而言DMA 缓冲区 fd 只是一个不透明对象因此通用接口非常精简但文档强调了几个必须注意的行为。这些行为都可在 dma-buf.c 的dma_buf_fops文件操作表中找到对应实现。3.1 llseek探测缓冲区大小自内核 3.12 起dma-buf fd 支持llseek系统调用但只允许 offset0 且 whence 为SEEK_END或SEEK_SET的组合。SEEK_SET的支持是为了让惯用的“探测大小”写法size lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET)能工作其余任何llseek操作都返回-EINVAL。如果不支持该特性旧内核会对所有llseek调用返回-ESPIPE用户态可以用这一点探测llseek是否可用。源码实现见 dma_buf_llseek()SEEK_END返回dmabuf-sizeSEEK_SET返回 0其它 whence 一律-EINVAL。3.2 O_CLOEXEC必须原子地设置为防止 exec 时 fd 泄漏dma-buf fd 必须设置FD_CLOEXEC标志。文档特别强调这不只是资源泄漏问题而是潜在的安全漏洞——泄漏的 fd 会让新 exec 出来的程序访问本不允许其访问的缓冲区。如果创建后再单独调用fcntl()设置在多线程应用中存在竞态窗口当打开/创建 fd 的代码位于库中时问题更严重因为应用层可能根本不知道这个 fd 的存在。因此导出驱动对外提供的“创建 dma-buf fd”API必须让用户态能在创建时控制O_CLOEXEC标志该标志最终传入dma_buf_fd()。3.3 缓冲区大小也可从 fdinfo 查看除llseek外内核还实现了show_fdinfo见 dma_buf_show_fdinfo()可通过 procfs 查看 dma-buf 的size、引用计数count、导出者名exp_name及用户态设置的名字name便于调试时定位泄漏。四、设备 DMA 访问的基本操作流程这是驱动接入 dma-buf 的核心调用序列引自 dma-buf.c 中 dma buf device access 文档段共 4 步导出导出者用DEFINE_DMA_BUF_EXPORT_INFO()宏定义导出信息结构调用dma_buf_export()将私有缓冲区对象包装成struct dma_buf实现见 dma_buf_export()再通过dma_buf_fd()将其作为 fd 导出给用户态。注意dma_buf_export()会对必要操作做强制校验ops-priv、ops-map_dma_buf、ops-unmap_dma_buf、ops-release缺一不可且pin与unpin必须同时存在或同时缺省。附加用户态把 fd 传给所有要共享该缓冲区的驱动内核侧先用dma_buf_get()把 fd 转回struct dma_buf *再用dma_buf_attach()把设备附加到缓冲区上内部调用 dma_buf_dynamic_attach()。在此之前导出者仍可以自由迁移或重新分配后备存储。映射/解映射缓冲区附加到所有设备后用户态可发起 DMA 访问。内核侧通过dma_buf_map_attachment()和dma_buf_unmap_attachment()完成。实现见 dma_buf_map_attachment()对静态导入者若导出者实现了pin映射前会自动 pin 住后备存储映射的 sg_table 中 DMA 地址和长度保证是PAGE_SIZE对齐的映射存续期间后备存储被固定因此导入者不应长时间持有映射。清理驱动用完共享缓冲区后先调用dma_buf_detach()在此之前清理自己的映射再通过dma_buf_put()释放dma_buf_get()获取的引用。需要强调的是角色边界导出者决定存储位置并负责迁移导入者只拿到设备地址空间中的 scatterlist 视图对静态导入者内核在 map 时会替其等待内核侧 fencedma_resv_wait_timeout但动态导入者必须先自行等待 dma-resv 的独占 fence文档与源码注释都明确写出这一点。五、CPU 访问 DMA 缓冲区dma-buf 支持 CPU 直接访问文档归纳了三类动机见 dma-buf.c cpu access 文档段内核内的后备操作例如设备走 USB 连接时内核需要先把数据搬移整理再发送。此时用dma_buf_begin_cpu_access()/dma_buf_end_cpu_access()成对包裹访问以保证缓存一致性由于内核内部访问通常需要整个缓冲区额外提供了 vmap 接口void *dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map); void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map);vmap 可能因导出者不支持或 vmalloc 空间耗尽而失败在老 32 位架构上尤其如此。dma-buf 层对 vmap 访问维护引用计数只有第一个 vmap 时才真正调用导出者的vmap()最后一个 vunmap 时才真正解映射并发 vmap/vunmap 由dma_buf.lock互斥锁保护。注意dma_buf_vmap()要求调用者持有 dma-buf 的 reservation 锁源码中有dma_resv_assert_held断言。兼容既有用户态 mmap 接口许多处理管线软渲染图像喂给硬件管线、缩略图、截图等早已支持 mmap 缓冲区Android 的 ION 框架也支持这一点dma-buf fd 要替代 ION 缓冲就必须提供 mmap。用户态直接对 dma-buf fd 调用mmap即可但同样需要用 ioctl 成对包裹访问见下文DMA_BUF_IOCTL_SYNC且该 ioctl 可能返回-EAGAIN或-EINTR此时必须重试。标准序列为mmapdma-buf fd每个 CPU 绘制/上传周期1. 发SYNC_STARTioctl → 2. 读写 mmap 区域 → 3. 发SYNC_ENDioctl可任意多次重复新数据可被 GPU 或 scanout 设备消费不再需要时munmap。文档特别强调即使某些系统上不调用这些 ioctl 也“恰好能工作”用户态也不能依赖一致性访问为保证正确性和最优性能必须始终成对使用SYNC_START/SYNC_END。用户态处理管线的 CPU 后备导入子系统的用户态代码应能用与处理原生缓冲区对象相同的接口处理导入的 dma-buf——这对 DRM 尤其重要因为 OpenGL、X 等用户态驱动体系庞大改用其他 mmap 方式侵入性太强。当前 dma-buf 接口假设“重定向初始 mmap”就足够了。内核侧对应入口是 dma_buf_begin_cpu_access() 和dma_buf_end_cpu_access()前者先调用导出者的begin_cpu_access回调再通过dma_resv_wait_timeout()等待所有隐式同步 fence只对隐式同步的 DMA 事务有效——若 DMA 事务使用显式同步本函数只保证缓存一致性调用者须自行同步。六、隐式 Fence 轮询poll 支持跨设备、跨驱动的缓冲区访问同步通过隐式 fence 实现其“胶水”逻辑与 dma-resv 结构绑在一起。用户态可用poll()及相关系统调用查询这些隐式 fence 的状态见 dma-buf.c implicit fence polling 文档段检查EPOLLIN可读查询最近的写/独占 fence的状态——即“之前所有写者都完成了可以读了”检查EPOLLOUT可写查询所有已附着 fence共享 独占的状态——即“缓冲区完全空闲可以写入了”。注意poll 就绪只表示相应 fence 已完成、DMA 传输已结束缓存刷新以及 CPU 访问前的其它准备工作仍须自行处理。实现上dma_buf_poll() 会为 EPOLLOUT 和 EPOLLIN 分别注册独立的 fence 回调dma_buf_poll_add_cb通过dma_resv_for_each_fence()遍历相应用途的 fence 并挂上dma_buf_poll_cbfence 完成时回调经wake_up_locked_poll()唤醒等待者。每个 fd 每类事件最多有一个活动回调dcb-active位控制。作为poll()的替代当前附着在 dma-buf 上的一组 fence 可以通过dma_buf_sync_file_export导出为sync_file对应 fd 文件操作 sync_file.c供显式同步模型使用。七、DMA 缓冲区 ioctl 一览dma-buf fd 支持几个 dma-buf 专用 ioctl定义在 include/uapi/linux/dma-buf.h分发逻辑见 dma_buf_ioctl()ioctl参数结构用途DMA_BUF_IOCTL_SYNCstruct dma_buf_syncCPU 访问一致性同步mmap 区域访问前后成对调用DMA_BUF_SET_NAME字符串32 字节上限DMA_BUF_NAME_LEN为 dma-buf 设置名字以便追踪用途注意 uapi 中 32/64 位编号在 Android 上历史原因不一致DMA_BUF_SET_NAME_A/_BDMA_BUF_IOCTL_EXPORT_SYNC_FILEstruct dma_buf_export_sync_file把 dma-buf 当前的 fence 快照导出为 sync_file fdDMA_BUF_IOCTL_IMPORT_SYNC_FILEstruct dma_buf_import_sync_file把一个 sync_file 插入 dma-buf供隐式同步者等待7.1 SYNC ioctl 的标志语义struct dma_buf_sync.flags取值DMA_BUF_SYNC_READ (1 0) // 客户端将经 CPU map 读取 DMA_BUF_SYNC_WRITE (2 0) // 客户端将经 CPU map 写入 DMA_BUF_SYNC_RW (READ|WRITE) DMA_BUF_SYNC_START (0 2) // 访问会话开始 DMA_BUF_SYNC_END (1 2) // 访问会话结束内核侧将标志映射为 DMA 方向READ→DMA_FROM_DEVICEWRITE→DMA_TO_DEVICERW→DMA_BIDIRECTIONALSYNC_END调dma_buf_end_cpu_access()否则调dma_buf_begin_cpu_access()。uapi 头文件还明确警告DMA_BUF_IOCTL_SYNC只提供缓存一致性不阻止其他进程或设备同时访问内存与 GPU 等设备的同步要由客户端自行完成隐式同步可 poll dma-buf fd显式同步需等待 sync_file 等外部原语。7.2 EXPORT/IMPORT SYNC_FILE显式模型与隐式模型的桥DMA_BUF_IOCTL_EXPORT_SYNC_FILE用于把 dma-buf fd 上当前的 fence 集合导出为 sync_file供稍后等待——与“poll 等待当时挂着的 fence”不同它是快照式的特别适合 Vulkan 这类显式同步模型。dma_buf_export_sync_file() 通过dma_resv_get_singleton()取得单例 fence无 fence 时用dma_fence_get_stub()再创建 sync_file且新 fd 以O_CLOEXEC创建。推荐的三步使用模式引自 uapi 文档注释按预期 GPU 用途对应的 flags 导出 sync_file提交使用该 dma-buf 的渲染工作工作前先等导出的 sync_file完成时产出新的 sync_file用DMA_BUF_IOCTL_IMPORT_SYNC_FILE把“渲染完成”的 sync_file 导入 dma-buf。与隐式同步经 GPU 驱动 exec ioctl 一步完成不同上面不是原子操作——用户态必须用锁或其它机制保证第 1~3 步之间没有其他上下文添加 fence 或提交工作。dma_buf_import_sync_file() 会把 sync_file 内含的全部 fence经dma_fence_unwrap_for_each展开数组/链按 flags 用途READ→共享WRITE→独占批量加入 dma-resv。八、DMA-BUF 锁约定为避免导出者与导入者之间的死锁所有 dma-buf API 使用者必须遵守统一的锁约定见 dma-buf.c locking convention 文档段。这是驱动开发中最容易踩坑的部分务必完整记住导入者importers调用以下函数时必须持有dma-buf 的 reservation 锁dma_buf_pin()、dma_buf_unpin()dma_buf_map_attachment()、dma_buf_unmap_attachment()dma_buf_vmap()、dma_buf_vunmap()调用以下函数时必须不持有reservation 锁dma_buf_attach()、dma_buf_dynamic_attach()、dma_buf_detach()dma_buf_export()、dma_buf_fd()、dma_buf_get()、dma_buf_put()dma_buf_mmap()、dma_buf_begin_cpu_access()、dma_buf_end_cpu_access()以及各函数对应的_unlocked变体dma_buf_map_attachment_unlocked()、dma_buf_unmap_attachment_unlocked()、dma_buf_vmap_unlocked()、dma_buf_vunmap_unlocked()导出者exporters以下dma_buf_ops回调在未锁dma-buf reservation 时被调用导出者可以自行取锁attach()、detach()、release()、begin_cpu_access()、end_cpu_access()、mmap()以下回调在已锁状态下被调用导出者不得再取锁pin()、unpin()、map_dma_buf()、unmap_dma_buf()、vmap()、vunmap()导出者调用dma_buf_invalidate_mappings()时必须持有 reservation 锁该函数源码中有dma_resv_assert_held断言。从源码结构看这套约定在实现中是强制校验的如dma_buf_map_attachment()、dma_buf_pin()、dma_buf_vmap()入口都有dma_resv_assert_held()违反约定的代码在开了 debug 的内核里会直接触发警告。九、Reservation 对象dma-resv每个struct dma_buf都持有一个struct dma_resv *resv见dma_buf_export()中从exp_info-resv取回它是缓冲区同步状态的容器内部维护共享 fence 集合与独占 fence并带有内部锁与事件等待队列。共享/独占的语义使得内核可以在“读者之间并发、读写互斥、写者之间串行”的模型上自动排队各使用者提交的工作这正是隐式同步implicit synchronization能维持“一致性访问假象”的基础。其完整 APIdma_resv_add_fence()、dma_resv_wait_timeout()、dma_resv_for_each_fence()、dma_resv_get_singleton()等由 dma-resv.c 实现头文件在 include/linux/dma-resv.h。本文前文出现的 poll 实现、CPU 访问 fence 等待、sync_file 导出/导入全部构建在这组接口之上。十、dma-fence 及其辅助结构10.1 dma-fence 总览struct dma_fence是单个异步硬件操作的完成信号驱动在提交工作时创建或获取已有fence硬件完成后调用dma_fence_signal()置位等待方可以dma_fence_wait()、dma_fence_add_callback()或挂入 dma-resv 被动排队。关于 fence 的跨驱动契约cross-driver contract、signal 的注解约束signalling annotation例如回调中可做什么、以及 deadline hintsdma_fence_set_deadline()等供调度器参考任务紧迫度等详细规范分别见 dma-fence.c 中标注的 DMA fences overview、fence cross-driver contract、fence signalling annotation、deadline hints 文档段函数级参考见 include/linux/dma-fence.h。10.2 复合 fence数组与链dma_fence_arraydma-fence-array.c头文件 include/linux/dma-fence-array.h把一组 fence 组合成“全部完成才完成”的单一 fence常用于导入一个 sync_file 内含多个 fence 的场景——上文dma_buf_import_sync_file()正是先展开数组计数再逐个加入 dma-resv。dma_fence_chaindma-fence-chain.c头文件 include/linux/dma-fence-chain.h表示对同一资源上的顺序执行——链中每个元素完成后才轮转到下一个整体在最后一个元素完成时才完成。unwrap 工具dma-fence-unwrap.c头文件 include/linux/dma-fence-unwrap.h提供dma_fence_unwrap_signal/wait/add_callback/for_each等迭代器让调用者可以透明地“穿透”数组/链操作其内部的全部基元 fence。10.3 sync_file把 fence 暴露给用户态sync_filesync_file.c头文件 include/linux/sync_file.huAPI 定义 include/uapi/linux/sync_file.h把一组 dma-fence 包装成可 poll 的 fd是显式同步模型Vulkan 等与隐式同步模型OpenGL、多数媒体/视频驱动之间互通的桥梁。它与 dma-buf 的衔接即上文的 EXPORT/IMPORT SYNC_FILE ioctl另有一个纯软件实现 sw_sync.c 可在不依赖硬件 fence 的场景下产出 sync_file。十一、无期限 DMA fence为什么内核禁止“用户态控制完成时间”的 fence文档专章讨论了曾提出的几类“完成时间由用户态控制的 fence”Indefinite fencesFuture fencesHWC1 用它表示“缓冲区不再被显示使用”随使缓冲区可见的屏幕更新创建完成时刻完全由用户态决定Proxy fences处理drm_syncobj中尚未设置的 fence用于异步延迟命令提交用户态 fence / GPU futex命令缓冲区内跨引擎或 CPU 的细粒度锁再作为 DMA fence 导入以融入现有 winsys 协议长时计算命令缓冲区用传统的 batch 结束 fence 做内存管理而不是可随计算任务重新调度而重新附加的抢占上下文 fence。这些方案的共性是用户态控制 fence 的依赖关系和触发时刻。文档论证了无期限 fence 与内核内 DMA fence 混合不可行即使带保护性超时也不行原因是只有内核知道全部 DMA fence 依赖——用户态看不见内存管理和调度决策注入的依赖只有用户态知道无期限 fence 的全部依赖及其确切完成时刻——内核没有可见性。而且内核必须能够为了内存管理挂起用户态命令提交即必须支持“无期限 fence 依赖于 DMA fence”。若内核同时支持把无期限 fence 当作普通 DMA fence 使用就可能形成死锁环内核 DMA fence ──(memory management)── 用户态控制的 fence 内核 DMA fence ──(Future fence / proxy)── 用户态控制的 fence原文以 “Indefinite Fencing Dependency Cycle” 图描述该环。于是内核可能通过用户态不知情的内存管理依赖偶然制造死锁让从用户态视角毫无死锁的工作负载随机挂起到超时触发。在这种混合架构里不存在任何单一实体掌握全部依赖因此内核内部无法预防这类死锁。唯一解法是内核根本不允许无期限 fence 存在具体含义不接受无超时或带超时的 future fence、proxy fence、用户态 fence 被导入为 DMA fence当用户态被允许使用用户态 fence 或长时计算负载时不允许提供“以 batch 结束 fence 表示命令提交完成”的 DMA fence——意味着这些场景下共享缓冲区也不能使用隐式同步。十二、可恢复硬件页错误Recoverable Page Faults的影响现代硬件支持可恢复页错误这对 DMA fence 语义有一系列连带影响文档末章挂起的页错误会阻塞加速器上正在运行的工作且通常需要内存分配来解决。但内存分配不允许卡住 DMA fence 的完成——因此任何使用可恢复页错误的负载都不能用 DMA fence 做同步必须改用用户态控制的同步 fence。对 GPU 这是个现实矛盾Linux 上的桌面合成器协议依赖 DMA fence若不构建一套完全基于用户态 fence 的新用户态栈就享受不到可恢复页错误的收益隐式同步将不可用。例外是页错误仅作迁移提示、从不做按需内存填充的情形。目前这意味着 GPU 上的可恢复页错误限于纯计算负载。3D 渲染与计算通常共享硬件资源计算单元、命令提交引擎。若一个带 DMA fence 的 3D 任务和一个依赖页错误的计算任务同时挂起可能死锁3D 任务等计算任务释放硬件资源计算任务卡在页错误上而解决页错误所需的内存分配又在等 3D 任务的 DMA fence。驱动必须确保以下任一机制以防止该问题计算负载总能被抢占即使页错误尚在处理中并非所有硬件支持DMA fence 负载与需页错误处理的负载使用独立的硬件资源保证前进例如专用引擎并给 DMA fence 负载做最小计算单元预留上述预留可进一步细化为仅在 DMA fence 负载在途时预留——时间窗口必须覆盖“从 fence 对其他线程可见到dma_fence_signal()完成置位”的整段最后手段若硬件没有可用的预留机制则在“需要 DMA fence 的作业”与“需要页错误处理的作业”之间切换时冲刷GPU——即所有 DMA fence 完成后才能把带页错误的计算任务入队反之在某个 DMA fence 于系统任何位置可见之前必须先抢占所有计算负载保证所有挂起的 GPU 页错误被冲刷掉一个相当理论化的选项是在解决页错误的内存分配时解开依赖环独立内存块或运行时跟踪全部 DMA fence 依赖图——这会大范围影响内核因为 CPU 侧解决页本身就可能触发页错误把页错误处理的影响限制在特定驱动内部要可行和健壮得多。文档还指出运行在独立硬件拷贝引擎、其他 GPU上的负载不受影响因此内核内部在解决硬件页错误时仍可使用 DMA fence例如用拷贝引擎清理/拷贝解决页错误所需的内存。最后该页错误问题可视为“无期限 fence”讨论的特例计算负载的“无限 fence”允许依赖 DMA fence反之不行且页错误问题并非全新——用户态某个线程也可能命中页错误从而卡住一个用户态 fence。十三、驱动开发实践要点小结结合全文向 dma-buf 框架接入一个驱动时应遵循Kconfig中select DMA_SHARED_BUFFER导出者用DEFINE_DMA_BUF_EXPORT_INFO()填好size、ops、priv、resv、exp_name、owner后调用dma_buf_export()再dma_buf_fd(dmabuf, flags)导出 fdflags 中让用户态可控地传入O_CLOEXEC导入侧严格按get → attach → map/unmap → detach → put序列操作锁状态遵守“必须持锁 / 必须不持锁”两组约定pin/unpin只用于 scanout 等受控的长时固定场景绝不允许用户态任意 pin 住大量缓冲区CPU 访问一律用begin/end_cpu_access内核或mmap SYNC_START/SYNC_END ioctl用户态成对包裹且不能依赖“不调同步调用也恰好能工作”的机器需要跨驱动排队的场景依赖 dma-resv 的隐式同步poll 的 EPOLLIN/EPOLLOUT 语义分别对应“可读”与“可写”需要与显式同步模型互通时走 EXPORT/IMPORT SYNC_FILE不要尝试引入“完成时间由用户态决定”的 fence——依赖环死锁在内核内部无法预防。相关实现入口汇总核心框架 dma-buf.c、预留对象 dma-resv.c、fence dma-fence.c、复合 fence dma-fence-array.c / dma-fence-chain.c / dma-fence-unwrap.c、用户态同步 sync_file.c、通用内存池 dma-heap.cdmabuf heaps 用户态接口用户侧缓冲区交换 API 设计规范见 dma-buf-alloc-exchange.rst。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表