欢迎光临
我们一直在努力

page_alloc set_pageblock_migratetype

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


一、函数签名

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

参数

参数类型含义
page struct page * 目标 pageblock 内的某一页(用于定位 zone/位图)
migratetype enum 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, pfn enum migratetype
set_pageblock_migratetype(page, migratetype) 写 page, migratetype void

参数差异:写函数为什么没有 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)
并发 不加锁,正确性依赖调用方同步
赞(0)
未经允许不得转载:171主机测评 » page_alloc set_pageblock_migratetype
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址