ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

page_alloc bad_page

page_alloc bad_page 页结构损坏/异常时的报错函数。它是内核内存管理调试机制的最后一道防线在发现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()负责打印详细诊断信息页地址、pfn、flags、引用计数、mapcount、原因等采取保护措施避免损坏扩散。三、典型实现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 归属错误页不属于它声称的 zoneflags 异常如既有PageBuddy又有PageSlab互斥状态同时出现内存损坏物理内存位翻转、野指针写坏了 page 结构。
返回列表