背景
zswap 把换出的页压缩后存放在内存池里,swap 槽位与 zswap entry 的映射记录在 xarray 中,每 64MB swap 区域一棵。swap 槽位被批量释放时(swap_range_free),每个槽位对应的 zswap entry 都要失效:从所属的 tree 中擦除并释放。zswap_store() 存储失败或 zswap 被禁用时也要清掉 folio 各页偏移上可能残留的旧 entry,否则后续 writeback 会用旧数据覆盖新写入的 swapfile 内容。
失效接口按单槽设计的浪费
┌──────────────────────────────────┐
│ swap 槽位按 64MB 区域分树 │
└────────────────┬─────────────────┘
▼
┌──────────────────────────────────┐
│ 释放槽位要从对应 tree 擦除 entry │
└────────────────┬─────────────────┘
▼
┌──────────────────────────────────┐
│ 旧接口一次一个槽,调用方逐槽循环 │
└──────────────────────────────────┘
旧的 zswap_invalidate() 一次只处理一个槽,接口按 swp_entry 设计:调用方把 type 与 offset 打包成 swp_entry,函数进门第一件事就是再解开,而两个调用方手里本来就有这两个值。swap_range_free 只能逐槽循环调用,zswap 从未启用的系统上,每次调用仍然要做一次 xarray 的空检查。zswap_store 的回退路径则把同样的逐页查找擦除逻辑又手写了一遍,对空 tree 也照样发起 erase 查找。
问题
- swap_range_free 逐槽调用 invalidate,每次打包再解开 swp_entry
- zswap 从未启用时,槽位释放仍逐槽触碰 xarray
- zswap_store 回退路径重复实现同一套失效逻辑
- store 回退路径对空 tree 也发起 erase 查找
方案
invalidate 接口 range 化
zswap_invalidate() 的签名从单个 swp_entry 改为直传 type、offset 与 nr_entries,打包再解开的往返消失。逐槽循环收进函数内部,swap_range_free 对整个 range 只调用一次。槽位所属的 xarray 按 64MB 区域划分,一个 range 可能跨多棵 tree,内部循环按槽重算所属 tree,空 tree 跳过,否则逐个 xa_erase 并释放 entry。
未启用时整体跳过
函数入口新增 zswap_never_enabled() 判断,这是一个 static branch,zswap 从未启用时整个 range 的失效工作坍缩成一次分支判断,不再逐槽触碰 xarray。不开 zswap 却使用 swap 的系统,槽位批量释放路径上的这部分纯开销被整体移除。
整个 range 一次调用
┌─────────────────────────────────────┐
│ 调用方直传 type 与 offset,不再打包 │
└──────────────────┬──────────────────┘
▼
┌─────────────────────────────────────┐
│ 未启用时 static branch 直接返回 │
└──────────────────┬──────────────────┘
▼
┌─────────────────────────────────────┐
│ 内部逐槽重算 tree 并擦除 │
└─────────────────────────────────────┘
store 回退路径复用同一实现
zswap_store 的 check_old 路径直接调用 zswap_invalidate(),替换掉手写的逐页 tree 查找加 erase 循环。重复实现删除的同时,回退路径继承上 never-enabled 与 xa_empty 两道守卫:zswap 从未启用时直接返回,空 tree 不再发起 erase 查找。
store 回退路径复用 invalidate
┌──────────────────────────────────┐
│ 存储失败须清掉偏移上的残留 entry │
└────────────────┬─────────────────┘
▼
┌──────────────────────────────────┐
│ 复用 invalidate,删掉手写循环 │
└──────────────────────────────────┘
收益
作者未提供性能数据,从代码逻辑推断的预期收益:
- zswap 未启用系统的 swap 槽位批量释放,从逐槽 xarray 访问降为一次 static branch 判断
- range 一次调用,消除逐槽的 swp_entry 打包解包与函数调用开销
- store 回退路径消除重复的失效实现,空 tree 不再做 erase 查找