☰
page_alloc set_pageblock_migratetype
2026/10/7 15:15:53 网站建设 项目流程

设置某个 pageblock 的迁移类型。它是反碎片机制的核心写入接口,与get_pfnblock_migratetype()读配对。


一、函数签名

static void set_pageblock_migratetype(struct page *page, enum migratetype migratetype)

参数

参数类型含义
pagestruct page *目标 pageblock 内的某一页(用于定位 zone/位图)
migratetypeenum migratetype要设置的迁移类型

返回值

  • void:无返回值。

static

  • 文件内私有,不导出。仅在page_alloc.c内部使用。

  • 对外可能通过其他封装(如set_pageblock_migratetype_nolock())或宏提供。

注释

/** * set_pageblock_migratetype - Set the migratetype of a pageblock * @page: The page within the block of interest * @migratetype: migratetype to set */
  • "Set the migratetype of a pageblock":设置一个 pageblock 的迁移类型。

  • 注意:不是 page,而是 pageblock——整个2^pageblock_order页的属性。


二、与读函数对比

函数方向参数返回
get_pfnblock_migratetype(page, pfn)读page, pfnenum migratetype
set_pageblock_migratetype(page, migratetype)写page, migratetypevoid

参数差异:写函数为什么没有pfn?

  • 读函数get_pfnblock_migratetype(page, pfn)同时给page和pfn,是为了省去page_to_pfn()(性能优化)。

  • 写函数set_pageblock_migratetype(page, migratetype)只给page,内部自己算 pfn:

    unsigned long pfn = page_to_pfn(page);
  • 原因:写操作本身就是慢路径(分配/释放/规整时调用),page_to_pfn()的开销可忽略,API 简洁更重要。

  • 若调用方已有 pfn,可能内部有另一个接口(如set_pfnblock_migratetype(page, migratetype, pfn))来复用。


三、典型实现

static void set_pageblock_migratetype(struct page *page, enum migratetype migratetype) { if (unlikely(page_group_by_mobility_disabled)) return; set_pfnblock_flags_mask(page, page_to_pfn(page), (unsigned long)migratetype, PB_migrate_mask); }

或更直接地编码到字段位置:

static void set_pageblock_migratetype(struct page *page, enum migratetype migratetype) { unsigned long pfn = page_to_pfn(page); if (unlikely(page_group_by_mobility_disabled)) return; /* * 把 migratetype 编码到 PB_migrate 字段: * (migratetype << PB_migrate) & PB_migrate_mask */ set_pfnblock_flags_mask(page, pfn, (unsigned long)migratetype << PB_migrate, PB_migrate_mask); }

逐步说明

1. 禁用分组的快速返回

if (unlikely(page_group_by_mobility_disabled)) return;
  • page_group_by_mobility_disabled:

    • 当系统内存太小、分组收益不大时,内核禁用按迁移性分组。

  • 禁用后,pageblock 的迁移类型不再有意义(所有页混在一起管理),设置它没有用处。

  • 直接return,跳过写入,省开销。

  • unlikely():因为运行期绝大多数系统不会禁用分组(只有小内存系统才禁用),所以偏向"不返回"。

2. 把迁移类型编码到字段

(unsigned long)migratetype << PB_migrate
  • PB_migrate:迁移类型字段的起始位偏移。

  • 把migratetype值左移到该字段位置。

  • 例如PB_migrate = 0、migratetype = MIGRATE_MOVABLE (1)→ 编码为1。

3. 用 mask 限定只改迁移类型字段

PB_migrate_mask
  • 覆盖PB_migrate ~ PB_migrate_end的掩码。

  • 保证只改迁移类型字段,其他独立位(如PB_migrate_skip)保持不变。

4. 调用set_pfnblock_flags_mask()

set_pfnblock_flags_mask(page, pfn, 编码值, PB_migrate_mask);
  • 这是__set_pfnblock_flags_mask()的对外包装(带VM_BUG_ON等检查)。

  • 底层做读-改-写:(旧值 & ~mask) | (新值 & mask),只更新迁移类型字段。

完整语义

set_pageblock_migratetype(page, MIGRATE_MOVABLE) ↓ if (分组禁用) return; // 小内存优化 ↓ pfn = page_to_pfn(page) ↓ set_pfnblock_flags_mask(page, pfn, MIGRATE_MOVABLE << PB_migrate, // 新值 PB_migrate_mask) // 只改这几位 ↓ 底层读-改-写,其他位不动

四、并发与锁

这个函数本身不加锁,正确性依赖调用方:

  • 常见调用点在持zone->lock或pgdat->node_size_lock等锁的情况下;

  • 或者操作的是当前 CPU 独有的页块(不冲突);

  • 多 CPU 并发修改同一 pageblock的迁移类型需要外部同步。

这也是它为什么是static且注释简洁——它是内部工具,同步责任在调用方。


五、典型用途

1. 伙伴系统初始化

  • 启动时把各 pageblock 的迁移类型设为初始值(通常是MIGRATE_MOVABLE或MIGRATE_UNMOVABLE)。

2. 分配时改变迁移类型

  • 当从某迁移类型 fallback 到另一类型取页时,可能需要更新 pageblock 的迁移类型,反映实际使用情况。

  • 例如__rmqueue_fallback()中"偷"了别的类型的页块后,可能把该 pageblock 标记为新类型,避免后续继续误用。

3. 内存规整(compaction)

  • 规整前把页块标记为MIGRATE_ISOLATE(隔离),规整后恢复。

  • 通过set_pageblock_migratetype(page, MIGRATE_ISOLATE)实现。

4. CMA 区域

  • CMA 预留的内存页块迁移类型设为MIGRATE_CMA,表示"这块给 CMA 用"。

  • 分配时 CMA 类型优先满足 CMA 请求,非 CMA 请求可临时借用。

5. 内存热插拔

  • 下线内存前,把页块迁移类型设为MIGRATE_ISOLATE,隔离后迁移走页,再下线。

  • 上线时恢复迁移类型。

6.ZONE_MOVABLE

  • MOVABLE zone 的页块迁移类型通常是MIGRATE_MOVABLE。


六、与前面内容的呼应

前面出现过的这里的关联
migratetype_names[]enum migratetype的名字表
get_pfnblock_migratetype()读配对
PB_migrate/PB_migrate_end/PB_migrate_mask编码与掩码
__set_pfnblock_flags_mask()/set_pfnblock_flags_mask()底层写入实现
page_group_by_mobility_disabled分组禁用时直接 return
MIGRATE_ISOLATE/MIGRATE_CMA特殊迁移类型,用此函数设置
PB_migrate_skip(独立位)不受本函数影响,因为 mask 只覆盖迁移类型字段

调用链:

set_pageblock_migratetype(page, migratetype) ├── if (page_group_by_mobility_disabled) return; // 分组禁用 ├── pfn = page_to_pfn(page) └── set_pfnblock_flags_mask(page, pfn, migratetype << PB_migrate, PB_migrate_mask) └── __set_pfnblock_flags_mask(...) // 读-改-写 ├── get_pageblock_bitmap() ├── pfn_to_bitidx() └── 更新位

七、小结表

项说明
函数名set_pageblock_migratetype
作用设置某 pageblock 的迁移类型
参数page用于定位 zone/位图,内部转 pfn
参数migratetype要设置的迁移类型
返回值void
可见性static,文件内私有
关键优化分组禁用(page_group_by_mobility_disabled)时直接返回
实现依赖set_pfnblock_flags_mask(page, pfn, migratetype << PB_migrate, PB_migrate_mask)
并发不加锁,正确性依赖调用方同步

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

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

立即咨询