Linux阅码场 - Linux内核月报(2020年11月)

关于Linux内核月报

Linux阅码场

Linux阅码场内核月报栏目,是汇总当月Linux内核社区最重要的一线开发动态,方便读者们更容易跟踪Linux内核的最前沿发展动向。

限于篇幅,只会对最新技术做些粗略概括,技术细节敬请期待后续文章,也欢迎广大读者踊跃投稿为阅码场社区添砖加瓦。

本期月报主要贡献人员:

张健、廖威雄、chenwei、夏天

往期链接:

Linux阅码场 - Linux内核月报(2020年06月)

Linux阅码场 - Linux内核月报(2020年07月)

Linux阅码场 - Linux内核月报(2020年08月)

Linux阅码场 - Linux内核月报(2020年09月)

Linux阅码场 - Linux内核月报(2020年10月)

阅码场征稿Linux阅码场征集Linux工程师一线研发心得;工程师、高校学生老师、科研院所研研究人员对Linux某一技术要点深入分析的稿件。您的文章将获得近十万一线Linux工程师的广泛受众。投稿要求:原创且从未在任何媒体、博客、公众号发表过的文章。高屋建瓴、深刻全面地论述一个技术点或者面。投稿请微信联系小月:linuxer2016录取的稿件,我们也会奉上微薄的稿酬聊表寸心,稿费标准为300-500元/篇。

内核版本

Linus Torvalds Linux 5.10-rc4 November 16, 2020

  1. 体系结构相关

1.1 Guest Last Branch Recording Enabling

LBR(last branch recording)是一个performance monitor unit (PMU)特性,记录了在LBR stack中处理器最近的分支跳转记录。这次的补丁是为KVM虚拟机使能LBR。

1.2 x86: Support Intel Advanced Matrix Extensions

Advanced Matrix Extension(AMX)是一个x86架构上一个新的矩阵运算编程框架。包括称之为TILE的二维寄存器堆(目前的大小是8k)和一组加速器。如果使用当前的管理XSAVE状态的方式管理AMX寄存器,每个任务都需要分配上述8k空间,这有点浪费。所以AMX的工作引入了eXtendedFeature Disabling (XFD),当相应task第一次访问TILE状态时,会触发#NM异常并切换AMX的状态。

参考资料:https://en.wikichip.org/wiki/x86/amx

1.3 Add AMD SEV page encryption bitmap support

之前月报提到过AMD的SEV技术,这个技术可以把虚拟机的内存加密,从而避免从主机得到虚拟机的数据。这个补丁引入了加密位图以支持虚拟机热迁移,虚拟机page migration和虚拟机调试。

1.4 An alternative series for asymmetric AArch32 systems

之前月报提到过,这个补丁用于在系统只有部分arm64 CPU支持aarch32 EL0运行环境(即非对称的系统)时,在用户空间可以使用aarch32应用。现在补丁发到了第四版,这次介绍下接口和实现。

如果希望在这样非对称的系统运行aarch32应用,需要先使能内核参数allow_mismatched_32bit_el0。系统启动后,可以从”/sys/devices/system/cpu/aarch32_el0”读到支持的cpu,其格式和/sys/devices/system/cpu/{offline,online,possible,present}一样,例如”0,3-6“表示0,3,4,5,6这五个核支持aarch32 EL0。

用户可以通过查询这个接口,在对应核心执行aarch32应用。如果用户空间在仅仅支持aarch64的cpu上执行aarch32应用,内核会通过修改task affinity使其调度到支持aarch32的cpu上。从用户空间看起来,就好像是想运行aarch32的aarch64 CPU被热插拔移除了。

对于用户空间和内核ABI感兴趣的童鞋可以看看这个补丁,了解如何新增一个内核特性并暴露给用户空间。

1.5 arm64: Introduce prctl(PR_PAC_{SET,GET}_ENABLED_KEYS)

