近日,麒麟软件的工程师定位到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
• 在业务层面进行优化, 避免在同一个目录写入千万级别的文件
通讯员 | 闫相臣、张诗达
来 源 | 产品与社区发展中心、研发中心
审 核 | 市场与政府事务部
往期回顾