上下层依赖
重要数据结构
zswap_pool
struct zswap_pool { // 挂 zswap 所用的内存池
struct zpool *zpool;
struct crypto_acomp_ctx __percpu *acomp_ctx;
struct kref kref;
struct list_head list;
struct work_struct release_work;
struct work_struct shrink_work;
struct hlist_node node;
char tfm_name[CRYPTO_MAX_ALG_NAME];
};
struct zpool *zpool
:指向 zpool 对象的指针,用于表示当前 zswap 池所对应的 zpool。可能需要基于 uma 进一步封装实现。struct crypto_acomp_ctx __percpu *acomp_ctx
:指向压缩算法。struct crypto_acomp_ctx { struct crypto_acomp *acomp; struct acomp_req *req; struct crypto_wait wait; u8 *dstmem; struct mutex *mutex; };
struct kref kref
:用于实现引用计数技术的 kref 对象,用于管理 zswap 池对象的生命周期。当一个 zswap 池对象被创建时,其引用计数值初始化为 1;当该对象被使用时,其引用计数值增加;当不再需要该对象时,其引用计数值减少,当引用计数值降为 0 时,该对象将会被释放。 FreeBSD 支持 refcount 特性,我们认为是可以迁移的。struct list_head list
:用于实现链表的list_head
结构体,用于将当前 zswap 池对象添加到 zswap 的池列表中。普通链表头,可以迁移。struct work_struct release_work
:表示一个工作队列对象,用于异步释放当前 zswap 池对象。在该工作队列中执行的操作会在一个单独的内核线程上运行,从而避免阻塞当前进程。struct work_struct shrink_work
:表示一个工作队列对象,用于在 zswap 池中的页面数量超过一定阈值时触发缩减操作。该工作队列也是异步执行的,在单独的内核线程上运行。FreeBSD 的 taskqueue 和 workqueue类似,都支持异步调用,可以迁移。
struct hlist_node node
:表示一个哈希表节点,用于将当前 zswap 池对象添加到 zswap 的池哈希表中。char tfm_name[CRYPTO_MAX_ALG_NAME]
:表示保存压缩算法名称的字符数组,用于指定 zswap 池所使用的压缩算法名称。在进行前端交换时,内核将会根据该名称来查找相应的压缩算法,并使用其进行数据压缩处理。
zswap_entry
struct zswap_entry {
struct rb_node rbnode;
pgoff_t offset;
int refcount;
unsigned int length;
struct zswap_pool *pool;
union {
unsigned long handle;
unsigned long value;
};
struct obj_cgroup *objcg;
};
struct zswap_entry
表示单个被压缩页面元数据。
struct rb_node rbnode
:红黑树节点pgoff_t offset
:表示该页面在交换分区中的偏移量,也是红黑树的 idxint refcount
:表示对该页面的引用计数,用于保证在页面同时被加载、失效和写回等操作时不会出现条件竞争,从而避免页面被过早地释放。unsigned int length
:被压缩后页面长度。struct zswap_pool *pool
:标识该页面所属的 zswap 池。union
:a)
unsigned long handle
:压缩页面数据句柄。这个是 zpool 用的。b)
unsigned long value
:内容相同的空白页面填充值。struct obj_cgroup *objcg
:指向obj_cgroup
结构体的指针,用于标识该页面所属的 cgroup(如果按 cgroup 进行回收)。
zswap_tree
struct zswap_tree {
struct rb_root rbroot;
spinlock_t lock;
};
这个结构体代表了一个 zswap 树的元信息,分别有一个红黑树的根和一个自旋锁。
一点对 zswap_pool\entry\tree的理解
enrty 是页面单元,包括该页在内存中的位置大小等信息,pool是实际存储 entry 元信息对应页面压缩后数据的内存池,tree 维护了一颗平衡树,用于找到对应 type+offset 的元信息entry。
zswap_header
一个 ulong
其他全局变量
一般为 config 或者全局状态量,易于迁移。
page
篇幅过长,Linux 的基础页面数据结构
重要依赖模块
内存管理池 zpool
- zpool 是 linux 的一类内存管理 API,是 zswap 所依赖的最底层的数据结构。zswap_pool 通过 zpool 的各类内存管理工具,包括申请、映射、收缩等关键操作
异步压缩 acompress
- acompress 是 linux crypto 下的模块,它提供了类似队列式的异步的压缩和解压缩能力
- 同时,crypto 模块还提供了统一的同步方式
swap 框架 frontswap
- 提供了一种 swap 接口层,通过实现 frontswap 提供的函数指针,可以自定义swap 的实现方式
- 有了 frontswap,我们只需要关注 swap 后端的设计,并向对应的初始化、存入、取出等接口实现逻辑、提供功能即可。frontswap 是zswap 最重要的依赖之一
平衡树 rbtree
- 维护 zswap_tree 的核心数据结构,保证插入和索引 offset 对应的页面的时候的复杂度。
工作队列work_queue
- 提供一个异步工作的机制,包括对 pool 的 shrink 和 release
引用计数 kref
- 需要一个引用计数器,主要是保证在 pool 和 entry被释放时的内存安全性
锁与信号量
- 主要需要关于自旋锁和互斥锁的 aquire/release的实现,避免线程竞争带来的各类安全和数据访问问题。
原子操作
一般依赖模块
认为一般依赖模块仅是为了某些特性准备,不影响 swap 的关键流程
scatterlist
为了支持 acomp 的参数而依赖,属于间接依赖
多 CPU 系列的宏和回调注册
有的为了支持 CPU 热插拔事件、有的为了实现 acomp 在多 CPU 上的真并行
kmem_cache
entry_cache 的底层申请与管理依赖于 kmem_cache,属于性能优化。
评论 (0)