.. Kenneth Lee 版权所有 2021
:Authors: Kenneth Lee :Version: 1.0 :Date: 2021-12-10 :Status: Released
5.15
2021年10月31日发布。\ [1]_
传统的DRAM swap策略是DRAM页不足了,通过shrink放弃部分页面,如果Page dirty就自动 同步到back file上了。这个版本提供了一个新功能,把这些Page迁移到Persistent内存中。 我就不明白了,为什么不直接把swap建立在这些Persistent上?
我不怎么用Btrfs,但我们把这个作为大特性来分析一下fs-verity和id-mapped是什么东 西。
fs-verity是一个文件级别的dm-verity。后者用于创建一个device-mapping层,这一层会 调用crypto API对readonly的目标进行摘要,从而保证目标的数据是可靠的。dm-verity的 摘要放在另一个块设备上,通过dm-verity参数<dev>和<hash_dev>分别指定目标块设备和 摘要块设备完成整个算法。
fs-verity的功能类似,你通过ioctl要求校验一个文件,请求生效后,文件系统里面会另 外创建一个透明的摘要影子,目标文件会变成只读,之后你再访问这个文件,它就必须校 验通过才能访问得到了。这个功能最早是在ext4和f2fs上支持的。
fs-verity的ioctl命令包括:
我没有看到接口上有去激活的接口,我猜只能通过删除来去激活。
这个框架要求文件系统提供少量代码支持(我猜主要是用于放这个影子文件吧)。
而id-mapped特性也许应该叫id-remapped特性,它可以把文件系统里面的用户id,map到另 一个id上。这种事情我自己就经常遇到。比如我有一个备份用的U盘,把我的用户(比如叫 kenny)的文件备份上去,用户id是1000,但到了另一台机器,我这个kenny的用户对应到 1001,这样U盘上的用户就对不上我另一台机器的kenny了。id-mapped允许你在mount的时候 指定这个映射关系,比如你要映射1000到1001,1001到1002,你可以用参数:::
u1000:k1001:r2
来mount(具体命令如何设计还没有看),这样就映射了两个id的关系了。这里u和k表示 user和kernel,具体的算法有不少规则(而且我一眼看上去没有看懂),但和我关系不大 ,就不看下去了。
这个特性叫DAta access MONitor,是一个轻量级内存访问监控框架。它可以告诉你一个进 程的内存怎么被使用的,哪地方访问得比较多,哪些地方访问得比较少,哪些地方干脆就 没有访问。
工具的输出通过一个叫\ damo <https://github.com/awslabs/damo>
_\ 的工具提供,它
的输出结果是这样的:
.. figure:: _static/masim_stairs_heatmap_ascii.png
也可以生成图形的报告:
.. figure:: _static/damo_graph_report.png
框架的代码实现在mm/admon下,它是一个针对每个跟踪对象的内核线程(kdamond),启动 跟踪后周期性扫描被跟踪对象的页表,根据dirty bit找到它是否被修改过,从而得知对应 的区域有没有发生更改,它的跟踪项不以页为单位,而是以有相同特征的region为单位( 感觉这只能节省没有访问过的空间的跟踪数据结构)。
它还在自己的跟踪点上设置了tracepoint,这样这个工具可以通过trace接口来跟踪每个变 更的事件。
它也提供的debugfs接口在/sys/kernel/debug/damon目录下。
它同时提供了kunit和sleftest的测试用例,我觉得kunit这个框架也算是简单有效了,以 后我们的代码也可以把它们作为基本方法放进去的,专门用来测试数据接口挺好的。
这是Amazon德国提交的补丁。
这个系统调用用于做OOM Killer的工作,也就是“收割目标进程”。OOM Killer主要是用于 系统内存不足的时候,杀掉一个最值得牺牲的进程从而获得额外的资源。Android上的“杀 后台”功能是一种最常见的情况了。但OOM Killer是有不少障碍的,因为如果被杀的进程正 在做系统调用,里面做了uninterruptable的锁,你的信号可发过去,但那个进程不一定能 立即响应你,你还是拿不到想要的内存。解决思路当然是让这家伙回不去用户态,一旦退 出uninterruptable区就让它死掉,这就算提前清它的内存也不用担心了。这就叫killer和 reaper分离。
新的process_mrelease(pidfd, flags)调用就完成独立的reaper功能,它只有两个参数, 一个类似pidfd_send_signal()那样的pid文件句柄,另一个是flags,暂时没有用,只要不 是0就行。完成的功能就是直接找到这个任务,把它的vma全部释放掉再说。只是任务句柄 什么时候被释放,那就等其他的kill流程来搞了。
PREEPT-RT特性提供了新的锁机制,提升系统的实时性。这个修改包含72个补丁,包括: rtmutx,rtlock, rwlock, spinlock,futex等锁的修改,它需要在schedule中认知正在做 这些锁的进程的行为,对调度策略进行调整。
为了这个算法,rb-tree的头文件依赖关系出了问题,所以也影响这个部分的代码。
这个代码涉及东西太多了(大部分补丁修改的东西都不如commit comment长,可想而知这 些修改的内聚有多低),我没能把逻辑都连起来。等有需要的时候再看吧。
BTW,ttwu是try to work up的缩写。
同一批补丁一起修改的还有33个修改SLUB的补丁,这些工作应该是一组提高实时性的系列 工作成果。我现在不怎么管嵌入式系统,可能做嵌入式的同学可以跑跑实时测试套看看提 升了多少。
Symmetric Scheduling Affinity。也许应该称为非对称调度绑定。主要是在CPU支持的用 户态的指令集不一样的时候,把CPU分成不同的类别,限定进程只能在这些CPU间迁移。这 我还以为肯定是ARM给的补丁,结果是Google的,但Will Deacon以前是ARM的,说是ARM的 补丁也差不离了。
现在这个方案是需要用户态制定自己可以兼容的CPU在什么位置上的,设置后反映为 task.user_cpus_ptr上的一个掩码。
这个框架不是这个版本才加入的,但这次它提交了一组比较长的补丁引起我的注意。所以 我作为一个大特性来分析。
VDUSE是字节跳动维护的一个特性,叫vDPA Device in Userspace。而vDPA是Redhat维护的 一个特性,叫virtio Data Path Accelerator。说起来原理很简单,就是把网卡数据面直 接从内核分流到virtio共享内存buffer,让虚拟机用virtio设备去处理它。然则,既然 virtio一直宣称不仅针对虚拟机,还可以是任何要暴露给用户态的接口,那么提供一个用 户态直接访问它的引擎也顺理成章了。
不过实际看这个代码,会发现它并不是直接使用用户态的virtio设备去用这个框架的,而是 在内核中直接和vDPA接口,同时封装了iommu/iova接口接口来提供用户态支持的。
为了理解这个框架,我们可以先理解一下vDPA框架:
:doc:`vDPA框架分析<vdpa>`
根据这个分析,我们注意到了,要创建一个新的vdpa,你需要在内核驱动里面干。但VDUSE 呢,希望可以根据需要创建任意多的虚拟vdpa设备,所以它创建了一个控制文件: /dev/duse/control,你通过这个文件下命令,可以创建很多的vdpa设备实例,设置它们的 virtqueue参数。
但这样有什么用呢?这些vDPA和谁通讯呢?难道是为了虚拟机之间互相通讯?
现在只能这样猜了。