2 kernel-migration-flow: 内核迁移主流程

发布时间:2026/8/9 18:43:36
2 kernel-migration-flow: 内核迁移主流程 本篇讲清楚一次UVM_MIGRATE从 ioctl 进入内核后的完整路径重点标注NUMA 目标节点dst_node_id/dest_nid在各层如何传递。1. 入口uvm_api_migrate()文件uvm_migrate.cuvm_api_migrate约 L860。主要职责解析UVM_MIGRATE_PARAMS把destinationUuid解析成目标处理器dest_gpu或 CPU。校验cpuNumaNode见文档 01 的合法性规则uvm_migrate.c。区分内存类型分派到不同实现UVM_API_RANGE_TYPE_NUMApageable透明访问→uvm_migrate_pageable()其它managed / HMM→uvm_migrate()。处理集成 GPU / CDMM / 关闭 pageable 迁移等特殊情形把目标改写为 CPU并把cpu_numa_node设为 GPU 的closest_cpu_numa_node见 uvm_migrate.c详见文档 04。// 集成 GPU迁到该 GPU 等价于迁到它最近的 CPU NUMA 节点if(dest_gpudest_gpu-parent-is_integrated_gpu){dest_idUVM_ID_CPU;cpu_numa_nodedest_gpu-parent-closest_cpu_numa_node;}2. Managed 内存uvm_migrate()文件uvm_migrate.c。2.1 把目标 NUMA 节点注入 service context关键一行——这是把用户请求的节点交给下游 make_resident 的地方service_context-block_context-make_resident.dest_niddest_nid;// uvm_migrate.c:626dest_nid即用户cpuNumaNode或被特殊硬件逻辑改写后的值。2.2 两遍two-pass策略见 uvm_migrate.c 大段注释。除非只覆盖单个 VA block 或带UVM_MIGRATE_FLAG_SKIP_CPU_MAP否则做两遍Pass 1搬运所有 VA block 的数据不建立映射Pass 2逐 block 复查可能被别人移动过并补建映射。目的避免「建立 CPU 映射同步」阻塞后续 block 的搬运并减少并发迁移间的假依赖。HMM 始终单遍。调用链uvm_migrate() └─ uvm_migrate_ranges() // 遍历 [base,len) 覆盖的 managed range └─ uvm_va_range_migrate() // 单个 range 内按 block 切分 └─ uvm_va_range_migrate_multi_block() └─ uvm_va_block_migrate_locked() └─ uvm_va_block_make_resident*() // 真正 make resident2.3 HMM 分支若无 managed rangeuvm_migrate_ranges()转uvm_hmm_migrate_ranges()uvm_migrate.c同样最终走 make_resident CPU chunk 分配NUMA 处理与 managed 一致。3. make_residentCPU 目标的核心文件uvm_va_block.c。当目标是 CPU 时uvm_va_block_make_resident*需要为目标页分配 CPU 物理内存并拷贝。分配这一步就是 NUMA 感知的落点由block_populate_pages_cpu()完成uvm_va_block.c详见 03-numa-node-selection。目标节点通过uvm_va_block_context_get_node()归一化uvm_va_block.cstaticintuvm_va_block_context_get_node(...){if(va_block_context-make_resident.dest_nid!NUMA_NO_NODE)returnva_block_context-make_resident.dest_nid;// 1) 迁移请求指定if(policy-preferred_nid!NUMA_NO_NODE)returnpolicy-preferred_nid;// 2) 首选位置策略returnnuma_mem_id();// 3) 就近兜底}make_resident上下文中与 NUMA 相关的字段uvm_va_block_types.h字段作用dest_id最终驻留处理器CPU / GPUdest_nid目标为 CPU 时的最终 NUMA 节点node_pages_mask计算「每个 CPU 节点对应哪些页」的临时掩码pages_migrated/pages_changed_residency结果掩码4. Pageable 内存uvm_migrate_pageable()文件uvm_migrate_pageable.c。与 managed 不同pageable 借助内核migrate_vma_setup/pages/finalize框架目标页由 UVM 自己alloc_pages_node()分配因此 NUMA 落点直接由dst_node_id决定。4.1 目标节点保存在uvm_migrate_args-dst_node_id结构见 uvm_migrate_pageable.h// dst_node_id may be clobbered by uvm_migrate_pageable().intdst_node_id;4.2 决定每页是否需要搬NUMA 判断migrate_vma_compute_masks()uvm_migrate_pageable.c里对每个源页判断src_nidpage_to_nid(src_page);// 已在目标节点 → 不搬if(src_niduvm_migrate_args-dst_node_id){...dst_resident...;continue;}// 目标是 CPU且该页已在某个「有 CPU 的」节点 → 不搬if(UVM_ID_IS_CPU(dst_id)node_state(src_nid,N_CPU)){...;continue;}// 目标是 CPU且源节点不是任何 GPU 的内存节点 → 不搬if(UVM_ID_IS_CPU(dst_id)!src_gpu){...;continue;}含义回迁到 CPU 时如果页面已经在某个 CPU NUMA 节点上默认不会为了「换个 CPU 节点」而搬除非它当前在 GPU 内存节点上。这是一个重要的性能取舍。4.3 分配目标页并校验落点uvm_migrate_vma_alloc_page()uvm_migrate_pageable.cdst_pagealloc_pages_node(uvm_migrate_args-dst_node_id,g_migrate_vma_gfp_flags,0);// 校验内核是否真的把页分到了目标节点规避历史内核 __GFP_THISNODE 未生效的 bugif(dst_pagepage_to_nid(dst_page)!uvm_migrate_args-dst_node_id){__free_page(dst_page);dst_pageNULL;// 视为 OOM触发用户态换节点重试协议}分配失败会最终以NV_ERR_MORE_PROCESSING_REQUIRED返回用户态对应文档 01 的重试协议。4.4dst_node_id NUMA_NO_NODE的处理pageable 路径要求确定节点在uvm_migrate_pageable()内部若dst_node_id NUMA_NO_NODEuvm_migrate_pageable.c会做相应处理/校验这也是为什么用户态对 pageable 传-1被判非法。5. 流程小结回迁到 CPU 的 NUMA 视角集成GPU/CDMM/禁用pageablemanaged/HMMpageable失败UVM_MIGRATE ioctluvm_api_migrate 校验 cpuNumaNodedstCPU, nodeclosest_cpu_numa_node内存类型uvm_migrate: make_resident.dest_nid cpuNumaNodeblock_populate_pages_cpuuvm_cpu_chunk_alloc __GFP_THISNODE 回退uvm_migrate_pageable: dst_node_idalloc_pages_node 校验落点NV_ERR_MORE_PROCESSING_REQUIRED → 用户态换节点下一篇 03-numa-node-selection 深入 managed/HMM 路径的 CPU chunk 分配与 per-node 驻留跟踪。

相关新闻