zswap 数据结构维护解析
zswap 是 Linux 内核中的一个前端压缩交换(swap)机制,它在内存中维护一个 zpool 来存储被压缩的页面,以减少磁盘 I/O 并提高性能。以下是 zswap 维护加解压相关数据结构的核心解析。
1. zswap 的核心数据结构
1.1 struct zswap_entry
zswap_entry 结构体表示 zswap 维护的每个压缩页面的元数据。
struct zswap_entry {struct rb_node rbnode; // 用于红黑树索引struct list_head pool; // 用于池管理pgoff_t offset; // 页面在 swap 空间中的偏移量struct zswap_tree *tree; // 所属的 zswap 树unsigned int length; // 压缩后数据的长度unsigned int swp_type; // 交换设备类型unsigned int refcount; // 引用计数
};
作用:
- 通过
rbnode组织为红黑树,便于高效查找。 offset和swp_type用于唯一标识 swap 空间中的页面。length记录压缩后数据的大小。tree指向zswap_tree,用于组织多个zswap_entry。
1.2 struct zswap_tree
zswap_tree 组织多个 zswap_entry,采用红黑树管理。
struct zswap_tree {struct rb_root rbroot; // 红黑树根节点struct rw_semaphore lock; // 读写锁保护
};
作用:
rbroot是存储zswap_entry的红黑树,支持高效插入、删除、查找。lock保护zswap_tree,防止并发访问问题。
1.3 struct zswap_pool
zswap_pool 代表 zswap 运行时管理的一个压缩池,支持多个池。
struct zswap_pool {struct list_head list; // 链接到 `zswap_pools` 全局链表struct zpool *zpool; // 关联的 zpool 实例struct crypto_comp *tfm; // 压缩算法实例(如 LZO, ZSTD)struct work_struct release_work; // 释放任务char tfm_name[CRYPTO_MAX_ALG_NAME]; // 算法名称int refcount; // 引用计数
};
作用:
zpool负责实际存储压缩数据。tfm是加密 API 提供的压缩上下文。release_work用于释放zswap_pool。refcount记录被使用的计数。
2. zswap 关键操作流程
2.1 页面压缩并存储流程
-
检查页面是否适合压缩
- 通过
zswap_frontswap_store()处理 swap 出的页面。 - 计算 swap type 和 offset,检查是否已经存在于
zswap_tree。
- 通过
-
压缩页面
- 选择合适的
zswap_pool进行存储。 - 调用
crypto_comp_compress()进行压缩。
- 选择合适的
-
存入
zpool- 调用
zpool_malloc()分配空间。 - 将压缩数据存入
zpool,并记录zswap_entry。
- 调用
-
更新
zswap_tree- 通过
rb_insert_color()插入红黑树。
- 通过
2.2 页面解压读取流程
-
查找
zswap_entry- 通过
zswap_frontswap_load()根据 swap type 和 offset 查询zswap_tree。
- 通过
-
从
zpool读取并解压- 通过
zpool_map_handle()获取压缩数据。 - 调用
crypto_comp_decompress()进行解压。
- 通过
-
恢复到物理页
- 将解压后的数据写回物理内存。
-
移除
zswap_entry(可选)- 如果页面不再需要保留,则从
zswap_tree中删除。
- 如果页面不再需要保留,则从
3. 相关源码文件
mm/zswap.c:主逻辑,包括zswap_entry、zswap_tree维护。mm/zpool.c:实现zpool,用于存储压缩数据。crypto/目录:压缩算法,如crypto/lzo.c。
4. 总结
zswap 通过 zswap_entry、zswap_tree 和 zswap_pool 维护压缩数据的存储与查询,结合 zpool 高效管理物理内存。其核心流程依赖于红黑树进行索引,加解压过程由 crypto_comp_compress() 和 crypto_comp_decompress() 执行。
