ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

page_alloc pindex_to_order

page_alloc pindex_to_order 是order_to_pindex()的逆函数用于在PCPPer-CPU Pages批量管理中把链表索引 pindex反解回阶数 order。一、函数签名static inline int pindex_to_order(unsigned int pindex)参数参数类型含义pindexunsigned intPCP 中空闲链表的索引pindex返回值int对应的阶数order。static inline文件内私有且强制内联或建议内联因为这属于热路径上的简单计算。二、背景PCP 的pindex与order1. 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)编码迁移类型 阶数pindexpindex_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()确认阶数。
返回列表