资讯详情

page_alloc deferred_pages_enabled

📅 2026/10/6 16:13:35 | 华诺云谱 👁 阅读
page_alloc deferred_pages_enabled
涉及deferred pages延迟初始化页机制以及为它设计的一个__ref包装函数。逐块拆解。一、deferred_pages_enabled()—— 延迟页机制是否启用static inline bool deferred_pages_enabled(void) { return static_branch_unlikely(deferred_pages); }1.deferred_pages是什么一个静态键static key定义在别处通常是DEFINE_STATIC_KEY_TRUE/FALSE(deferred_pages)。它标记deferred pages 机制当前是否处于启用状态。初始通常是true启用因为启动早期伙伴系统还没完全初始化好。2. 背景为什么需要 deferred pages延迟页核心矛盾启动早期内存还没全部初始化完但已经有代码需要分配内存。伙伴系统初始化是分阶段的先初始化一部分内存让系统能跑起来再逐步初始化剩下的。在完全初始化之前如果某次分配发现某个 zone 的空闲内存不够正常路径会唤醒 kswapd → 但 kswapd 还没就绪直接回收 → 但 vmscan 还没就绪OOM → 显然不能。所以需要一种机制这个 zone 还有没初始化完的内存我先把它们初始化再重试分配。这就是deferred pages延迟初始化页把尚未加入伙伴系统的内存延迟到真正需要时再加入。deferred_grow_zone(zone, order)就是干这个的给 zone 补充grow尚未初始化的内存使其可用。3. 为什么用static_branch_unlikely静态键 unlikelydeferred_pages只在启动早期为 true之后永久关闭所有内存初始化完毕。运行期绝大多数时间它是 false所以分支预测应偏向不启用。static_branch_unlikely让编译器生成偏向 false 的代码当键被关闭时分支变成 NOP 或跳转几乎零开销。用静态键而非普通if (deferred_pages)这是长期不变、启动后固定的状态最适合静态键。关闭后deferred_grow_zone调用点被优化掉不浪费热路径性能。4. 调用点示意static struct page * get_page_from_freelist(gfp_t gfp, unsigned int order, ...) { ... if (deferred_pages_enabled()) if (_deferred_grow_zone(zone, order)) goto try_this_zone; // 重试分配 ... }即在get_page_from_freelist()里如果正常分配失败且 deferred pages 还启用就尝试补充 zone 内存然后重试。二、_deferred_grow_zone()——__ref包装函数/* * deferred_grow_zone() is __init, but it is called from * get_page_from_freelist() during early boot until deferred_pages permanently * disables this call. This is why we have refdata wrapper to avoid warning, * and to ensure that the function body gets unloaded. */ static bool __ref _deferred_grow_zone(struct zone *zone, unsigned int order) { return deferred_grow_zone(zone, order); }1. 问题__init函数被非__init代码调用deferred_grow_zone()被标记为__init__init表示只在初始化阶段使用。链接器会把它放到.init.text段初始化完成后整段内存被释放函数体被卸载。但它被get_page_from_freelist()调用而后者是运行期常驻函数不是__init。这会产生两个问题问题 1编译/链接警告内核有检查机制如modpost、section mismatch检查会警告非__init函数引用了__init函数。因为运行期调用一个已被卸载的函数是未定义行为。问题 2__init段被卸载后调用就悬空虽然实际上deferred_pages关闭后这个调用不会再发生但代码路径依然存在静态检查不认这个动态保证。2. 解决__ref包装static bool __ref _deferred_grow_zone(struct zone *zone, unsigned int order) { return deferred_grow_zone(zone, order); }__ref属性__ref是内核提供的一个标记告诉链接器/检查工具这个函数是有意引用__init代码的不要报警告。它把函数放到.ref.text段而非.init.text不会被卸载。用于这种运行期代码需要引用__init代码但动态保证只在启动早期调用的场景。包装的作用避免 section mismatch 警告引用__init的是__ref函数检查工具认可。保证函数体被卸载真正的deferred_grow_zone()仍是__init初始化后其代码被释放节省内存。间接层get_page_from_freelist()调用_deferred_grow_zone()常驻后者转调deferred_grow_zone()__init。3. 注释里的 refdata wrapper注释说 we have refdata wrapper__ref相关的还有__refdata用于数据这里用的是函数版__ref。refdata 是泛指这套 reference to init section 的机制。4. 安全性依赖这个包装本身不保证安全安全性依赖deferred_pages_enabled()在初始化完成后返回 falseget_page_from_freelist()只在deferred_pages_enabled()为 true 时才调用_deferred_grow_zone()所以运行期不会真正调用到已被卸载的deferred_grow_zone()。即动态条件保证正确性__ref只是让静态检查通过并允许段卸载。三、完整调用链与生命周期启动早期 deferred_pages true get_page_from_freelist() └── if (deferred_pages_enabled()) // true └── _deferred_grow_zone() // __ref常驻 └── deferred_grow_zone() // __init补充 zone 内存 ... 内存全部初始化完成 ... static_branch_disable(deferred_pages) // 永久关闭 运行期 deferred_pages false get_page_from_freelist() └── if (deferred_pages_enabled()) // false静态键跳过 // 不会调用 _deferred_grow_zone() deferred_grow_zone() 所在 .init.text 段已被释放四、与前面内容的呼应前面出现过的这里的关联vm_numa_stat_keyDEFINE_STATIC_KEY_TRUE同样是静态键deferred_pages也是static_branch_likely/unlikely这里用static_branch_unlikely因运行期几乎总是 false__read_mostly类似优化思路区分冷热数据/代码__init段卸载内核启动内存回收的一部分deferred_grow_zone是__init五、小结表代码作用deferred_pages静态键标记延迟页机制是否启用启动早期 true之后永久 falsedeferred_pages_enabled()用static_branch_unlikely零开销地检查该键deferred_grow_zone()__init函数补充 zone 尚未初始化的内存_deferred_grow_zone()__ref包装避免 section mismatch 警告允许__init函数体被卸载调用点get_page_from_freelist()分配失败时若机制启用则补充后重试一句话总结deferred_pages是一个静态键标记延迟初始化页机制是否启用——启动早期为 true分配失败时可通过deferred_grow_zone()补充 zone 内存并重试该函数是__init运行期会被卸载所以用__ref包装函数_deferred_grow_zone()转调既避免链接警告又允许其函数体被回收而正确性由静态键在初始化完成后永久关闭来保证。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