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()
执行。