首页 / 资讯中心 / 文章详情

page_alloc set_buddy_order

page_alloc set_buddy_order ★ FEATURED ARTICLE
设置空闲伙伴页块的阶数。它是在页块被释放进伙伴系统或从伙伴系统取出时用来在struct page的private字段里记录这个空闲块有多大的辅助函数。一、函数签名static inline void set_buddy_order(struct page *page, unsigned int order)参数参数类型含义pagestruct page *页块的首页head pageorderunsigned int该空闲页块的阶数返回值void。static inline文件内私有 强制/建议内联。在伙伴系统的分配/释放/合并热路径上频繁调用必须零开销。二、背景空闲页块的阶数存在哪struct page的private字段struct page有一个联合体字段其中一个成员是struct { ... unsigned long private; ... };private是一个unsigned long不同场景下复用在buffer_head场景指向 buffer_head在slab场景指向 slab 相关结构在伙伴系统空闲页场景存 order。关键约定当一个页块空闲、挂在伙伴系统free_area[order]链表上时它的首页head page的private字段存order这样从链表取出页块时能立刻知道它有多大。当页块被分配出去后private可能被其他用途复用如 buffer_head所以 order 信息不再有效。set_buddy_order()就是写这个字段static inline void set_buddy_order(struct page *page, unsigned int order) { set_page_private(page, order); __SetPageBuddy(page); }逐步说明1. 记录 orderset_page_private(page, order);set_page_private(page, value)是内核提供的封装把page-private设为value通常还带一些调试/类型检查如VM_BUG_ON_PAGE。这里把order写进private。2. 标记为 Buddy 页__SetPageBuddy(page);设置PG_buddy标志位__SetPageBuddy是底层、不加额外检查的版本。表示这个页当前是伙伴系统里的空闲页。这是状态标记用于free_pages_prepare()时检测双重释放已 Buddy 又被释放bad_page()检测非法状态区分空闲伙伴页与已分配页。对应的读取/清除读 orderstatic inline unsigned int buddy_order(struct page *page) { VM_BUG_ON_PAGE(!PageBuddy(page), page); return page_private(page); }清除 Buddy 状态页被分配出去时__ClearPageBuddy(page); set_page_private(page, 0);或封装成rmv_page_order()之类。三、在伙伴系统中的位置释放页块时__free_one_page()static inline void __free_one_page(struct page *page, unsigned long pfn, struct zone *zone, unsigned int order, int migratetype, fpi_t fpi_flags) { ... /* 合并伙伴最终确定 order */ while (order max_order - 1) { buddy_pfn __find_buddy_pfn(pfn, order); buddy page (buddy_pfn - pfn); if (!page_is_buddy(page, buddy, order)) // 检查 buddy 是否空闲且同阶 break; /* 合并 */ list_del(buddy-lru); ... order; } ... /* 把合并后的页块加入 free_area[order] */ set_buddy_order(page, order); list_add(page-lru, zone-free_area[order].free_list[migratetype]); ... }合并完成后用set_buddy_order(page, order)记录最终阶数并标记 Buddy。然后挂到对应free_area[order]链表。分配页块时__rmqueue_smallest()/expand()从free_area[order]取出页块后rmv_page_order(page)清除 Buddy 状态和 private若需要分裂expand()把大块拆成小块每块重新set_buddy_order()后放回对应链表。page_is_buddy()检查static inline int page_is_buddy(struct page *page, struct page *buddy, unsigned int order) { if (!PageBuddy(buddy)) return 0; if (buddy_order(buddy) ! order) return 0; ... return 1; }判断伙伴页是否空闲且同阶才能合并。
阅读完成 · 觉得有帮助?
咨询建站