☰
page_alloc __alloc_frozen_pages_noprof
2026/10/13 6:56:41 网站建设 项目流程

__alloc_frozen_pages_noprof()是 Linux 伙伴系统分配路径的核心主入口,也是alloc_pages()系列宏最终展开调用的函数。它的名字包含三层信息:双下划线__表示内部主函数,frozen表示返回的页处于“引用计数已设置”的状态,noprof表示这是不带 profiling 钩子的底层实现。

核心职责

它的职责是协调快速路径与慢速路径:先进行必要的上下文准备,然后尝试快速分配(get_page_from_freelist),失败后交给慢速路径(__alloc_pages_slowpath)做最后的努力。

核心流程

struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order, int preferred_nid, nodemask_t *nodemask) { struct page *page; unsigned int alloc_flags = ALLOC_WMARK_LOW; gfp_t alloc_gfp; struct alloc_context ac = { }; /* 1. 合法性检查:阶数超出 MAX_ORDER 直接失败 */ if (WARN_ON_ONCE_GFP(order > MAX_ORDER, gfp)) return NULL; /* 2. 应用 early boot 阶段的 GFP 限制 */ gfp &= gfp_allowed_mask; /* 3. 应用当前任务的上下文约束 */ gfp = current_gfp_context(gfp); /* 4. 准备分配上下文:确定 zone、迁移类型、初始 alloc_flags */ alloc_gfp = gfp; if (!prepare_alloc_pages(gfp, order, preferred_nid, nodemask, &ac, &alloc_gfp, &alloc_flags)) return NULL; /* 5. 快速路径:首次尝试分配 */ page = get_page_from_freelist(alloc_gfp, order, alloc_flags, &ac); if (likely(page)) goto out; /* 6. 慢速路径:回收、规整、OOM */ alloc_gfp = gfp; page = __alloc_pages_slowpath(alloc_gfp, order, &ac); out: return page; }

逐步解析

1. 阶数合法性检查

if (WARN_ON_ONCE_GFP(order > MAX_ORDER, gfp)) return NULL;

MAX_ORDER是伙伴系统支持的最大阶数(通常为 10,即 4MB)。超出此范围直接返回失败,避免后续代码做无意义的尝试。

2.gfp_allowed_mask过滤

gfp &= gfp_allowed_mask;

这是启动早期的保护机制。在系统初始化完成前,某些 GFP 标志(如__GFP_DIRECT_RECLAIM、__GFP_KSWAPD_RECLAIM)还不允许使用,因为回收子系统尚未就绪。gfp_allowed_mask在启动过程中逐步放宽,最终变为完整的GFP_KERNEL等。

3.current_gfp_context()应用任务上下文约束

gfp = current_gfp_context(gfp);

这是运行时的关键步骤。它会根据当前任务的内存分配上下文标志(PF_MEMALLOC_NOFS、PF_MEMALLOC_NOIO等),动态修改gfp:

  • 如果任务处于memalloc_nofs_save()保护下,__GFP_FS被清除;

  • 如果处于memalloc_noio_save()保护下,__GFP_IO也被清除。

这个调用必须在prepare_alloc_pages()之前完成,因为prepare_alloc_pages()内部会根据最终的gfp计算迁移类型、允许的 zone 类型和初始alloc_flags。

4.prepare_alloc_pages()构造分配上下文

这是分配路径的“准备中枢”,它完成:

  • 确定ac->migratetype(根据__GFP_MOVABLE等);

  • 应用 cpuset/mempolicy 约束,设置ac->nodemask和ac->highest_zoneidx;

  • 初始化ac->zonelist和ac->preferred_zoneref;

  • 调用gfp_to_alloc_flags()计算初始ALLOC_*标志;

  • 处理__GFP_NOFRAGMENT。

5. 快速路径:get_page_from_freelist()

这是分配的首选路径,在保守水位(ALLOC_WMARK_LOW)下遍历 zonelist,尝试从 PCP 或伙伴系统分配。它力求快速成功,避免不必要的 kswapd 唤醒。

6. 慢速路径:__alloc_pages_slowpath()

如果快速路径失败,慢速路径接管。它通过逐步放宽限制(降低水位、动用保留区、直接回收、内存规整、OOM)来尝试满足分配,或在确实无望时失败。

与相关函数的关系

函数角色
__alloc_frozen_pages_noprof()主入口,协调快慢路径
prepare_alloc_pages()构造alloc_context
get_page_from_freelist()快速路径执行者
__alloc_pages_slowpath()慢速路径执行者

总结

__alloc_frozen_pages_noprof()是物理页分配的总调度器:它先做合法性检查,应用gfp_allowed_mask(early boot 限制)和current_gfp_context()(任务上下文约束),然后通过prepare_alloc_pages()构造完整的分配上下文,接着尝试快速路径分配;失败则交给慢速路径做回收、规整和 OOM 处理。它是从上层alloc_pages()宏到伙伴系统底层取页逻辑之间的核心桥梁。

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

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

立即咨询