☰
page_alloc pindex_to_order
2026/10/7 12:10:03 网站建设 项目流程

是order_to_pindex()的逆函数,用于在PCP(Per-CPU Pages)批量管理中,把"链表索引 pindex"反解回"阶数 order"。


一、函数签名

static inline int pindex_to_order(unsigned int pindex)

参数

参数类型含义
pindexunsigned intPCP 中空闲链表的索引(pindex)

返回值

  • int:对应的阶数order。

static inline

  • 文件内私有且强制内联(或建议内联),因为这属于热路径上的简单计算。


二、背景:PCP 的pindex与order

1. PCP 缓存的结构

每个 CPU、每个 zone 有一个per_cpu_pages(简称 PCP),里面维护若干空闲页链表:

struct per_cpu_pages { spinlock_t lock; int count; /* 总页数 */ int high; /* 高水位 */ int batch; /* 批量补充/归还大小 */ struct list_head lists[NR_PCP_LISTS]; /* 多个链表 */ };
  • lists[]的索引就是pindex。

  • 每个链表对应某种迁移类型 + 某个阶数的组合。

2. 为什么需要pindex而不是直接用(migratetype, order)?

  • PCP 需要为不同迁移类型、不同阶数分别维护链表。

  • 但用二维数组lists[MIGRATE_TYPES][MAX_ORDER]会:

    • 浪费空间(很多组合实际不用);

    • 索引计算复杂。

  • 内核改用一维数组 + 编码:

    • 把(migratetype, order)编码成一个整数pindex;

    • 用order_to_pindex()编码,pindex_to_order()解码。

3. 编码方式

static inline unsigned int order_to_pindex(int migratetype, int order) { ... return (order << MIGRATE_PCPTYPES_LOG2) | migratetype; /* 或类似:低几位存 migratetype,高位存 order */ }
  • 低位存迁移类型(migratetype),因为迁移类型数量较少(通常 < 8)。

  • 高位存阶数order。

于是pindex_to_order()就是取出高位:

static inline int pindex_to_order(unsigned int pindex) { return pindex >> MIGRATE_PCPTYPES_LOG2; /* 或 pindex >> ilog2(MIGRATE_PCPTYPES) */ }

4. 另一种编码:order 直接映射

不同内核版本实现不同。有的版本把 PCP 链表按 order 分组,迁移类型在同一 order 内再分:

/* 每个 order 占 NR_PCP_LISTS_PER_ORDER 个 pindex */ #define NR_PCP_LISTS_PER_ORDER ... static inline int pindex_to_order(unsigned int pindex) { return pindex / NR_PCP_LISTS_PER_ORDER; }

或用移位:

return pindex >> NR_PCP_LISTS_PER_ORDER_SHIFT;

关键:pindex_to_order()必须与order_to_pindex()严格互逆。


三、与order_to_pindex()的对称关系

函数方向输入输出
order_to_pindex(migratetype, order)编码迁移类型 + 阶数pindex
pindex_to_order(pindex)解码pindex阶数order
  • 编码:pindex = f(migratetype, order)

  • 解码阶数:order = pindex_to_order(pindex)

  • 通常还有一个pindex_to_migratetype(pindex)(或类似)解码迁移类型。

为什么只需要pindex_to_order()而不常需要解码迁移类型?

  • 在很多路径中,阶数是关键信息(决定页块大小、伙伴合并等);

  • 迁移类型有时不需要从 pindex 反解(调用方本来就知道,或通过其他方式获取);

  • 所以pindex_to_order()更常用,被单独定义。


四、典型使用场景

1.free_pcppages_bulk()—— 批量归还 PCP 页到伙伴系统

static void free_pcppages_bulk(struct zone *zone, int count, struct per_cpu_pages *pcp, ...) { ... for (pindex = 0; pindex < NR_PCP_LISTS; pindex++) { struct list_head *list = &pcp->lists[pindex]; ... order = pindex_to_order(pindex); /* 用 order 调用 __free_one_page() 归还 */ ... } }
  • 遍历 PCP 各链表,从pindex反解order,才能正确释放对应大小的页块。

2.rmqueue_pcplist()/rmqueue_bulk()—— 从 PCP 分配

  • 分配时需要知道从哪个链表取、页块多大。

  • 可能用order_to_pindex()定位链表,用pindex_to_order()确认阶数。

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

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

立即咨询