☰
page_alloc bad_page
2026/10/7 12:29:00 网站建设 项目流程

页结构损坏/异常时的报错函数。它是内核内存管理调试机制的"最后一道防线",在发现struct page状态异常时打印诊断信息并采取保护措施。


一、函数签名

static void bad_page(struct page *page, const char *reason)

参数

参数类型含义
pagestruct page *出问题的页
reasonconst char *出问题的原因描述(字符串字面量)

返回值

  • void:无返回值。

static

  • 文件内私有,只在page_alloc.c内部使用。

  • 由check_new_page()、free_pages_prepare()、bad_range()等调试检查调用。


二、作用

当内核在分配/释放/操作页时发现struct page的状态不符合预期,说明:

  • 页结构被损坏;

  • 引用计数错误;

  • 页的 flag 状态异常;

  • 页被重复释放/释放未分配页;

  • 页属于错误的 zone;

  • 等等。

此时bad_page()负责:

  1. 打印详细诊断信息(页地址、pfn、flags、引用计数、mapcount、原因等);

  2. 采取保护措施,避免损坏扩散。


三、典型实现

static void bad_page(struct page *page, const char *reason) { static unsigned long resume; static unsigned long nr_shown; static unsigned long nr_unshown; /* * 允许通过内核参数控制打印频率,避免刷屏 * (bad_page 可能被反复触发) */ unsigned long nr = ...; /* 如果不是第一次,可能只打印摘要或抑制 */ if (nr_shown == 0) pr_alert("BUG: Bad page state in process %s pfn:%05lx\n", current->comm, page_to_pfn(page)); /* 打印 page 详情 */ dump_page(page, reason); /* 打印调用栈,定位谁触发的 */ dump_stack(); /* 统计并可能抑制后续打印 */ ... /* * 重要:把 page 标记为"坏的",避免再次被使用 * 通常清除相关标志、设置 PageReserved 或类似, * 使该页不再参与分配。 */ ... }

(不同内核版本实现差异较大,早期版本有bad_page计数器nr_shown/nr_unshown抑制刷屏;现代内核更倾向于用dump_page()+dump_stack()+pr_alert。)

核心动作

1. 打印头部信息

pr_alert("BUG: Bad page state in process %s pfn:%05lx\n", current->comm, page_to_pfn(page));
  • pr_alert:最高日志级别,确保输出。

  • current->comm:当前进程名,帮助定位哪个进程触发的。

  • page_to_pfn(page):出问题的 pfn。

2. 打印页详情

dump_page(page, reason);
  • dump_page()(定义在mm/debug.c):

    • 打印 page 的 flags、refcount、mapcount、mapping、index 等;

    • reason作为附加说明;

    • 可能还会打印所属 zone、是否 slab、是否 compound 等。

3. 打印调用栈

dump_stack();
  • 打印当前调用栈,定位是哪个代码路径触发的 bad_page。

  • 这是调试的关键信息。

4. 抑制刷屏

  • 早期实现用静态变量resume、nr_shown、nr_unshown控制:

    • 第一次打印详细信息;

    • 后续可能只打印简要信息或按频率抑制;

    • 避免大量坏页导致日志爆炸、系统卡死。

  • 现代实现可能用printk_ratelimit()或类似机制。

5. 保护措施

  • 把 page 标记为"不再使用",防止损坏扩散。常见做法:

    • 清除PageBuddy、PageSlab等标志;

    • 设置引用计数为某个安全值;

    • 有时设置PageReserved,让伙伴系统忽略它;

    • 或者在严重情况下触发BUG()/ panic(取决于配置)。


四、为什么叫 "bad_page"?

  • 内核把状态异常的struct page称为 "bad page"。

  • 可能是:

    • 双重释放(double free):页已释放又被释放;

    • 释放未分配页:页从未分配就被释放;

    • 引用计数错误:_refcount异常;

    • zone 归属错误:页不属于它声称的 zone;

    • flags 异常:如既有PageBuddy又有PageSlab(互斥状态同时出现);

    • 内存损坏:物理内存位翻转、野指针写坏了 page 结构。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询