☰
page_alloc is_free_buddy_page
2026/10/22 2:17:10 网站建设 项目流程

is_free_buddy_page()是内核中用于可靠地检测一个页是否属于伙伴系统的空闲页的函数。它诞生于硬件毒化(HWPOISON)处理机制,因为伙伴系统中大多数空闲页并没有设置PG_buddy标志。

核心作用与设计动机

在伙伴系统中,只有空闲页块的首页(head page)才会设置PG_buddy标志,而页块内的其他页(尾页或中间页)不会设置。因此,如果仅通过PageBuddy(page)来判断,对于高阶空闲页块中的非首页,会得到错误的“非空闲”结论。

is_free_buddy_page()的设计目标就是穿透页块,找到真正标记了PG_buddy的首页,从而判断该页是否属于一个空闲的伙伴块。

核心实现逻辑

该函数的实现围绕“向上寻找页块首页”展开:

bool is_free_buddy_page(const struct page *page) { unsigned long pfn = page_to_pfn(page); unsigned int order; for (order = 0; order < NR_PAGE_ORDERS; order++) { const struct page *head = page - (pfn & ((1 << order) - 1)); if (PageBuddy(head) && buddy_order_unsafe(head) >= order) break; } return order <= MAX_PAGE_ORDER; }

核心步骤解析:

  1. 从 order 0 开始逐级向上查找:循环从order = 0遍历到NR_PAGE_ORDERS - 1。

  2. 计算当前 order 下的页块首页:page - (pfn & ((1 << order) - 1))。这通过pfn的位运算,快速定位到对齐到2^order的首页。

  3. 检查首页是否为空闲伙伴页:PageBuddy(head) && buddy_order_unsafe(head) >= order。如果首页设置了PG_buddy且其记录的 order 不小于当前 order,说明该页属于这个空闲块,跳出循环。

  4. 返回判断结果:如果循环在MAX_PAGE_ORDER内找到了符合条件的块,返回true;否则返回false。

历史演进:从加锁到无锁

该函数在 2009 年由 Wu Fengguang 引入,最初的实现在函数内部获取zone->lock。然而在 2021 年,Eric Dumazet 的补丁移除了这个锁。

移除的原因:

“Grabbing zone lock in is_free_buddy_page() gives a wrong sense of safety, and has potential performance implications when zone is experiencing lock contention.”

核心观点是:函数内部的加锁给人一种错误的“安全性”错觉,因为函数返回时锁已经释放,结果可能已经过时。如果调用者需要稳定的结果,应该自己在调用此函数前获取 zone 锁。

因此,现代实现中,该函数的文档明确标注:

“This function returns a stable result only if called under zone lock.”

同时,内部读取 order 时使用buddy_order_unsafe()而非普通的buddy_order(),以表明调用者需要自行保证并发安全。

总结

is_free_buddy_page()是伙伴系统的空闲页块探测工具:它通过逐级向上查找页块首页,判断给定页是否属于一个标记了PG_buddy的空闲块。其核心价值在于解决了“高阶空闲页块的非首页没有PG_buddy标志”的问题。2021 年后,它不再内部加锁,而是将并发安全的责任明确交给调用者——需要稳定结果的调用者必须自行持有zone->lock。

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

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

立即咨询