ARTICLE DETAIL

资讯详情

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

page_alloc get_pfnblock_migratetype

page_alloc get_pfnblock_migratetype 读取某个 pageblock 的迁移类型migratetype。它是反碎片机制的核心读取接口。一、函数签名__always_inline enum migratetype get_pfnblock_migratetype(const struct page *page, unsigned long pfn)参数参数类型含义pageconst struct page *目标 pageblock 内的某一页用于定位位图pfnunsigned long目标页帧号返回值enum migratetype该 pageblock 的迁移类型MIGRATE_UNMOVABLE、MIGRATE_MOVABLE、MIGRATE_RECLAIMABLE、MIGRATE_CMA等。__always_inline强制内联。这个函数在分配/释放/规整的热路径上频繁调用内联后零调用开销。与前面的get_pfnblock_bit()普通函数不同这里因为是简单读取移位适合强制内联。注释的关键点* Use get_pfnblock_migratetype() if caller already has both page and pfn * to save a call to page_to_pfn().提示如果调用方已经有page和pfn就用这个双参数版本省去page_to_pfn()的开销。还存在一个单参数版本通常叫get_pageblock_migratetype(page)内部会调用page_to_pfn(page)把 page 转成 pfn。所以这是性能优化接口已知 pfn 时避免重复转换。二、典型实现补充__always_inline enum migratetype get_pfnblock_migratetype(const struct page *page, unsigned long pfn) { unsigned long flags; flags __get_pfnblock_flags_mask(page, pfn, PB_migrate_mask); return (enum migratetype)((flags PB_migrate) ((1 PB_migratetype_bits) - 1)); }逐步说明1. 读取迁移类型字段flags __get_pfnblock_flags_mask(page, pfn, PB_migrate_mask);PB_migrate_mask迁移类型字段的掩码覆盖PB_migrate到PB_migrate_end的位。典型定义#define PB_migrate_mask (((1 PB_migratetype_bits) - 1) PB_migrate)即从PB_migrate开始的PB_migratetype_bits位全 1。__get_pfnblock_flags_mask()前面讲的读取实现返回按 mask 过滤后的位。结果flags是原始位模式可能还带偏移取决于__get_pfnblock_flags_mask是否右移对齐。2. 提取迁移类型值return (enum migratetype)((flags PB_migrate) ((1 PB_migratetype_bits) - 1));flags PB_migrate把字段右移到最低位。 ((1 PB_migratetype_bits) - 1)只保留PB_migratetype_bits位得到纯数值。强转为enum migratetype返回。注意具体移位方式取决于__get_pfnblock_flags_mask()的实现约定如果它返回的是已右移对齐的值(flags mask) __ffs(mask)那么这里只需 ((1 PB_migratetype_bits) - 1)不用再 PB_migrate。如果它返回未移位的原始位则这里需要 PB_migrate。不同内核版本实现略有差异但语义一致取出迁移类型字段的数值。三、单参数版本对比典型的单参数版本static inline enum migratetype get_pageblock_migratetype(const struct page *page) { return get_pfnblock_migratetype(page, page_to_pfn(page)); }调用page_to_pfn(page)把页转成 pfn。page_to_pfn()本身是(page - vmemmap) ...或类似计算在CONFIG_SPARSEMEM_VMEMMAP下是简单减法但仍是一步运算。如果调用方已经知道 pfn直接用双参数版本可以省掉这一步。这就是注释所说的 save a call to page_to_pfn()。使用建议场景用哪个只有pageget_pageblock_migratetype(page)已有page和pfnget_pfnblock_migratetype(page, pfn)更快在遍历 pfn 的循环里双参数版本避免反复转换四、迁移类型回顾enum migratetype的值与前面的migratetype_names[]对应值名字含义MIGRATE_UNMOVABLEUnmovable不可移动内核结构、页表MIGRATE_MOVABLEMovable可移动用户态页MIGRATE_RECLAIMABLEReclaimable可回收slab 缓存MIGRATE_HIGHATOMICHighAtomic高优先级原子分配保留MIGRATE_CMACMA连续内存分配器区域MIGRATE_ISOLATEIsolate被隔离热插拔/规整这些值编码在 pageblock 的PB_migrate字段里本函数就是读出这个编码。五、典型用途1. 伙伴系统分配__rmqueue_smallest()根据迁移类型从对应空闲链表取页。取之前/之后可能需要读 pageblock 的迁移类型。2. 释放页时free_one_page()/__free_one_page()需要知道页块的迁移类型决定放回哪个链表。尤其合并merge伙伴时迁移类型影响合并策略。3. 反碎片 fallback__rmqueue_fallback()当目标迁移类型没有空闲块时找其他类型的页块偷。需要读取各 pageblock 的迁移类型来判断/更新。4. 内存规整compaction判断哪些 pageblock 可移动决定是否迁移。5. 内存热插拔设置/读取 pageblock 迁移类型为MIGRATE_ISOLATE隔离待下线内存。6./proc/pagetypeinfo展示各迁移类型的空闲页统计底层会读这些信息。六、与前面内容的呼应前面出现过的这里的关联migratetype_names[]enum migratetype的名字表PB_migrate/PB_migrate_end/PB_migratetype_bits迁移类型字段的位置和位数PB_migrate_mask本函数传给__get_pfnblock_flags_mask()的 mask__get_pfnblock_flags_mask()本函数的底层读取is_standalone_pb_bit()本函数读的是非独立的迁移类型字段正好与之相对get_pfnblock_bit()读独立位本函数读迁移类型字段两者互补page_group_by_mobility_disabled控制是否按迁移类型分组影响本函数结果的使用调用链get_pfnblock_migratetype(page, pfn) // 双参数热路径 ├── __get_pfnblock_flags_mask(page, pfn, PB_migrate_mask) │ ├── get_pageblock_bitmap() │ └── pfn_to_bitidx() └── 移位 掩码 → enum migratetype get_pageblock_migratetype(page) // 单参数便捷 └── get_pfnblock_migratetype(page, page_to_pfn(page))七、小结表项说明函数名get_pfnblock_migratetype作用读取某 pageblock 的迁移类型参数page用于定位位图参数pfn目标页帧号返回值enum migratetype关键优化__always_inline已知 pfn 时省去page_to_pfn()实现依赖__get_pfnblock_flags_mask(page, pfn, PB_migrate_mask) 移位/掩码单参数版get_pageblock_migratetype(page) 本函数 page_to_pfn()典型用途伙伴系统分配/释放、反碎片 fallback、规整、热插拔、/proc/pagetypeinfo一句话总结get_pfnblock_migratetype(page, pfn)是读取 pageblock迁移类型的强制内联接口它通过__get_pfnblock_flags_mask(page, pfn, PB_migrate_mask)取出PB_migrate字段并按PB_migratetype_bits解码成enum migratetype因为已知 pfn 可省去page_to_pfn()它是伙伴系统、反碎片、规整、内存热插拔等热路径上的关键读取函数与读取独立位的get_pfnblock_bit()互补。
返回列表