ROP(Return-oriented programming)是把函数返回前的代码片段(Gadgets)拼接起来实现的攻击。有一种预防的方式是Pointer authentication,这个方法通过在函数进入和退出时检查指针签名是否合法以阻止非法跳转。Pointer authentication的签名称为 Pointer Authentication Code (PAC)。

这个补丁允许用户程序(例如 ld.so )控制特定进程使用哪一个PAC密钥,这样既可以保证特定代码的保护,也可以保证不支持PAC的二进制可以正常运行。

参考资料:iPhone上PAC设计:https://downloads.immunityinc.com/infiltrate2019-slidepacks/marco-grassi-liang-chen-2pac-2furious/infiltrate19_final.pdf

1.6 arm64:msr: Add MSR driver

来自阿里巴巴的王荣巍写了一个MSR的驱动,支持用户空间访问有权限的MSR寄存器,并提供了相应的用户空间工具。https://github.com/alibaba/system-register-tool

 

  1. 文件系统和Block Layer

2.1 新的IO调度算法:i10

补丁:https://lwn.net/Articles/837009/

新的硬件功能催生除了新的 IO 调度算法。在这系列补丁中,作者提出了 i10 IO调度算法,主要是为了让一些支持批处理请求的块设备实现最大IO吞吐率。

越来越多的设备支持批处理多个请求,例如一些新的 MMC,例如像 nvme-tcp 这样的基于 tcp 的存储驱动。虽然块层已经支持了批量请求的分发功能,我们还需要一个 IO 调度器来有效地启用批处理,这个新的 IO 调度器需要热衷于解决那种可以并行处理 IO 请求的场景,不仅仅是单个并行处理IO请求的设备,还包括多个存储设备组合的情况。于是,作者提出了 i10 IO 调度算法。

i10 调度算法以请求数量、字节数和超时时间作为批处理的判定条件。当请求的数量或者字节数达到默认阈值时,或者超时,就会触发批量分发请求。当前默认的阈值是 16 个请求或者 64 KB 的请求大小或者 50us 的超时时间。当前,这些默认值并不一定是最好的,将来的计划则是能做到根据系统负载自适应分发,同时实现对延迟敏感的应用实现低延迟,对吞吐有要求的应用实现高吞吐。

虽然其他调度器也可以批处理 IO(例如mq-deadline),但 i10 IO 调度器中的优化目标是吞吐量最大化。因此没有延迟目标,也不需要全局跟踪上下文,因此需要一个新的调度程序,而不是将此功能构建到现有的调度程序中。

2.2 fscrypt支持直接IO

补丁:https://lwn.net/Articles/837510/

fscrypt:https://www.kernel.org/doc/html/latest/filesystems/fscrypt.html

系列补丁通过 blk-crypto 实现 fscrypt 的直接 IO 访问。

此处拓展下 fscrypt,这里指的是内核的 fscrypt 而不是其配套使用的 fscrypt 工具包。fscrypt 并不是一个文件系统,而是集成到文件系统中的一个功能,例如 ext4、ubifs、f2fs都已经支持 fscrypt。与 dm-crypt 这样的块设备加密不同,fscrypt 是文件系统级别的加密,准确来时是文件、文件夹粒度的加密,能实现加密文件与非加密文件的并存,且是不同文件不同机密key。这在多用户且要求不同加密的情况非常实用。

2.3 close_range() 新增参数标志 CLOSE_RANGE_CLOEXEC

补丁:https://lwn.net/Articles/837602/

close_range()是比较新的系统调用了,用于支持批量关闭文件。其声明是这样的:

int close_range(unsigned int fd, unsigned int max_fd, unsigned int flag)

当 CLOSE_RANGE_CLOEXEC 参数使能时,close_range 会设置 close-on-exec 位而不是直接关闭文件。

