ZONE_DEVICE 介绍
原始问题:ZONE_DEVICE 是什么,有什么用 · 2026-08-05
ZONE_DEVICE 是什么,有什么用
📋 问题定位
- 所属子系统:内存管理(mm),核心文件
include/linux/mmzone.h、include/linux/memremap.h、mm/memremap.c、mm/migrate_device.c - 核心概念:
ZONE_DEVICE是 zone 枚举中最特殊的一个 zone;memory_type(5 种设备内存类型);dev_pagemap(设备内存元数据);memremap_pages()(注册入口)
🎯 原理说明
1. 它是什么:一个”只挂名、不参与分配”的 zone
在内核的 zone 体系中,ZONE_DEVICE 排在最末位(include/linux/mmzone.h:957):
enum zone_type {
ZONE_DMA,
ZONE_DMA32,
ZONE_NORMAL,
ZONE_MOVABLE,
#ifdef CONFIG_ZONE_DEVICE
ZONE_DEVICE,
#endif
__MAX_NR_ZONES
};
但它和其他 zone 有本质区别:ZONE_DEVICE 中的页面永远不进入 buddy 分配器、不出现在 LRU 链表中。用 Dan Williams 在 2017 LSFMM 的话说,它是”内存热插拔机制的上半部分”——它完成 struct page 的建立和映射,但不把页面”上线”给内核做普通分配。所以设备内存无法被 alloc_pages() 拿到,普通内存也无法被迁移进去(除了显式的设备迁移路径)。
它的存在意义只有一个:给非 CPU 侧内存(设备内存)分配 struct page,使它们能参与内核的统一内存管理基础设施(DMA 映射、迁移、页表映射、引用计数等)。
2. 五种设备内存类型(include/linux/memremap.h:68)
| 类型 | CPU 可访问性 | 典型硬件 | 关键约束 |
|---|---|---|---|
MEMORY_DEVICE_PRIVATE |
不可访问(非 cache-coherent) | GPU 显存(Nouveau/AMDGPU) | 必须提供 migrate_to_ram、folio_free 回调;CPU 访问触发 fault 迁回 |
MEMORY_DEVICE_COHERENT |
可访问且 cache-coherent | CXL 内存、CAPI | 允许进程页迁入;禁止 pin(必须可逐出) |
MEMORY_DEVICE_FS_DAX |
可访问 | 持久内存上的 DAX 文件系统 | 页被 pin 后需 wakeup 协调 truncate/hole punch |
MEMORY_DEVICE_GENERIC |
可访问 | DAX 字符设备暴露的内存 | 类似 System RAM 语义 |
MEMORY_DEVICE_PCI_P2PDMA |
可访问(non-cached) | PCIe BAR 内存 | 专用于设备间 DMA,pgprot_noncached |
3. 注册流程:memremap_pages()(mm/memremap.c:266)
设备驱动通过 devm_memremap_pages() 把一段设备物理地址范围注册为 ZONE_DEVICE:
dev_pagemap 描述(type/ops/owner/ranges)
│
▼
memremap_pages(pgmap, nid)
├─ 按 type 校验(PRIVATE 必须有 migrate_to_ram + folio_free + owner)
├─ 初始化 percpu_ref(引用计数,防止驱动卸载时页仍被使用)
└─ pagemap_range() 逐个 range:
├─ 建立 vmemmap(struct page 数组,可用 altmap 放在设备内存自身)
└─ 将 section 标记为 SECTION_TAINT_ZONE_DEVICE
struct dev_pagemap(include/linux/memremap.h:133)是这套机制的元数据结构:
struct dev_pagemap {
struct vmem_altmap altmap; /* vmemmap 元数据可下沉到设备内存 */
struct percpu_ref ref; /* 引用计数,防止 use-after-free */
enum memory_type type; /* 上表五种类型 */
unsigned long vmemmap_shift; /* 大 folio 化的 vmemmap(>0 表示 compound pages) */
const struct dev_pagemap_ops *ops;
void *owner; /* 驱动标识,防止跨驱动误访问 */
...
};
4. 核心工作流:以 GPU 私有内存为例(HMM/migrate_vma)
CPU 视角下,设备私有内存相当于”换出到显存的页”:
进程访问 GPU 页 → CPU page fault
│
▼
do_handle_mm_fault → migrate_to_ram 回调(驱动实现)
│ 把设备页数据迁回系统 RAM
▼
migrate_vma_setup() (mm/migrate_device.c:729)
├─ migrate_vma_collect() 收集 src/dst PFN 数组
├─ migrate_vma_unmap() 锁页 + 解除映射,检查是否被 pin
├─ 驱动分配目的内存并拷贝
├─ migrate_vma_pages() 迁移 struct page 状态
└─ migrate_vma_finalize() 更新 CPU 页表指向新页
这正是 Popple 在 2025 LSFMM 提到的痛点:migrate_vma 以 PFN 数组为粒度工作,页面变大后(huge page)接口变得笨重,他希望支持迁移时的大页拆分/合并。
💡 适用场景(结合你提供的 LWN 素材)
| 场景 | 类型 | 现状/进展 |
|---|---|---|
| GPU 异构计算(CUDA/OpenCL 统一地址空间) | PRIVATE | HMM 自 4.14 合入,Nouveau/AMDGPU 使用 |
| CXL 内存池化/内存扩展 | COHERENT | 内核热插拔 + devm_memremap_pages,可迁移但不可 pin |
| 持久内存 DAX | FS_DAX / GENERIC | struct page 引用计数 off-by-one 问题已在 6.15 修复(32 个 patch) |
| NVMe/GPU 间 P2P DMA | PCI_P2PDMA | 避免数据绕经 CPU 内存 |
| AI 训练数据设备侧本地化 | PRIVATE(file-backed 设想中) | Popple 提议让 device-private 页进入 page cache;社区共识:只支持只读共享,共享可写映射被 Wilcox/Bacik 明确反对(”terrible programming model”) |
与你 OLK 工作的强相关点:
- 你的 gmem(GPU 内存管理) 本质就是
MEMORY_DEVICE_PRIVATE的驱动侧实现 + migrate_vma 流程定制 - 可靠内存/CXL 场景对应
MEMORY_DEVICE_COHERENT,注意其”禁止 pin、必须可逐出”的约束,这与 ZONE_MOVABLE 的 pin 限制文章(Tatashin 的 patch)是同一类设计哲学:可迁移性是内存灵活性的前提
💡 收益效果
- 消除地址空间分裂:程序员不再需要区分系统内存/设备内存,
malloc的数据可透明迁移(2025 年 GPU 带宽 ~1TB/s vs PCIe 32GB/s,数据就地访问收益巨大) - 统一 struct page 抽象:DMA 映射、迁移、页表管理复用同一套机制,避免驱动各自为政(2017 年讨论中 pfn_t 方案因 SPARC64 cache aliasing 失败,最终回到”struct page 不可回避”的共识)
- 代价:struct page 开销(每 4KB 页 64 字节);2017 年讨论的”大页 struct page”问题至今未解决(会增加热路径开销);设备内存生命周期与驱动绑定,一旦驱动卸载而页仍被引用,需要 percpu_ref 兜底
💡 应用前景
- CXL 时代的关键基础设施:ZONE_DEVICE 是 CXL 内存进入内核的必经之路,
MEMORY_DEVICE_COHERENT直接支撑内存池化/分层内存 - 大页设备内存是下一站:Popple 的清理工作(6.15 引用计数修复)后,hugetlb/THP 级别的 device-private 页即将铺开(Balbir Singh 已发布 THP for device-private 系列);
dev_pagemap.vmemmap_shift字段已为 folio 化 vmemmap 预留 - file-backed device-private 页:方向已明确(page cache 特例 + 只读共享),但按社区共识会”做对为止、不做复杂化”——OLK 若跟进,建议先做只读路径
- 维护视角:上游 6.6 分支已包含完整 ZONE_DEVICE/HMM 框架(
CONFIG_ZONE_DEVICE/CONFIG_DEVICE_PRIVATE),OLK-6.6 的 gmem 补丁与上游 migrate_vma 的演进需持续同步,尤其注意 6.15 的 FS-DAX refcount 修复是否影响你们的 OOT 路径参考来源
include/linux/mmzone.h:956-959— ZONE_DEVICE 枚举定义include/linux/memremap.h:68-93— memory_type 五种类型注释include/linux/memremap.h:133— struct dev_pagemap 定义mm/memremap.c:266— memremap_pages() 注册入口mm/migrate_device.c:729— migrate_vma_setup() 迁移流程- 用户提供素材:LWN 2025 LSFMM(Popple)、LWN 2017 LSFMM(Dan Williams/HMM)、LWN 2021(ZONE_MOVABLE pin 限制)
参考来源
⚠️ 免责声明
本站内容均由 AI 基于公开知识辅助生成,仅供学习参考,请勿直接引用作为依据。作者不对信息的准确性、完整性及适用性作保证,亦不对因使用本站内容产生的任何损失承担责任。