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閱碼場",掃描下方二維碼關注

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