内存管理-33-2-GFP分配掩码约束
基于 Linux-6.1.114
一、全局约束
全局约束通过全局变量 gfp_allowed_mask 实现,它是一个全局 GFP 位掩码过滤器,所有页面分配请求的 gfp_mask 在进入分配器前都会与它做 AND 运算,将系统当前不允许使用的 GFP 标志位强制清除。
1. 赋值位置
(1) 初始定义
//mm/internal.h #define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS)) //mm/page_alloc.c gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK;
初始状态: 不允许回收(同步/异步),不允许 IO、不允许 FS。作用域是内核启动期间。
(2) 启动完成
/* 根据配置是 1<<28 - 1 或 1<<29 -1,包含全部 ___GFP_X 掩码 */ #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) start_kernel //init/main.c rest_init //init/main.c kernel_thread(kernel_init, NULL, CLONE_FS) //创建init线程 kernel_init //main.c kernel_init_freeable //init/main.c gfp_allowed_mask = __GFP_BITS_MASK;
内核启动完成后解除限制,这个解除限制的时间还是挺晚的,init 进程运行后才解除。
(3) Suspend/Resume
hibernation_snapshot //hibernate.c hibernation_restore //hibernate.c enter_state //suspend.c pm_restrict_gfp_mask //page_alloc.c saved_gfp_mask = gfp_allowed_mask; //保存当前值 gfp_allowed_mask &= ~(__GFP_IO | __GFP_FS); //清除 IO 和 FS 位 suspend_devices_and_enter //执行休眠,resume后从这里退出 pm_restore_gfp_mask pm_restore_gfp_mask gfp_allowed_mask = saved_gfp_mask; saved_gfp_mask = 0;
在系统休眠/挂起时限制 IO, 在 suspend/hibernate 路径中调用:设备即将挂起,存储设备将不可用,禁止任何分配请求触发磁盘 IO(writeback、swap out 等)。
2. 使用位置
(1) 主分配入口
__alloc_pages //page_alloc.c gfp &= gfp_allowed_mask; //第一步就做全局掩码过滤 gfp = current_gfp_context(gfp); //然后再处理任务上下文约束
这是所有页面分配的必经之路,确保任何分配请求都不会使用当前系统禁止的 GFP 标志。
(2) 批量分配
__alloc_pages_bulk //page_alloc.c gfp &= gfp_allowed_mask;
这是批量分配入口函数,批量分配路径同样做过滤。只有使能 CONFIG_NUMA 才有调用路径。
(3) 存储挂起判断
bool pm_suspended_storage //page_alloc.c { if ((gfp_allowed_mask & (__GFP_IO | __GFP_FS)) == (__GFP_IO | __GFP_FS)) return false; //IO 和 FS 都允许 --> 存储正常 return true; //IO 或 FS 被禁止 --> 存储已挂起 } folio_free_swap //mm/swapfile.c if (pm_suspended_storage()) //返回false表示先不释放swap空间 return false; __alloc_pages_slowpath __alloc_pages_may_oom if (pm_suspended_storage()) goto out;
folio_free_swap: 本质是"防御性设计":在存储不可用期间,保留 swap 备份作为数据的"保险",确保即使出现意外的内存回收,数据也不会丢失。等存储Resume后再安全释放。
__alloc_pages_may_oom() 调用:若存储已挂起则跳过 OOM killer, 因为 OOM 杀的进程可能因 IO 阻塞无法退出。
3. 小结
(1) 三个生命阶段
-------------------------------------------------------------------------------------------------------------- 阶段 gfp_allowed_mask 的值 含义 -------------------------------------------------------------------------------------------------------------- 早期启动 GFP_BOOT_MASK(受限子集) 中断未启用、设备未初始化,不允许 IO/FS/同步异步回收等操作 系统正常运行 __GFP_BITS_MASK(所有位全开) 不做任何额外限制,所有 GFP 标志都允许使用 休眠/挂起期间 ~(__GFP_IO | __GFP_FS)(去除 IO/FS) 设备已挂起,禁止任何 IO 和文件系统操作 --------------------------------------------------------------------------------------------------------------
posted on 2026-08-07 17:43 Hello-World3 阅读(4) 评论(0) 收藏 举报
浙公网安备 33010602011771号