开关查询函数,用于判断"页分配/释放的调试检查是否启用"。它配合free_page_is_bad()、check_new_page()等使用。
一、函数签名
static inline bool is_check_pages_enabled(void)
参数
无参数。
返回值
bool:true表示启用页检查;false表示不启用。
static inline
文件内私有 + 强制/建议内联。
在分配/释放热路径上被调用,必须零开销。
二、背景:页检查(check_pages)
什么是"页检查"?
free_page_is_bad()、page_expected_state()、check_new_page()、bad_page()等,都属于"页检查"机制:
分配新页后:检查页是否处于干净、可用的初始状态;
释放页前:检查页是否处于可安全释放的状态(refcount 为 0、无异常标志等);
发现问题 →
bad_page()报错 → 阻止操作,避免损坏扩散。
为什么需要开关?
页检查是调试功能:
在开发/调试内核(
CONFIG_DEBUG_VM)上启用,帮助发现 bug;在生产内核上禁用,避免热路径上的额外开销(每次分配/释放都要读
refcount、mapcount、flags等,成本不小)。
所以需要一个运行期/编译期的开关,让代码能根据配置决定是否执行检查。
三、典型实现
版本 A:基于静态键
static inline bool is_check_pages_enabled(void) { return static_branch_unlikely(&check_pages_enabled); }用静态键
check_pages_enabled控制。static_branch_unlikely():运行期绝大多数时间为 false(生产内核);
用静态键实现"关闭时零开销"。
开启时分支变成真实检查;关闭时被优化掉。
版本 B:基于编译配置
#ifdef CONFIG_DEBUG_VM static inline bool is_check_pages_enabled(void) { return true; } #else static inline bool is_check_pages_enabled(void) { return false; } #endif直接在编译期决定。
CONFIG_DEBUG_VM=y→ 总是 true;CONFIG_DEBUG_VM=n→ 总是 false(甚至被编译器优化掉,if (is_check_pages_enabled())整段删除)。
版本 C:基于静态键 + 默认值
#ifdef CONFIG_DEBUG_VM DEFINE_STATIC_KEY_TRUE(check_pages_enabled); #else DEFINE_STATIC_KEY_FALSE(check_pages_enabled); #endif static inline bool is_check_pages_enabled(void) { return static_branch_unlikely(&check_pages_enabled); }结合两者:编译期决定默认值,运行期可通过静态键动态开关(如调试时临时开启)。
这是较灵活的设计。
实际内核常见形式
现代内核中,类似函数常写作:
static inline bool is_check_pages_enabled(void) { return static_branch_unlikely(&check_pages_enabled); }配合:
#ifdef CONFIG_DEBUG_VM DEFINE_STATIC_KEY_TRUE(check_pages_enabled); #else DEFINE_STATIC_KEY_FALSE(check_pages_enabled); #endif
或直接用IS_ENABLED(CONFIG_DEBUG_VM)之类的编译期常量。
四、典型调用场景
1.free_pages_prepare()—— 释放前检查
static bool free_pages_prepare(struct page *page, unsigned int order, fpi_t fpi_flags) { ... if (is_check_pages_enabled()) { if (free_page_is_bad(page)) return false; /* 坏页,阻止释放 */ } ... }只有启用检查时,才做
free_page_is_bad()。关闭时直接跳过,零开销。
2.check_new_page()—— 分配后检查
static inline void check_new_page(struct page *page) { if (is_check_pages_enabled()) { if (!page_expected_state(page, PAGE_FLAGS_CHECK_AT_PREP)) bad_page(page, page_bad_reason(page, PAGE_FLAGS_CHECK_AT_PREP)); } }分配新页时校验。
3.check_pages_enabled静态键的开启/关闭
可能通过内核参数或 sysfs 动态控制:
static_branch_enable(&check_pages_enabled); static_branch_disable(&check_pages_enabled);
典型场景:
CONFIG_DEBUG_VM下默认开启;生产内核默认关闭,调试时可临时开。