add_to_free_list()是__add_to_free_list()的带统计更新的封装版本,用于将一个空闲页块加入伙伴系统的空闲链表,并同步更新free_area的nr_free计数。
核心作用与与__add_to_free_list()的区别
| 函数 | 操作 | nr_free计数 |
|---|---|---|
__add_to_free_list() | 仅list_add/list_add_tail | 调用方负责 |
add_to_free_list() | __add_to_free_list()+ 计数更新 | 自动递增 |
双下划线前缀__表示“纯物理操作”,而add_to_free_list()是完整封装——加入链表的同时,把zone->free_area[order].nr_free加 1。
典型实现
static inline void add_to_free_list(struct page *page, struct zone *zone, unsigned int order, int migratetype, bool tail) { __add_to_free_list(page, zone, order, migratetype, tail); zone->free_area[order].nr_free++; }参数解析
| 参数 | 含义 |
|---|---|
page | 页块首页 |
zone | 目标 zone |
order | 阶数,决定free_area[order] |
migratetype | 迁移类型,决定free_list[migratetype] |
tail | true尾插(延迟复用),false头插(优先复用) |
在释放路径中的位置
__free_one_page()在合并完成后、未被 compaction 捕获时,会调用它把页块加入空闲链表:
if (capc && !compaction_capture(capc, page, order, migratetype)) { set_buddy_order(page, order); add_to_free_list(page, zone, order, migratetype, to_tail); }迁移类型变更时的nr_free处理
一个容易忽略的细节:当页块从一种迁移类型移到另一种时(如 fallback 偷页、CMA 借用),不能简单地用add_to_free_list(),因为那样会重复增加总数。
move_to_free_list()的操作是“先删后加”:__del_page_from_free_list()会减少旧链表的nr_free,再用__add_to_free_list()(而非add_to_free_list())加回新链表。如果这里误用add_to_free_list(),就会导致该页块的计数被错误地增加。
总结
add_to_free_list()是伙伴系统的空闲链表加入封装:它在__add_to_free_list()完成链表插入的基础上,额外递增zone->free_area[order].nr_free。它被__free_one_page()在释放路径上调用,是“页块进入伙伴系统”时维护空闲计数的标准入口。与它对称的是del_page_from_free_list()(移出 + 递减计数),两者共同保证nr_free的准确性。