近日,麒麟軟件的工程師定位到Linux內(nèi)核中的一項bug,并將問題描述、復現(xiàn)步驟、觸發(fā)條件、可能的優(yōu)化方案等信息同步到上游內(nèi)核社區(qū)。
問題現(xiàn)象描述
在服務(wù)器上將數(shù)據(jù)盤格式化成ext4文件系統(tǒng)時,如果強制指定blocksize 64K大小,在同一目錄下文件數(shù)量達到千萬級別時,可能導致系統(tǒng)ext4文件系統(tǒng)異常,文件寫入失敗等問題。
問題定位
經(jīng)過層層定位,發(fā)現(xiàn)ext4 get_dx_countlimit()函數(shù)有三處代碼可能導致問題的產(chǎn)生。下圖函數(shù)主要是在校驗fakedirent -> rec_len的長度,在不符合規(guī)范的情況下可能返回空值。
ext4 中目錄采用了B+樹(htree)結(jié)構(gòu)來加速查找過程。這其中將節(jié)點劃分為了根節(jié)點和中間節(jié)點,而fakedirent 是每個節(jié)點的第一個entry,用于記錄整個節(jié)點的大小。
對此, rec_len的可能取值有以下兩種情況:
??rec_len?= blocksize(表明屬于中間節(jié)點?struct dx_node)
??等于12個byte大?。ū砻鲗儆诟?jié)點?struct dx_root)
在 rec_len 不屬于以上兩種取值時,程序會報錯并返回空值。
通過問題定位,發(fā)現(xiàn)故障文件中rec_len的值為0xffff,這是由于blocksize 為64K時,rec_len的值應(yīng)當為0x10000, 但是由于字節(jié)大小限制,會使用rec_len = 0xffff 來代表 rec_len = 0x10000。
而在最初的代碼中,對rec_len進行校驗時存在異常,可能導致問題出現(xiàn)。
問題復現(xiàn)
在實驗環(huán)境模擬現(xiàn)場復現(xiàn),通過在同類服務(wù)器上數(shù)據(jù)盤在格式化成ext4時強制制定blocksize 64K大小,同時在一個目錄下創(chuàng)建 2000?萬個文件夾,成功復現(xiàn)問題現(xiàn)象,此時文件夾無法進行讀取,系統(tǒng)日志內(nèi)出現(xiàn)了 ext4 文件系統(tǒng)的報錯。
同時,按照同樣的復現(xiàn)步驟,使用其他發(fā)行版本和 Linux 社區(qū)最新內(nèi)核,指定 blocksize 64K大小,也成功復現(xiàn)了這一問題,證明這一問題同時存在于社區(qū)以及主流的Linux系統(tǒng)上。
問題修復
基于上述分析及定位,麒麟軟件推出修復方案,并將該方案第一時間推送社區(qū)(點擊閱讀原文可訪問社區(qū)鏈接),提醒所有ext4用戶在此場景下都會遭遇相同的問題。
同時,麒麟軟件建議問題修復前:
??在業(yè)務(wù)部署時格式化存放數(shù)據(jù)硬盤,采用默認值blocksize 4K, 避免強制設(shè)置64K
??在業(yè)務(wù)層面進行優(yōu)化, 避免在同一個目錄寫入千萬級別的文件
通訊員?|?閆相臣、張詩達
來? ? 源?| 產(chǎn)品與社區(qū)發(fā)展中心、研發(fā)中心
審? ? 核?| 市場與政府事務(wù)部
往期回顧