dma-buf(DMA Buffer)是 Linux 内核中用于跨设备/跨驱动内存共享 的核心子系统。近年来,随着 AI 训练、大模型推理以及超高性能网络(如 400G/800G 网络)的爆发,数据在 GPU、网卡(NIC)、存储设备(NVMe)之间的零拷贝(Zero-copy)传输成为了刚需。dma-buf 已经从最初一个简单的"媒体设备间共享内存"的小工具,演变成了如今支撑现代 AI 数据中心、GPU 服务器超高性能通信的底层基石。
一、 什么是 dma-buf?
在传统 Linux 中,每个设备驱动(如显卡驱动、网卡驱动)都独立管理自己的内存。如果要把 GPU 里的数据通过网卡发出去,通常需要:
-
GPU 驱动将数据拷贝到系统内存(CPU 内存)。
-
CPU 将数据从内核空间拷贝到用户空间。
-
网卡驱动再将系统内存中的数据拷贝到网卡硬件中。
这种多次拷贝严重浪费了 CPU 周期和内存带宽。
dma-buf 改变了这一切。它提供了一个抽象的内存文件描述符(fd):
-
Exporter(导出者) :分配内存的驱动(如 GPU 驱动),将这块内存包装成一个
dma-buf并暴露一个文件描述符(fd)。 -
Importer(导入者):使用内存的驱动(如网卡驱动),通过这个 fd 获取内存的物理散射列表(Scatterlist),并将其映射到自己的 DMA 地址空间。
通过 dma-buf,网卡可以直接去读 GPU 的内存,实现硬件级别的零拷贝(P2P DMA)。
二、 dma-buf 在 RDMA 中的演进
RDMA(远程直接内存访问)天然追求极致的低延迟和高吞吐。为了让远程机器直接读写本地 GPU 内存(如 NVIDIA GPUDirect RDMA),RDMA 子系统(ib_core)对 dma-buf 的支持经历了几个重要阶段:
1. 早期阶段:用户态硬编码与私有内核 Peer-to-Peer
在 dma-buf 完善前,要实现 GPUDirect RDMA,需要 NVIDIA 驱动提供私有的内核符号(如 nvidia_p2p_get_pages),RDMA 驱动(如 Mellanox mlx5)去调用这些私有接口。这种方式没有统一的标准,无法进入 Linux 主线内核。
2. 标准化阶段:ib_umem_dmabuf 的引入 (约 2020-2021年)
Linux 内核引入了 ib_umem_dmabuf 机制。用户空间通过 GPU 驱动分配内存并获得 dma-buf fd,然后通过 RDMA 的 ibv_reg_dmabuf_mr(或通用的内存注册 ioctl)将这个 fd 注册为 RDMA 的内存区域(MR, Memory Region)。RDMA 核心层可以通过标准的 dma_buf_attach() 和 dma_buf_map_attachment() 接口获取 GPU 内存的 DMA 地址,不再依赖厂商私有驱动。
3. 动态内存管理与页面失效(Dynamic dma-buf)
早期的 RDMA 内存注册必须是常驻(Pinned)的,即内存不能被移动或释放。但 GPU 显存非常宝贵,GPU 驱动希望能动态回收或换出(Evict)显存。
内核引入了 dma_buf_move_notify 和 ODP(On-Demand Paging) 结合的机制。当 GPU 驱动需要移动这块显存时,会通过 dma-buf 的 peer 机制通知 RDMA 驱动让其硬件条目(TPT / MR)暂时失效,等 GPU 移动完后再重新建立映射,实现了高吞吐与灵活性的平衡。
三、 dma-buf 在 Netdev(传统网络子系统)中的演进
传统网络子系统(netdev)使用 sk_buff(skb)来传输数据。skb 默认设计是基于系统内存(CPU 内存)和页(struct page)的。随着 GPU 成为计算核心,传统网络栈对 struct page 的深度依赖成为了瓶颈,因为 GPU 显存或某些特殊的设备内存(Device Memory)在内核中不一定有对应的 struct page 结构。这导致传统的 send / recv 无法直接操作 dma-buf。
为了解决这一痛点,在 2026 年 Linux 存储、文件系统、内存管理和 BPF 峰会(LSFMM+BPF) 上,开发者们针对如何让 dma-buf 更加高效地服务于网络和存储展开了深入探讨。以下是本次峰会关于该技术的最新动态:
2026 LSFMM+BPF 峰会现场直击:io_uring 与 dma-buf 的融合趋势
内核的 dma-buf 子系统提供了一种在驱动程序之间共享内存缓冲区的方法,通常用于支持高效的设备到设备(device-to-device)I/O。在 2026 年 Linux 存储、文件系统、内存管理和 BPF 峰会(LSFMM+BPF)上,Pavel Begunkov 在 Kanchan Joshi 的协助下,主持了存储与内存管理轨道的联合会议,共同探讨如何让 dma-buf 的使用更加高效,并使其能够用于由用户空间发起的读写操作。
Begunkov 首先提到了 Keith Busch 在 2022 年提交的一套补丁。该补丁指出,虽然 dma-buf 可以促进高效的 I/O 操作,但在这些操作发生之前,通常需要进行大量昂贵的准备工作。这些工作包括创建各种内部数据结构、建立 DMA 映射,以及可能对 I/O 内存管理单元(IOMMU)进行的高昂配置。当必须为每次操作都创建一个新的 dma-buf 时,这些工作就不得不重复进行,从而导致大部分效率优势荡然无存。Busch 的解决方案是允许将 dma-buf 注册到 io_uring 子系统中,类似于 io_uring 支持注册文件和缓冲区的方式。这将允许注册的 dma-buf 在 io_uring 内部被重复使用,从而将设置成本分摊到多次操作中。
虽然那套补丁从未合并到主线中,但人们对这一概念的兴趣依然不减。Begunkov 带来了自己的一套补丁系列来扩展 Busch 的工作。他在会上表示,他的目标是创建一个一致的基础设施,以允许在网络和存储子系统中使用 dma-buf。他选择将 io_uring 的注册缓冲区(registered buffers)作为用户空间 API,并为 dma-buf 引入了一种特殊的注册操作。用户空间将从支持 dma-buf 的子系统中获取它,然后将关联的文件描述符(file descriptor)注册到 io_uring 中;此后,它就可以用于 I/O 操作了。
这项工作有一些核心要求。尽管使用了 io_uring 作为 API,但该机制的内部实现不应该与 io_uring 强绑定;它最终应该能够扩展到文件系统及更广泛的领域。此外,它还必须支持由 dma-buf 提供者触发的映射失效(map invalidation)机制。其内部 API 围绕着一个新的 io_dmabuf_token 结构展开,该结构是实现 dma-buf 的驱动程序与 io_uring 之间的接口。具体的 I/O 请求则通过 io_dmabuf_map 结构进行追踪,并由 iomap 子系统提供支持,以提供一种驱动程序特定的方式来迭代遍历 I/O 请求。该补丁系列正在推进中,但尚未完全准备就绪。
他说,偶尔会有人提出一个问题:是否应该将 P2PDMA(Peer-to-Peer DMA)用于此目的?然而,有几个原因导致 P2PDMA 并不足够。首先,P2PDMA 无法使用用户空间可能已经拥有的 dma-buf,而这是一个刚性需求。新的 API 可以支持更低成本的数据中间转换、更好地优化 IOMMU 的使用,并提供映射失效支持;对此,台下的一位听众指出,P2PDMA 其实也支持映射失效。当然,不使用 P2PDMA 的缺点是需要一套全新的 API,而且目前这套 API 还局限于 io_uring。
Begunkov 介绍到,其应用场景包括需要利用普通主机内存来优化 IOMMU 使用的应用程序。许多网络存储解决方案也可以从中受益,因为它可以方便地在网络接口和文件系统之间移动数据。显然,还有一家公司希望将该特性用于其 GPU 基础设施。Joshi 补充说,NVMe 子系统可以利用该特性来实现透传(pass-through)支持等功能。未来的计划还包括为更多的块设备驱动程序、SCSI 子系统以及文件系统添加支持。
一项 IOMMU 预映射(pre-mapping)基准测试显示,其性能提升最高可达 8.8倍。值得注意的是,预映射完全消除了在"延迟(lazy)"或"严格(strict)"模式下使用 IOMMU 所带来的性能惩罚------这两种模式都会在映射更改时执行一定量的 TLB 失效操作,以强制实现设备隔离。换句话说,为了获得满负荷的性能,人们不再需要使用在某些人看来安全性较低的 IOMMU 透传(pass-through)模式了。
然而,Jason Gunthorpe 感到疑惑:为什么透传模式还不够?预映射带来的额外复杂性又是如何体现其合理性的?Begunkov 回答说,摆脱透传模式的动力主要源于对安全性的考量。Gunthorpe 则认为,更好的解决方案是在操作完成后不保留 IOMMU 的映射。Christoph Hellwig 提到,一些数据中心开始强制要求使用 IOMMU,而且 IOMMU 所做内存合并(memory coalescing)对性能大有裨益,因此需要提供兼顾高性能的完整 IOMMU 支持;Gunthorpe 承认这些确实是很强有力的理由。Matthew Wilcox 建议,对缓冲区进行映射的时机正好可以用来对底层内存进行碎片整理,从而从根本上消除对内存合并的需求。
David Howells 担心,对 dma-buf 的误用(无论是无意的还是蓄意的)可能会因为耗尽所有可用的 IOMMU 插槽(slots)而引发问题,并询问该功能是否需要特定的权限(privilege)才能使用。Begunkov 赞同这确实可能成为一个问题,并表示将需要某种能力检查(capability check)机制。
Christian Brauner 对该功能仍在使用 scatterlists(散列表)这一事实提出了异议,因为开发者们最终希望淘汰这一内部 API;Hellwig 回答说,dma-buf 目前仍然需要 scatterlists,因此眼下还无法避免。随后,现场针对如何移除 dma-buf 对 scatterlists 的依赖进行了一些发散式的讨论,但 Hellwig 表示,不应该为了等待这项清理工作而搁置 Begunkov 的成果。随着会议时间耗尽,大家还讨论了未来如何支持文件系统访问的问题,不过目前尚未看到相关的补丁。
四、 尖端演进:dma-buf/devmem 与 netkit 的结合
到了 2024-2026 年,为了应对容器化 AI 基础设施(如 Kubernetes 中的 GPU 容器)对网络极致性能的追求,Linux 内核网络栈发生了一次重大变革,核心就是 devmem TCP 和 netkit 的结合。
1. TCP Devmem (dma-buf 基于 TCP 的非零拷贝/零拷贝接收)
由 Google 工程师主导的 TCP Devmem 补丁集并入主线。它允许网络协议栈直接将数据接收到通过 dma-buf 分配的设备内存(Device Memory,如 GPU 显存)中。
-
工作原理 :硬件网卡必须支持标头拆分(Header Split) 。网卡收到一个 TCP 报文时,把 TCP 标头(Header)放到系统内存中(供 CPU 协议栈处理),而把载荷(Payload,即真实的 AI 数据)直接通过 DMA 放到预先映射的 GPU
dma-buf块中。 -
这样,网络流在经过内核 TCP 协议栈时,CPU 只处理几百字节的 Header,而 G 级别的 Payload 实现了从网卡到 GPU 的纯硬件零拷贝接收 。用户态通过一个新的
recvmsg()标志(MSG_SOCK_DEVMEM)来获取包含dma-buf偏移量的元数据。
2. netkit:容器网络的下一代超车道
在云计算和 K8s 中,容器之间(或者容器与宿主机之间)通信通常使用 veth(Virtual Ethernet)设备。然而 veth 性能较差。netkit 是近两年引入的一种全新的内核虚拟网络设备(由 Meta 推进),旨在彻底取代 veth 用于容器网络。它与 eBPF 深度绑定,放弃了传统 veth 繁琐的排队重定向机制,直接在内核中进行极其高效的同宿主机容器间数据包传导。
3. 三者合一:dma-buf/devmem + netkit 的终极演进
当我们将 dma-buf/devmem 与 netkit 结合时,就诞生了当前 AI 容器网络的终极形态:容器间 GPU-to-GPU 的本地网络零拷贝。
-
场景:在同一台物理机(宿主机)上运行了两个 GPU 容器(例如 K8s 调度的大模型分布式训练节点),Container A 的 GPU 需要发送数据给 Container B 的 GPU。
-
演进后的路径:
-
两个容器的 GPU 内存都通过
dma-buf暴露并映射。 -
当 Container A 发送数据时,利用 TCP Devmem 机制,数据直接驻留在 GPU 内存中。
-
数据包进入
netkit设备,netkit内部的 eBPF 程序直接识别出目标是同台机器的 Container B。 -
netkit绕过所有物理网卡驱动和复杂的排队逻辑,直接将该数据包的引用(Payload 依然在dma-buf中)重定向到 Container B 的网络接收队列。 -
Container B 通过 Devmem 机制直接从自己的 GPU 内存或通过 P2P 访问对方的 GPU 内存读取数据。整个过程完全免除了 CPU 内存拷贝,将 AI 集群内部虚拟网络的损耗降到了接近于零的绝对极限。
-
五、 技术总结与演进脉络
| 阶段 / 领域 | 核心解决问题 | 核心技术 / 关键组件 |
|---|---|---|
| 基础 dma-buf | 解决跨驱动(如 V4L2 与 GPU)内存共享 | dma-buf fd, attach/map 抽象接口 |
| RDMA 演进 | 解决高带宽跨集群 GPU 零拷贝通信(如 InfiniBand/RoCE) | ib_umem_dmabuf, move_notify 动态页面失效机制 |
| Netdev 演进 | 解决传统网络协议栈无法直接处理无 page 结构设备内存的问题 | io_uring 预映射(Pre-mapping), 规避 IOMMU 频繁切换惩罚 |
| devmem + netkit | 解决 AI 容器化时代 宿主机内及跨机 TCP 网络的 GPU 极致零拷贝 | TCP Devmem (Header Split) + netkit (eBPF 驱动虚拟网卡) |
