v3 2026-10-28

swap 设备优先级队列 · v3

将 swap 设备选择与设备内簇分配解耦,用按优先级排列的设备环数组替代全局 per-CPU 缓存与共享轮转,并保留 swapon 和 memcg 记账。

原始补丁链接

子 Patch(18)

1/18
mm/swap: remove unused parameter for reading swap header
读取 swap header 的函数移除未使用参数,只调整签名与调用点,无功能变化。
2/18
mm/swap: slightly cleanup the code for hibernation error handling
重构 pin_hibernation_swap_type 错误路径为 goto out,避免重复 spin_unlock;unpin 把 si 空检查内联,find_first_swap 去掉循环内提前返回,仅清理流程。
3/18
mm/swap: cleanup and document swap device availability flag usage
新增 swap_device_enable/disable 明确 SWP_WRITEOK 发布/禁用边界,继续用 swap_avail_lock 串行可用性;保留 swap_lock 覆盖映射查找、休眠检查和禁用转换,放锁后再 drain cluster allocator,并补文档说明标志生命周期与锁规则。
4/18
mm/swap: introduce swap device iteration helper
为遍历 swap_info 找可用设备的用户引入通用迭代 helper,并调整 __swap_type_to_info 允许访问已 swapoff 设备,把合法性检查移到 __swap_entry_to_info;为后续去掉锁约定铺路。
5/18
mm/swap: change the swapon lock into a percpu rwsem
把 swap_lock 自旋锁改为 percpu rwsem:swap 元数据读取是热路径,swapon/swapoff 稀少,读侧可并发减少争用;同时更新 swap_info_struct 中锁名与注释。
6/18
mm/swap: serialize swap publication before removing swapon mutex
把 swap_file 发布、设备引用复活和可写转换收进同一 swapon_rwsem 写段,拆出写侧 enable helper;去掉 swapon_mutex,改用 topology reader 遍历 /proc/swaps 并保留 SWP_USED 过滤,避免 proc 看到半发布状态,保证无锁引用者先见完整元数据。
7/18
mm/swap: consolidate swap inuse accounting helpers
将 swap_usage_add/sub 内联进唯一调用者并重命名,明确其只维护每设备 inuse 页计数,无功能变化。
8/18
mm/swap: change back to use each swap device's percpu cluster
回退 1b7e90020eb7,恢复每设备 percpu cluster。全局 percpu cluster 让非默认设备策略和 swap tiering 无法高效工作,并可造成优先级反转:memcg2 用设备 B 填充全局缓存后,memcg1 快路径选 B 而非更高优先级 A,还使快慢路径与 discard 复杂化。
9/18
mm/swap: avoid direct reclaim when populating swap cluster metadata
swap cluster 元数据填充在分配路径内,原 GFP_KERNEL fallback 会放锁并直收,可能经 direct reclaim 重入 swap 分配;改为清除 __GFP_DIRECT_RECLAIM,保留 __GFP_HIGH/__GFP_NOMEMALLOC,可唤醒 kswapd 但不直收,代价是内存压力下更早失败并保留回滚。
10/18
mm/swap: add priority queue for swap device allocation
用按优先级从高到低的同优先级设备环替代 swap_avail_head 轮转,把设备选择与设备内 cluster 分配分开;成员/大小受 swapon_rwsem 保护,满/禁用设备用带 tag 指针屏蔽,tag 写用 swap_queue_update_lock 和 READ/WRITE_ONCE,并为每 CPU 维护环起始偏移与配额、任务游标,大 folio 先重试同优先级设备再拆分。
11/18
mm/swap: remove available list
priority queue 接管设备选择后,删除未用的 swap_avail_head/swap_avail_lock;throttle 路径改在 swapon_rwsem 下遍历 swap_active_head,检查 SWP_WRITEOK 与 off-list 状态,保持优先级且不选满设备。
12/18
mm/swap: bound synchronous discard during allocation
按设备 cluster 分配时,若空闲 cluster 链表耗尽则在所选设备上同步处理 discard,而非全局 fallback 扫描;抽出 swap_discard_one_cluster,在 si->lock 下摘一个 cluster,I/O 期间保留 CLUSTER_FLAG_DISCARD,完成后放回。每次设备分配尝试最多同步处理一个 cluster,限制 discard 工作量而不等 I/O 完成。
13/18
mm/swap: drop swap active plist
删除 swap_active_head 及 plist_node,设备身份查找改用可写 swap_info 迭代器;block-cgroup throttle 目标仍在 topology reader 下走 priority queue,取首个未屏蔽、可写、非 off-list 且有块设备的设备,并检查 WRITEOK/OFFLIST 与指针 tag,避免依赖 swapon 分配顺序。
14/18
lib/plist.c: remove requeue function
最后一个 plist_requeue 用户已移除,删除 include/linux/plist.h 声明和 lib/plist.c 实现,减少无用库代码。
15/18
mm/swap: reuse per-CPU queue readers across priority changes
在 swap_queue 插入新优先级时复用已安装的 per-CPU reader 数组,记录容量高水位直到队列空;新环放得下就重置有效 ring 索引,只有需扩容才在写者外准备并在写者内重查发布,保留 prepare/install 失败回滚,避免不必要分配导致 swapon 失败。
16/18
mm/swap: advance the global queue cursor directly between priority rings
分配游标改为直接保存 priority ring 索引和已尝试 peer 数,不再用总重试号每次从头扫描 swap_queue;首次访问某环才快照起始设备,逐 peer 含 masked 各访问一次,保留大 folio 同环边界与 reader offset 修正,遍历仍持 topology 读锁和禁迁移。
17/18
mm/swap: skip reader rotation for single-device priority rings
单设备优先级环无需轮转起始偏移或维护配额,直接在 topology 读锁和禁迁移下读取唯一项;仍走公共路径消耗游标尝试并检查满/禁用 tag,masked singleton 按既有边界终止或下探,省掉该常见情的 reader 本地状态更新。
18/18
mm/swap: redistribute queue readers after membership changes
设备增删后重置各 CPU 的有效 ring 偏移与配额:向已有环加 peer 会复用单设备时所有 CPU 相同的起点,删除设备和环也会留下旧成员描述;在 topology 写者下运行初始化 helper,按 cpu-id 取模做尽力轮转,不分配新 reader 存储、不增加选择热路径。