LWN:讓kernel使用更大的block size!
關(guān)注了就能看到更多這么棒的文章哦~
Moving the kernel to large block sizes
By Jake Edge
September 27, 2023
OSSEU
ChatGPT translation
https://lwn.net/Articles/945646/
使用更大的塊大小(block size)進(jìn)行I/O內(nèi)核是存儲(chǔ)和塊層領(lǐng)域經(jīng)常討論的話題。這個(gè)話題在2023年5月的Linux存儲(chǔ)、文件系統(tǒng)、內(nèi)存管理和BPF峰會(huì)(LSFMM)的討論中提出。在那些討論中的一位參與者Hannes Reinecke在2023年的Open Source Summit Europe上發(fā)表了一次關(guān)于為什么要使用更大塊進(jìn)行I/O、該工作的當(dāng)前狀態(tài)以及可能會(huì)引發(fā)的發(fā)展方向的概述演講。
Reinecke在SUSE工作了"差不多有20年了",在那之前他就已經(jīng)參與了Linux;他的第一個(gè)內(nèi)核版本是1.1.5或1.0.5。最近他一直參與存儲(chǔ)工作,特別是NVMe。這導(dǎo)致了他的一個(gè)個(gè)人項(xiàng)目"終于實(shí)現(xiàn)了",就是在Linux中能夠使用更大的塊。
塊和頁(yè)面
目前,Linux受限于使用不大于 PAGE_SIZE (通常為4KB)的塊大小。但有一些系統(tǒng)和應(yīng)用程序會(huì)受益于使用更大的頁(yè)面;例如,一些數(shù)據(jù)庫(kù)希望能夠使用16KB的塊,因?yàn)檫@是它們內(nèi)部組織數(shù)據(jù)的方式。此外,一些硬件也會(huì)受益于處理更大塊大小的數(shù)據(jù),因?yàn)檫@會(huì)減少內(nèi)部跟蹤block所需的開(kāi)銷(xiāo),從而使驅(qū)動(dòng)器更加高效和便宜。
[[https://static.lwn.net/images/2023/osseu-reinecke-sm.png]]
但是,他問(wèn)道,是否一定要有一個(gè)塊大小??jī)?nèi)核不能在需要的時(shí)候直接使用任意數(shù)量的數(shù)值嗎?問(wèn)題在于,沒(méi)有一個(gè)原子性地讀取或?qū)懭肴我鈹?shù)量數(shù)據(jù)的"do I/O"指令。每個(gè)I/O操作都需要多個(gè)指令來(lái)設(shè)置它,傳輸數(shù)據(jù)并收集結(jié)果。這會(huì)增加每個(gè)操作的延遲,因此目標(biāo)是盡量減少執(zhí)行的I/O操作數(shù)量,但也需要權(quán)衡。
有一個(gè)問(wèn)題是這些I/O操作的合適大小應(yīng)該是多少。他說(shuō),在早期階段,這是一個(gè)大量實(shí)驗(yàn)的主題。最終,加利福尼亞大學(xué)伯克利分校的研究人員("當(dāng)然,像往常一樣")找出了512字節(jié)是在開(kāi)銷(xiāo)和I/O粒度之間有合理折衷值的大小。這是二十年前的事情了,但我們目前仍然使用512字節(jié)—至少目前是這樣。
然而,CPU有硬件輔助的內(nèi)存管理,它以頁(yè)面為單位運(yùn)行。例如,有API可以確定哪些頁(yè)面是臟的(即需要寫(xiě)入后備存儲(chǔ)),就是以頁(yè)面大小來(lái)執(zhí)行的。這意味著頁(yè)面的大小取決于CPU,Linux不能隨意選擇大小。對(duì)于x86_64,選擇包括4KB、2MB或1GB;對(duì)于PowerPC和一些Arm系統(tǒng),使用16KB作為頁(yè)面大小。內(nèi)核有一個(gè)編譯時(shí)的 PAGE_SIZE 設(shè)置,規(guī)定了頁(yè)面的大小。
有時(shí)需要從磁盤(pán)讀取內(nèi)存中的頁(yè)面,或?qū)⑵鋬?nèi)容刷新到磁盤(pán)。對(duì)于緩沖I/O,頁(yè)面緩存(page cache)進(jìn)行了所有這些內(nèi)容的管理;它使用硬件提供的臟頁(yè)信息來(lái)確定需要寫(xiě)入哪些頁(yè)面。由于所有這些都是以頁(yè)面為單位完成的,因此以頁(yè)面大小單位進(jìn)行I/O是很自然的。
但是,如果有一系列連續(xù)的頁(yè)面都是臟的,那么你可以一次性對(duì)所有頁(yè)面進(jìn)行I/O。擁有一個(gè)處理多個(gè)頁(yè)面作為單個(gè)單元的數(shù)據(jù)結(jié)構(gòu)將有助于這一點(diǎn),這正是folios的目的。除了緩沖I/O (buffered I/O)之外,還有直接I/O(direct I/O),由用戶空間來(lái)完全控制;頁(yè)面緩存不涉及其中,用戶空間可以按需進(jìn)行多個(gè)塊的I/O。文件系統(tǒng)通過(guò)頁(yè)面緩存提供了緩沖I/O,并且有各種接口用于該I/O。最早的是緩沖頭(buffer heads),它的(某種程度上的)繼任者使用 struct bio ,而最近則有iomap,他說(shuō)他會(huì)回頭再談。然而,為了以更大的尺寸進(jìn)行緩沖I/O,頁(yè)面緩存需要轉(zhuǎn)換為使用folios。
Folios
folios是一種處理不同類(lèi)型頁(yè)面的嘗試。有普通頁(yè)面、復(fù)合頁(yè)面(就像是若干頁(yè)面組成的數(shù)組)和透明巨大頁(yè)面(THPs),每種頁(yè)面都有其自己的特點(diǎn)。然而,它們都可以使用 struct page 來(lái)訪問(wèn),因此內(nèi)核開(kāi)發(fā)人員必須知道給定的頁(yè)面結(jié)構(gòu)實(shí)際上是否是一個(gè)頁(yè)面—或者更復(fù)雜的東西。folios專(zhuān)門(mén)設(shè)計(jì)用于處理不同類(lèi)型,對(duì)于他的演講來(lái)說(shuō),重要的是它可以表示不止一個(gè)頁(yè)面,因此允許它用于更大塊的I/O。
這需要將頁(yè)面緩存—以及可能最終的內(nèi)存管理子系統(tǒng)—轉(zhuǎn)換為使用folios。這項(xiàng)工作由Matthew Wilcox于2020年提出,并在每次LSFMM上進(jìn)行了討論。它也曾經(jīng)是一些有爭(zhēng)議的郵件列表討論的主題。但工作仍在進(jìn)行中,將繼續(xù)進(jìn)行幾年("最終我們會(huì)成功的")。他展示了6.4-rc2內(nèi)核中" struct page "(8385)與" struct folio "(1859)的統(tǒng)計(jì)數(shù)量來(lái)展示事情的大致進(jìn)度。
然后,他轉(zhuǎn)向了緩沖頭(buffer heads),它們出現(xiàn)在0.01內(nèi)核中,因此是Linux中I/O的原始結(jié)構(gòu)。每個(gè)緩沖頭用于一個(gè)單獨(dú)的512字節(jié)磁盤(pán)扇區(qū),它跟特定的頁(yè)面結(jié)構(gòu)(page structure)關(guān)聯(lián)起來(lái),并在buffer cache中進(jìn)行緩存(以節(jié)省訪問(wèn)時(shí)的I/O)。大多數(shù)文件系統(tǒng)仍在使用緩沖頭,并且它們也用在了關(guān)于塊設(shè)備的一個(gè)偽文件系統(tǒng)中。頁(yè)面緩存(page cache)在內(nèi)核歷史中是比較后期才出現(xiàn)的,因?yàn)樵谠缙谶@個(gè)buffer cache就足夠了。
struct buffer_head 相對(duì)復(fù)雜,因此在2.5內(nèi)核中,引入了 struct bio 作為設(shè)備驅(qū)動(dòng)程序的"基本I/O結(jié)構(gòu)"。它允許對(duì)頁(yè)面數(shù)組進(jìn)行矢量化I/O,將bio結(jié)構(gòu)發(fā)送到各種設(shè)備,并從頁(yè)面緩存中抽象出來(lái)。如今,緩沖頭是在bio基礎(chǔ)設(shè)施之上實(shí)現(xiàn)的。有許多文件系統(tǒng),如AFS、CIFS、NFS和FUSE,直接使用 struct bio ,因此不依賴于緩沖頭。
最后,還有iomap,"或者說(shuō)是Christoph Hellwig有點(diǎn)發(fā)瘋";Hellwig對(duì)現(xiàn)有的I/O接口感到不滿,并創(chuàng)建了iomap作為替代,Reinecke說(shuō)。Iomap是一個(gè)現(xiàn)代化的接口,已經(jīng)使用folios;它為文件系統(tǒng)提供了一種指定I/O應(yīng)該如何映射的方式,并將其余部分留給block層。已經(jīng)將幾個(gè)文件系統(tǒng)轉(zhuǎn)換為使用iomap了,包括XFS、Btrfs和Zonefs,因此對(duì)于那些涉及folios轉(zhuǎn)換的文件系統(tǒng),無(wú)需再做其他工作。然而,iomap的一個(gè)問(wèn)題領(lǐng)域是文檔,文檔有點(diǎn)難找,而且常常過(guò)時(shí),因?yàn)閕omap正在積極開(kāi)發(fā)中。
替換緩沖頭?
存儲(chǔ)社區(qū)長(zhǎng)期以來(lái)一直有一個(gè)共識(shí),即"緩沖頭必須消失",他說(shuō)。他在今年的LSFMM上主持了一個(gè)關(guān)于這個(gè)話題的討論。這種思路是,緩沖頭是一種遺留接口,使用一種古老的結(jié)構(gòu),因此用戶應(yīng)該轉(zhuǎn)換為 struct bio 或iomap。但是,最近在ksummit-discuss郵件列表上的一次Linus Torvalds的不同意見(jiàn)引起了爭(zhēng)議。
回應(yīng)的強(qiáng)烈程度可能表明,應(yīng)該選擇不同的路徑來(lái)實(shí)現(xiàn)更大的block size的目標(biāo),Reinecke說(shuō)。轉(zhuǎn)換為folios是有用的,但只影響了頁(yè)面緩存和內(nèi)存管理子系統(tǒng);緩沖頭假定I/O將以子頁(yè)面粒度(即512字節(jié))進(jìn)行,因此需要解決這個(gè)問(wèn)題。一個(gè)可能的路徑是將所有內(nèi)容轉(zhuǎn)換為iomap,然后刪除緩沖頭,另一種可能是更新緩沖頭以處理更大的I/O大小。
在理想的情況下,所有文件系統(tǒng)都應(yīng)該轉(zhuǎn)換為使用iomap,他說(shuō);這是一個(gè)"現(xiàn)代化的接口,而且實(shí)際上是一個(gè)非常好的接口"。但是,正如ksummit-discuss的帖子所顯示的,有一些舊的文件系統(tǒng)沒(méi)有積極維護(hù)者—或者根本沒(méi)有維護(hù)者。對(duì)于這些舊的文件系統(tǒng),通常幾乎沒(méi)有文檔,也沒(méi)有真正可靠的測(cè)試改動(dòng)的方法。此外,轉(zhuǎn)換任何文件系統(tǒng)(無(wú)論是遺留還是不是)都需要更好的iomap文檔,以供進(jìn)行轉(zhuǎn)換的開(kāi)發(fā)人員使用。
另一個(gè)可能性是簡(jiǎn)單地刪除緩沖頭;Hellwig提供了一個(gè)允許將緩沖頭編譯出內(nèi)核的補(bǔ)丁集,已合并到了6.5內(nèi)核中。啟用該選項(xiàng)將意味著禁用所有使用緩沖頭的文件系統(tǒng),在當(dāng)前階段這并不完全現(xiàn)實(shí),Reinecke說(shuō)。特別是FAT文件系統(tǒng),它是用于引導(dǎo)UEFI系統(tǒng)的,如果在這樣的內(nèi)核中禁用了它,將無(wú)法引導(dǎo)。
在LSFMM上,Josef Bacik提出了將緩沖頭轉(zhuǎn)換為使用folios的想法,以便處理小于一個(gè)頁(yè)面(sub-page)或者超級(jí)頁(yè)面(super-page)的I/O。雖然這不是Reinecke最初選擇的方向,但他開(kāi)始考慮這個(gè)想法。這種轉(zhuǎn)換可能要么非常簡(jiǎn)單,如果代碼沒(méi)有關(guān)于sub-page I/O的什么假設(shè);要么就可能是一場(chǎng)完全的噩夢(mèng),因?yàn)檫@種假設(shè)普遍存在。
那天晚上,他在看了緩沖頭代碼后坐在酒吧里,對(duì)他的鄰居大聲抱怨。他不知道怎么能指望有人去轉(zhuǎn)換它們,因?yàn)樗鼈兣c頁(yè)面緊密相關(guān)。然后他意識(shí)到他的鄰居是Andrew Morton,他說(shuō):"在我實(shí)現(xiàn)這個(gè)代碼的時(shí)代,它還不錯(cuò)—而且它仍然能工作,不是嗎?"
因此,Reinecke開(kāi)始重新考慮將緩沖頭轉(zhuǎn)換為folios的想法,但需要解決許多問(wèn)題。首先,緩沖頭和iomap在根本上是不兼容的。例如,在頁(yè)面結(jié)構(gòu)中有一個(gè)void指針,根據(jù)使用的是哪種結(jié)構(gòu),它要么指向緩沖頭,要么指向iomap結(jié)構(gòu);在查看頁(yè)面緩存中的頁(yè)面時(shí),了解你擁有哪種結(jié)構(gòu)非常重要。需要謹(jǐn)慎考慮"混搭方法"。他說(shuō),review這些更改將會(huì)很困難,因?yàn)楹茈y發(fā)現(xiàn)對(duì) PAGE_SIZE 的依賴關(guān)系。
所有這些使他開(kāi)始懷疑,是否值得付出這么多努力來(lái)實(shí)現(xiàn)使用更大的block size 來(lái)進(jìn)行I/O的總體目標(biāo)。"我認(rèn)為是值得的…但這只是我的看法。"但他確實(shí)知道,數(shù)據(jù)庫(kù)確實(shí)希望能夠進(jìn)行更大的I/O操作,希望支持更大的I/O操作對(duì)文件系統(tǒng)來(lái)說(shuō)也會(huì)更高效。在很大程度上,文件系統(tǒng)已經(jīng)在更大的塊中進(jìn)行I/O操作。除了這些好處之外,驅(qū)動(dòng)供應(yīng)商希望出于效率、容量和實(shí)現(xiàn)更低成本的設(shè)備而使用更大的塊。
進(jìn)展
Reinecke在上周完成了他的補(bǔ)丁集。然而,就像在開(kāi)源世界中經(jīng)常發(fā)生的情況一樣,大約在同一時(shí)間出現(xiàn)了另一種實(shí)現(xiàn)。Luis Chamberlain和他在三星的同事發(fā)布了不同的補(bǔ)丁集,涵蓋了很多相同的領(lǐng)域。在演講中,Reinecke說(shuō),他正在提出自己的補(bǔ)丁來(lái)解決這些問(wèn)題,但他將在不久的將來(lái)與三星的人合作,將這兩種方法結(jié)合起來(lái)。
總體想法是將緩沖頭從頁(yè)面轉(zhuǎn)換為folios。這樣,所有的I/O仍然會(huì)小于所附加的單元,因此緩沖頭代碼中的假設(shè)仍然會(huì)得到滿足。folios將指向單個(gè)緩沖頭或緩沖頭列表的指針。在進(jìn)行此轉(zhuǎn)換時(shí)需要記住一些事情;首要的是內(nèi)存管理子系統(tǒng)仍然以 PAGE_SIZE 為單位工作,而頁(yè)面緩存和緩沖緩存已經(jīng)轉(zhuǎn)換為folios。
但是,為了進(jìn)行I/O,緩沖頭使用bio機(jī)制,它以512字節(jié)塊為單位工作。他說(shuō),這實(shí)際上已經(jīng)固定在塊層及其驅(qū)動(dòng)程序中,無(wú)法在不付出巨大努力的情況下更改。但實(shí)際的I/O由較低層驅(qū)動(dòng)程序處理,這些驅(qū)動(dòng)程序已經(jīng)將相鄰的塊合并為較大的單元。因此,頁(yè)面緩存中的folios可以傳遞給塊層,塊層將以512字節(jié)塊的方式枚舉它們,將結(jié)果交給驅(qū)動(dòng)程序,驅(qū)動(dòng)程序?qū)⑺鼈冎匦陆M裝為較大的單元。盡管這不是解決問(wèn)題的顯而易見(jiàn)的方法,但一切都"應(yīng)該正常工作"。
所以這就是他的補(bǔ)丁集的核心。當(dāng)然,還有其他工作要做,包括審核頁(yè)面緩存,以確保它分配了與底層驅(qū)動(dòng)程序使用的大小相同的folios,并確保它以folios大小的步長(zhǎng)遞增,而不是以頁(yè)面為單位遞增。他還需要為塊驅(qū)動(dòng)程序添加一個(gè)接口,以向頁(yè)面緩存報(bào)告其塊大小。一切都很順利,甚至可能太順利了,因?yàn)镹FS希望使用128MB的塊—并得到了—至少直到虛擬機(jī)出現(xiàn)內(nèi)存不足的情況。這個(gè)特定的測(cè)試"巧妙地證明了使用更大size的block會(huì)導(dǎo)致更高程度的內(nèi)存碎片化",如果真的需要這樣的證明的話。
完成了嗎?
盡管這些補(bǔ)丁使內(nèi)核能夠與具有大block size的驅(qū)動(dòng)程序通信,但仍然存在一個(gè)問(wèn)題:沒(méi)有驅(qū)動(dòng)程序在使用更大的block size,原因當(dāng)然是"因?yàn)闆](méi)有人可以與它們通信"。他已經(jīng)有了更新block ramdisk驅(qū)動(dòng)程序(brd)以支持更大block的測(cè)試目的的補(bǔ)丁。然后,該驅(qū)動(dòng)程序可以用作NVMe目標(biāo)的后備設(shè)備(backing device),以便可以使用更大的block size進(jìn)行測(cè)試。"這非常酷,但當(dāng)然還需要一些測(cè)試。"
還需要一些其他的工作。QEMU需要更新以支持更大的block size,需要使用它們來(lái)測(cè)試驅(qū)動(dòng)程序,還需要測(cè)試其他子系統(tǒng),如SCSI。除此之外,還需要與三星的工作統(tǒng)一起來(lái)。一旦所有這些都準(zhǔn)備就緒,就會(huì)進(jìn)行審查,然后需要處理審查引起的問(wèn)題,然后才能將這項(xiàng)工作推送給上游。
內(nèi)存碎片問(wèn)題仍然沒(méi)有解決。未來(lái),系統(tǒng)可能會(huì)具有各種不同的block size的設(shè)備;在這方面,16KB不應(yīng)該是一個(gè)主要問(wèn)題,但在未來(lái)可能會(huì)有更大的塊大小。內(nèi)存管理層繼續(xù)以page size的block來(lái)工作,這將導(dǎo)致額外的碎片化。如果系統(tǒng)可以切換到與更大的block size相同的粒度使用內(nèi)存,那么一切都變得完美了—但這假定只有一個(gè)block size,這可能并不成立。
一個(gè)可能的解決方案,可能值得獨(dú)立實(shí)施,是將SLUB分配器切換為使用更高級(jí)別的folios,而不是基于page的粒度。然后,如果 alloc_page() 用戶轉(zhuǎn)換為使用SLUB,它將消除分配的碎片問(wèn)題。不過(guò),再次強(qiáng)調(diào),這仍然要求只能有一個(gè)block size。他會(huì)很樂(lè)意聽(tīng)取在存在更大的block size的情況下改善碎片化情況的其他想法。
他在演講結(jié)束時(shí)提出了一個(gè)建議,"以防你真的很無(wú)聊":在block層及其512字節(jié)導(dǎo)向性方面仍然存在改進(jìn)空間。他認(rèn)為,將block層切換到使用folios并不是一項(xiàng)適合膽小的人的任務(wù),但他認(rèn)為這是可行的。bio結(jié)構(gòu)不直接存儲(chǔ)數(shù)據(jù),而是使用 struct bio_vec 以向量化形式存儲(chǔ)數(shù)據(jù)。雖然block層中有大約4000個(gè)使用 bio_vec 的情況,但這些情況也許可以轉(zhuǎn)換為使用folios而不是page。
[我要感謝LWN的旅行贊助商,Linux基金會(huì),為前往OSSEU的比爾巴奧提供旅行援助。]
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長(zhǎng)按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開(kāi)源社區(qū)的各種新近言論~
