prep_compound_page是复合页(Compound Page)的构造函数,用于把一个高阶物理连续页块初始化为一个在逻辑上可视为“单一更大页”的复合页。它是在分配高阶页且指定了__GFP_COMP标志时,由prep_new_page调用的。
函数签名
void prep_compound_page(struct page *page, unsigned int order)
参数
page: 指向复合页的首页(head page)。参数
order: 分配阶数,页块包含2^order个物理连续页。
核心作用:建立 Head/Tail 关系
物理内存本身就是连续的,prep_compound_page的作用是在struct page元数据层面建立一种层级关系,让内核能把这一组页当成一个整体来管理。
它主要完成两件事:
标记首页:将第一个
struct page标记为“头”(Head),设置PG_head标志。设置尾页:对后续的每一个“尾页”(Tail page),设置其
compound_head指针指向头页,并设置PG_tail标志。同时在第一个尾页中记录整个复合页的order。
为什么需要它?
这是内核内存管理的关键抽象,主要用于:
大页支持:透明大页(THP)和 hugetlbfs 都依赖复合页。CPU 的页表项可以指向一个“大页”,从而减少 TLB miss,提升性能。
统一管理:通过将一组页标记为复合页,上层代码(如文件系统)可以用
folio(现代内核中代表复合页的结构)来统一操作,而无需关心底层的多个struct page。典型的路径如folio_alloc会加上__GFP_COMP,进而触发prep_compound_page。正确的释放:当复合页被释放时,内核能通过
compound_order知道它实际占用了多少个页,从而正确地归还给伙伴系统。
在分配路径中的位置
它位于页分配的核心路径上,调用链大致如下:
__alloc_pages -> get_page_from_freelist -> prep_new_page -> prep_compound_page
prep_compound_page本身只负责“元数据标记”,并不涉及物理内存的清零或映射。它通常在页面内容被使用之前、在post_alloc_hook之前或之后执行,具体顺序取决于内核版本对初始化流程的调整。