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