close-on-exec 功能很早就有了,顾名思义,就是在执行 exec() 的时候自动把标记了的文件句柄关掉。在我们 fork() 时子进程会从父进程继承所有的文件句柄,在 exec() 后文件句柄依然是生效的,有时候不关掉会造成一些奇怪的问题。例如服务进程A通过socket与端进程B通信,当B进程退出了,理论上socket无人连接,但实际上却依然有进程在监听,导致进程A无法断开链接。原因就在于进程B 在fork()->exec() 执行其他程序时继承了进程B的文件句柄。

2.4 支持直接读写压缩的数据

补丁:https://lwn.net/Articles/837656/

这补丁添加了一些接口,实现直接从支持压缩的文件系统中读取裸的压缩数据,而不经过文件系统的透明解压过程。同时也支持直接写入压缩数据而不经过文件系统本身的压缩。

这功能目前主要用在 Btrfs 的收发数据上。当前,当从支持压缩的 Btrfs 发送压缩数据到另外一个支持压缩的 Btrfs 时,发送端默认流程总会先解压,而接收端也会对收到的数据再压缩后才写入。这的确挺浪费资源的,因此就有了这补丁。

 

  1. 虚拟化和容器

本月,谷歌在KVM发力,尝试将他们在Android-KVM项目中的诉求扩展到Linux Arm64 KVM upstream中,以满足移动客户的需求。本月两个主要的虚拟化补丁集都是为解耦KVM和HostOS Kernel做铺垫。目的是希望做到在没有GuestOS的显示许可的情况下,HostOS不能够访问虚拟机的内存。这不仅需要将EL2上的KVM代码与EL1上的HostOS内核进行分割,还需要在HostOS与虚拟机之间建立标准化通信,以实现相互控制的共享内存实例化,并在hypervisor实现之间实现一定程度的可移植性。详情参考David Brazdil和Quentin Perret的补丁序列。

 

另外Red Hat的工程师正在为virio - mem开发一种“大块模式”(big block mode),目前的virtio-mem驱动只支持不超过单个Linux memory block最大容量的设备块大小。“big block mode”解决了这个问题,并允许Linux虚拟机使用任何大小的设备块。大块模式对于Red Hat在QEMU中VFIO支持方面的工作也很重要。这种新virtio-mem工作模式允许轻松创建GB字节范围内的块,并且可以热拔插。大块“BB”跨越多个Linux memory block,并以大块的粒度添加/删除到内存管理代码中。子块模式仍然受支持,其模式由Linux Memory block大小和设备块大小决定。详情参考David Hildenbrand的补丁集。

3.1 Opt-in always-on nVHE hypervisor

David Brazdil在这个月引入了Arm64下的Always-on nVHE Hypervisor模式。该模式是针对当hostOS运行在nVHE模式的hypervisor之上时,让GuestOS的状态对HostOS不可见的一种努力。该补丁集在本月一共更新了三版。这个补丁序列允许hypervisor在HostOS运行之前将自己安装到新启动的CPU之上。

 

这个补丁集已经在Rock Pi 4b上测试过。作者发布该RFC补丁主要是想收集一些反馈以做如下决策:

1)      内核根据最终确定的系统功能检查新CPU核的特性。为了避免将这些代码/数据移动到EL2,该实现只允许启动在KVM初始化时上线的CPU核。

2)  捕获和转发的SMC调用无法被关闭。这可能会导致一些问题。比如EL3总是返回EL1。在这些的平台上,可能需要一个内核命令行参数来关闭该特性。(已经在V1和V2中通过Eearly Parameter实现)

 

3.2 KVM/arm64: A stage 2 for the host

这个RFC补丁系列提供了在nVHE中运行KVM时使用stage 2 包装HostOS内核的一些基础结构。这对于一些用户场景可能很有用,但主要的动机是(最终目的)能够保护虚拟机的内存不受HostOS内核的影响。更多有关总体思路、设计和动机可以在Will Deacon在KVM Forum 2020上的演讲[1]中找到,或者在LPC 2020期间Android uconf上的pKVM演讲[2]中找到。

[1] https://kvmforum2020.sched.com/event/eE24/virtualization-for-the-masses-exposing-kvm-on-android-will-deacon-google

