在云计算与超大规模数据中心中,内核升级通常意味着整机重启与服务中断。为了实现"零感知"升级,Linux 内核社区近年来相继引入了 KHO (Kexec HandOver,Kexec 内存与状态交接机制) 以及基于其构建的 LUO (Live Update Orchestrator,内核实时更新编排器) 技术。它们允许在新旧内核通过 kexec 切换时,将关键的内存页面、设备树信息乃至运行中的 VM/容器状态原封不动地交接给新内核。
然而,早期的 KHO 机制在设计上较为保守,采用了严格绑定的状态机模式。在近期提交的一系列内核重构补丁中,开发者对 KHO 架构进行了深度剥离与重构,推动其从一个"僵硬锁定的状态机"迈向 "完全无状态(Stateless)、支持动态重入" 的通用底层基础设施。
一、 核心痛点:旧架构的"僵硬"与"低效"
在重构之前,KHO 的工作流程存在几个致命的架构瓶颈:
-
状态被死死锁定 :旧版 KHO 依赖一套严格的状态机。一旦调用
finalization(完成最终化),保留内存集就会被强制"冻结"。驱动程序若想在中途新增或释放页面,必须先显式调用kho_abort()彻底清空当前状态重来。 -
操作顺序严重受限 :系统要求必须 先最终化 KHO 状态,才能加载 kexec 镜像。但在真实的运维场景中,运维人员希望在系统平稳运行时就提早加载好目标内核镜像(Load Early),直到重启前的最后一刻才对内存元数据进行最终刷新(Finalize Late)。
-
繁琐的 FDT 构建与重建:每次执行最终化,KHO 都要从零开始重新构建完整的扁平设备树(FDT)。一旦构建中途出错,还需要调用复杂的回滚清理代码。
二、 架构蜕变:四大维度的深度重构
本次提交的系列补丁针对上述痛点进行了精准的"瘦身"与架构重构成型:
1. 支持可重入:废除显式 kho_abort()
补丁彻底移除了 kho_abort() 函数,并将 kho_finalize() 重构为支持可重入(Re-entrant)。
-
新逻辑 :如果 KHO 已处于最终化状态,再次调用
kho_finalize()时,系统会自动清理并刷新上一次生成的旧元数据,直接生成一份最新状态。 -
解除冻结 :移除了内存保留 API(
kho_preserve_*/kho_unpreserve_*)中的状态检查。驱动程序在首次最终化后,依然可以自由地添加或释放页面,只需在修改完成后再次触发kho_finalize()刷新即可。
2. 时序解耦:实现"早加载,晚最终化"
得益于 KHO FDT 的物理内存地址早在系统启动阶段(kho_init)就已经静态固定,补丁放宽了 kexec_file_load 的检查条件。
内核镜像的加载不再依赖 KHO 是否完成最终化。运维系统可以在任意时刻将新内核载入内存,将最耗时的镜像加载与最后一刻的状态冻结完全解耦。
3. FDT 原地动态更新与单事实来源(Single Source of Truth)
-
动态维护 :废除了原本维护子设备树中间链表(
sub_fdts)并在最后一刻从零重建的逻辑。现在,系统在启动时直接初始化好空 FDT 树,子系统注册或卸载时,直接通过fdt_add_subnode和fdt_del_node在内存中原地(In-place)动态增删节点。 -
消除双重跟踪 :删除了结构体中的冗余字段
kho_out.preserved_mem_map。保留内存映射表头块的物理地址直接存放在 FDT 的preserved-memory-map属性中,让设备树成为全局唯一的权威数据源。
4. 高级内存分配器:大幅减少样板代码(Boilerplate)
针对驱动开发者,补丁封装了一套高层 API,将"内存分配/释放"与"KHO 保留/恢复"融为一体:
-
kho_alloc_preserve(size):一步完成"连续物理内存分配 + 清零 + KHO 标记保留"。 -
kho_free_unpreserve(ptr, size):当前内核中一步完成"取消保留 + 释放回伙伴分配器"。 -
kho_free_restore(ptr, size):新内核中恢复struct page状态并立即释放给新内核的分配器。
三、 细节打磨:健壮性与安全增强
除了架构级的重构,该补丁集还解决了一系列底层的安全与稳定隐患:
-
修复内存非对齐访问 Fault :由于设备树(FDT)节点属性不保证自然对齐,在某些 CPU 架构上直接通过指针读取 64 位值可能引发硬件对齐故障(Alignment Fault)。补丁改用安全的
memcpy()提取 64 位内存映射指针。 -
消除调试盲区与脏数据暴露 :不再根据 KHO 的状态动态隐藏
debugfs接口,而是在系统引导阶段即建立节点并对 FDT 空间做预清零(Pre-zero)处理。既保证了全生命周期的调试透明度,又防止将未初始化的敏感内存暴露给用户空间或下一代内核。 -
纠正概念误区 :修正了
kho_populate()中带有偏向性的日志。将原有的"Will skip init for some devices"剥离,明确了 KHO 仅仅是一个通用的跨重启内存保留机制 (可用于memfd、telemetry等),而"跳过设备初始化"只是上层 Live Update 驱动自身的特有行为。
四、 总结与展望
这套补丁集是 Linux 内核无缝更新技术演进中的关键一步。通过将 KHO 从繁重、僵硬的状态机中解放出来,使其具备了无状态、可重入以及高动态性的特点。
这不仅极大地简化了内核驱动的开发难度,更为上层的 Live Update Orchestrator (LUO) 提供了坚实、灵活的底层支撑,使云厂商和超大规模数据中心在进行内核热升级时,能够以更低的开销、更少的停机时间和更强的确定性完成系统迭代。