[2] https://youtu.be/54q6RzS9BpQ?t=10859

 

这个补丁系列基本上可以我们让我们知道,当KVM运行在nVHE模式并且'kvm-arm.protected'标志在内核命令行中被设置时,我们该在什么地方设置Host的HCR_EL2寄存器的'VM'比特位。存在于EL2对象(参考在之前介绍的nVHE hypervisor)直接处理来自Host的Memory Abort,并完全管理stage 2页表。

 

然而,本系列Patch还没有任何真实的用户,目前只是将所有内容以RWX和Cacheable属性,通过idmap(一比一映射)映射到Host的stage 2中。目前这些都是一些基础设施的工作,还没有准备好upstream,因此该补丁集还是RFC状态。

 

伴随本系列补丁而来的一个有趣需求是,管理页表需要在EL2上使用某种内存分配器来分配、计数和释放内存页面。显然,在目前的nVHE模式中这些一个都没有实现,因此本系列补丁的一大块内容都是致力于解决这个问题。目前提议的EL2内存分配器在原则上是模仿Linux的buddy系统,并重用了一些arm64内存管理的设计。具体地说,它在EL2上使用了vmemmap,这包含一组hyp_page数据结构来保存页面的元数据。为了支持这一点,作者扩展了EL2对象,让它在管理Host的Stage 2页表之外还管理自己的stage 1页表。这简化了hyp_vmemmap的创建,并且在保护VM内存不受hostOS内核干扰的用例中无论如何都是必需的。因为威胁模型告诉我们HostOS在启动阶段完成之后,并不能被信任,因此确保它不能任意映射EL2上的代码是至关重要的。

 

EL2分配器使用的内存池是在HostOS在启动阶段使用memblock API预先保留的(在HostOS的启动阶段它仍然是受信任的),并在KVM init期间转交给EL2。当前的假设是,主机保留了足够的内存,允许EL2对象以页面为粒度为hyp stage 1和Host Stage 2以及一些设备做映射。

 

除此之外,本系列补丁还引入了一些在此过程中需要的较小特性,在相关的提交消息中对这些特性都进行了适当的说明。

 

在最后,作者也指出,目前可以用一些简单的方法让HostOS绕过Stage 2保护来访问守保护VM内存。例如,它仍然拥有某些Guest的Stage 2页表,这意味着目前还没有什么可以阻止被恶意修改的HostOS使用这些Guest作为代理来访问受保护的Guest的内存。但本系列补丁为以后解决这些问题奠定了基础。

 

3.3 virtio-mem: Big Block Mode (BBM)  

virtio-mem的基本思想是提供一种灵活的、跨体系结构的虚拟机内存热插拔解决方案,避免了现有技术、体系结构和接口强加的许多限制。

             

 

virtio-mem目前只支持最多单个Linux Memory Block的设备块大小。例如,在x86-64上,hypervisor中的巨型页面导致设备块大小为1 GiB时,而Linux内存块大小为128 MiB,我们就无法支持这样的设备(驱动程序会加载失败)。我们希望在任何Linux VM中支持任何设备块大小。 

3.4  KVM: X86: TDX support

该补丁集是Intel为支持TDX特性收集社区反馈而做的RFC补丁集。主要还是为处于high-level设计阶段的KVM TDX增强收集反馈信息。目前该补丁集还不是很完整,也不能正常工作。但是可以作为一个公开讨论的基础。所以本期也不做太多介绍。但我们可以借机简单介绍下TDX。首先TDX是Trust Domain Extension的缩写,该特性用于隔离虚拟机和VMM (Hypervisor)以及平台上的其它一些软件。下图是TDX的可信边界:

        

虚拟机的CPU状态和内存信息对VMM和其它软件都不开放(CPU-STATE Confidentiality And Integrity)。以下是一个访问示意图。VMM需要TDX模块中的密钥才能够访问虚拟机的状态和内存信息

       

(END)

更多精彩,尽在"Linux阅码场",扫描下方二维码关注

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章