Ext4 Workshop 2014

作者:刘峥

2014年3月26日,Napa Valley, CA.  今年LSF/MM Summit 2014会议就在这里举行,因此Ext4 Workshop相应的也就在这里了。会议内容主要是讨论后续一年Ext4文件系统的开发问题。

今年讨论的内容如下:

  1. Data Block Checksums
  2. Reflink
  3. Encryption
  4. Extent Cache Shrinker
  5. Buffer_head Removal
  6. SMR/Flash Device Optimization
  7. Multi-block Allocation
  8. Testing
  9. Mount Options Restrict

与会人员:

  • Ted Ts'o (Google, Ext4/Jbd2 Maintainer)
  • Jan Kara (SUSE, Ext3/Jbd Maintainer)
  • Ric Wheeler (Redhat)
  • Eric Sandeen (Redhat)
  • Lukas Cerner (Redhat)
  • Carlos Maiolino (Redhat)
  • Darrick Wong (Oracle)
  • Zheng Liu (Alibaba)
  • Michael Halcrow (Google)
  • Eric Whitney
  • 两位来自Western Digital的工程师

1. Data Block Checksums

目前Ext4已经具备对元数据进行校验的能力。如果需要对文件系统元数据做校验,仅需通过如下命令即可:

# mkfs.ext4 -O metadata_csum ${DEV}

目前Redhat计划让文件系统支持数据的校验和,来保证数据的正确。由于需要在文件系统中保存每个数据的校验和信息,因此需要在文件系统中创建相应的数据结构来保存信息。目前有两个方案:

  1. 静态方案
  2. 动态方案

静态方案比较简单,类似于metadata checksums,预先在格式化文件系统时直接在每个block group中创建出需要的数据结构。这样的好处是简单,对文件系统的改动比较小,同时很容易根据block group直接找到对应的校验和的位置。缺点则是不太灵活,对一些不需要做校验的block也需要分配出相对应的空间(比如extent tree)。

动态方案则直接在inode或者block group的描述符中直接创建一个B+tree,所有的校验和均保存在其中。这样在查找/创建校验和的时候时间复杂度会有所上升。特别是在block group中分配的方案,由于多个文件可能同时修改同一个block group中的B+tree,所以会有锁争用的开销。

Ted指出静态的方法比较简单直接,可以一点点的改进。如果采用动态方案,则比较复杂。当然,理想情况下,Ted比较喜欢动态的方案。毕竟通过动态方案的实现,不仅仅是data block checksums的问题,连reflink的实现也会简单很多。另外就是一些细节的讨论,比如fsck的时候对data block checksums的检查、df显示磁盘空间时候的计算等等。

2. reflink

由于Mingming Cao没有出席今年的Ext4 Workshop,目前为止reflink的设计方案也没有任何邮件,同时Darrick也不太了解目前reflink的可能实现,因此reflink的讨论就变得极其有限了。reflink(2)调用的目的是创建一个新的inode,但是该inode指向的内容均为另外一个已经存在的文件。这个新创建的文件是COW的,对它的所有修改都不会反应在此前的文件上。正如上面介绍data block checksums时所说,reflink的实现需要创建一个B+tree来记录那些没有修改过的block,而如果有了data block checksums的动态B+tree,则问题迎刃而解,只需要在该B+tree中进行记录就解决了。具体reflink的实现,还是需要等相关的邮件才能揭晓。

3. Encryption

文件数据加密这个之前并不在讨论范围,是开会当天加上的,而且鉴于是Google需要的需求,所以排的位置十分靠前。文件系统的数据加密功能很容易理解,就是将写入文件的内容先进行加密再保存在磁盘上。在Ext4上加这个功能的原因是因为Android操作系统。印象中从Android 2.4之后的版本(我不是Android用户,不太了解 ^ ^)开始,默认的文件系统变成了Ext4。由于用户会在手机上登录各种网站,所以Chromium浏览器会将一些个人用户信息以文件形式保存在手机上。这当然没啥问题,除非您哪天手机丢了。那么这些用户的信息就存在被获取的可能。各位当然也不用担心太担心,因为目前Android系统上会在Ext4上再使用eCryptfs对文件数据进行加密保存。所以您的个人数据还是安全的。但是用Michael Halcrow的原话来讲就是,这完全是个错误。

所以为了纠正这个错误,目前Google的想法是让Ext4原生支持数据加密。关于具体的加解密理论我也不太了解,可说的不多。但是鉴于Google的原因,估计这个特性很快就会加到Ext4上。

4. Extent Cache Shrinker

再提这个问题的原因是在与PostgreSQL开发人员的交流过程中(这次LSF/MM邀请了几位PostgreSQL的开发者来分享一些他们对Linux Kernel开发的希望)发现他们也遇到了Shrinker回收过程过长的问题。这个问题很早就被报告给了社区,不过我一直没有时间去改进,对不起各位了。

目前Extent Cache Shrinker的问题主要是在RB-tree中保存了所有对象的信息。而有些对象由于需要被delayed allocation、seek data/hole功能使用,是不能被回收的,所以在某些情况下,会出现Shrinker扫描很长时间却扫描不到可以回收的对象的情况。对于这一问题,目前有两种改进方案:

  1. 添加一个list专门保存可以回收的对象
  2. 完全放弃LRU-list算法

方案1让Shrinker快速找到可以回收的对象,从而减少等待时间。但是仍然保留了目前的LRU算法,因此还是存在维护LRU的时间开销。另外,由于添加了另外一个list,内存开销会增加近1/3;方案2则完全放弃目前的LRU算法,通过指针记录上次扫描的位置,从该位置继续扫描可回收的对象。这样做可以避免维护LRU算法的开销,减少锁争用。由于目前Shrinker在回收对象时还要考虑inode的PRECACHE标志,因此较为复杂。Ted介绍目前Google内部的做法是完全不回收带有PRECACHE标记的inode,而对其他的则一概回收。当然这样做完全是出于Google自己的需要,PRECACHE的应用都是Google底层的核心应用。因此upstream kernel上不能这样做。同时由于Google大量direct IO的使用,产生delayed allocation对象的机会较少(不能被回收),所以问题也并不严重。

下一步的计划就是同时实现两个方案并比较结果。此外,对于Extent Status Tree,我还在考虑用skip list替代rb-tree的方案以减小锁争用的开销。

5. Buffer_head Removal

目前在Linux Kernel中,buffer_head结构的核心作用尽管已经被bio取代,但是仍然有大量文件系统的代码在使用buffer_head结构来记录文件系统的元数据信息。Ext4就是其中一个。当然,这也是没有办法的事情,毕竟VFS层的很多地方都还需要使用buffer_head结构。Ted提出这个想法的目前是在Ext4中,除了direct IO路径和data=journalled模式外,将所有使用buffer_head的路径中将这一结构干掉。这样做的目的如果是简单重构,其实意义并不大。Ted的想法是通过干掉bufferred IO路径上的buffer_head,从而避免使用buffer_head中的Delayed标记。这样就可以避免在blocksize与pagesize不同时处理的麻烦。随之而来的计划便是将dioread_nolock特性默认打开,从而提高高速设备上direct IO的性能(此特性可以解决目前Ext4中direct IO路径上的扩展性问题)。

尽管前景美好,但是Ted和Jan表示没时间搞。所以哪位有兴趣的可以试试看,做完这个,对整个Ext4的读写流程会非常熟悉的。

6. SMR/Flash Device Optimization

这块主要的改进思路其实已经体现在Ted发的RFC中了(http://lwn.net/Articles/579564/)。主要是两方面的改进,一方面是针对日志的改进,尽量减少对日志的频繁刷新,从而避免由于SMR随机写性能影响文件系统,造成性能下降。另一方面是对mballoc算法的改进,做到对SMR友好。鉴于目前大家基本都没有拿到可以测试的SMR硬盘,所以大家并没有什么意见提出。

7. Multi-block Allocation

对于mballoc算法的改进源于Lukas对使用thin-provision的Ext4文件系统进行测试时发现的问题。问题是mballoc目前的算法总是倾向于在整个块设备上分配磁盘空间,即便块设备的开头有空闲空间,mballoc也经常会分配块设备后面的空间来进行使用。这在传统磁盘上当然没有问题(其实还是有问题的,因为越往后磁盘性能越差),但是对于thinp设备就要命了,因为thinp设备根本就没有宣称的那么大的空间,所以文件系统总是分配后面的磁盘空间thinp设备自然受不了。Lukas目前有补丁来解决这个问题。但是从长远来看,还是需要改进mballoc的分配算法。目前最大的问题是很多mballoc中的代码除了Andreas Digler(mballoc的作者)就没人知道为啥要这么写了。。。

另外谈到的一个关键问题是如何测试来确保分配算法确实有改进和不是造成性能的下降。大家还是给了些意见的,包括用一些成熟的测试工具,用已有的磁盘使用情况的Tracer等等,总之目前对于mballoc的改进还没有具体方案,只是有这个想法。

8. Testing

Ted介绍了自己的测试方法,再次强调了测试的重要性并希望大家多测试。同时感谢了Eric Whitney的测试工作。Ted也提出了对于xfstests测试框架的改进意见,希望Redhat的同学能进行改进。

9. Mount Options Restrict

这个话题去年就聊过了,但是还是没有彻底解决。主要问题是去年Redhat主要在弄RHEL7,没空搭理这个小问题。但是今年RHEL7大问题都解决了,所以这个小问题又提上桌面了。主要问题还是发行版希望使用Ext4内核模块来挂在Ext2、Ext3文件系统。但是这样就存在到底这么多特性哪些特性可以用在哪些文件系统上。今年这件事情从Lukas转到Carlos身上了。

今年预计Ext4会开发的新特性如下:

  • Data Block Checksums
  • reflink
  • Project Quota
  • mballoc优化
  • Ecryption
  • Extent Cache Shrink优化

CLSF 2013讨论会纪要(一)

10月17日到18日两天在LSI上海办公室参加了 CLSF2013 讨论会。简要记录之,如有错误,欢迎拍砖。

第一天早上开场先是由LSI亚太区的总裁致辞欢迎大家,因为请来的几乎都是LSI的客户:华为、oracle、阿里、百度、腾讯等(其实还有竞争对手,比如fusionio:)。当然,LSI做为东道主不仅提供了场地还提供了中午饭,还真要谢谢人家。

先由Jeff Liu介绍去年xfs的进展。xfs去年最大的改动是加入了自描述的元数据,其实就是元数据的CRC校验,如果读取时发现校验对不上,就直接返回IO error。因为这个校验的增加,还将superblock升级到了v5,从测试来看加此校验只增加了不到5%的CPU消耗。
涛哥发问:“你是在机械硬盘上测的吧?机械硬盘太慢,所以校验计算增加的overhead比例就不明显,你应该用SSD进行测试。”
Jeff回答:“我们oracle没钱,我就一个笔记本,只能自己买了一个ORZ,不,是OCZ的便宜SSD做测试,overhead也就是这个水平。“
xfs_io现在开始支持SEEK_DATA/SEEK_HOLE,可以直接找到文件空洞所在的偏移。通过在mount的时候计算transaction log的保留空间(而不是像过去在运行时计算),减少了运行时的压力。在xfs做日志恢复时加入了readahead,减少了读延迟,加快了日志恢复的速度。
还有一些特性尚未merge code,但是正在开发中的,比如:在线文件系统缩容(涛哥一个劲的追问:谁会有这么奇怪的需求?);为空闲inode单独建一个btree,以加快小文件创建(也就是分配inode的速度);对inode cache的压缩(这里要解释一下,xfs是一款有20年历史的老文件系统,当初从SGI弄到linux里来的时候linux的vfs还不完善,所以里面有很多代码是做了今天vfs的很多工作的,所以inode也比较肥大:超过1700字节,有了压缩以后,可以减小到308字节),不仅省内存,也减少了磁盘IO。
接下来的讨论是关于online fsck的,
涛哥:我们线上有需求,如果机器异常重启,做fsck太慢来不及,所以希望先启动机器,然后慢慢的做online fsck,但是ext4是没有online fsck功能的,xfs有吗?
Jeff:xfs的目标,是不需要fsck,元数据自我描述自我恢复,现在AG(xfs的块分配单位,allocation group)就是自我管理的
Coly:我们当初挑选过的,xfs的代码量要几倍于ext4的,以我们这么小的团队和互联网对文件系统那么小的需求,ext4更加合适
Jeff:这个,xfs代码量大的问题,我得说两句,首先,xfs代码风格比较古老,函数调用里每个参数都是单起一行的,而且,注释量达到30~40%,比ext4的10~20%高得多,所以代码量自然也大得多。
涛哥:如果xfs有类似online fsck的功能,就是文件系统一边被使用一边做修复检查,那我们会考虑部分使用xfs的
Jeff:现在没有这个功能,也没有开发计划
涛哥:那xfs还有什么优势?
Jeff:xfs的需求是来源于付费的大客户的,要求大文件的支持、良好的稳定性、良好的扩展性、高并发IO下的良好性能
文卿:ext4在打了directio nolock的补丁以后,并发读写已经赶上xfs了....
总之,Jeff被涛哥一顿烂虐。后来吃晚饭的时候,涛哥反复申明:”我不是要难为Jeff,是我确实遇到一些需求ext4目前不好解决,如果xfs能满足我们就考虑部分使用xfs“,我:”你这样问法是不对的,你拿着火枪跑到武术馆说‘你们的武术能快过火枪吗?能快过我就学你们的武术’,这不是踢馆是什么?”

Intel的Yuanhan Liu(不是我故意输入英文名,是coly给的日程表里都是英文名,没办法)介绍和吴峰光一起做的0-day kernel test自动化框架,能自动检测kernel tree的性能变化(不管是好的变化还是坏的变化),然后自动bisect找到引起变化的patch,给相关人员发信。其实我们这边(阿里)非常需要这样的自动测试系统,因为内核组一个专职QA都没有。于是我们怂恿intel的同学把这个自动化测试的东东做成一个测试云服务,我们好接入,“做为回报,我们会持续的大量的继续购买intel的CPU“(Coly原话)。


clsf-2013

吃中午饭的时候我向Jeb Tang讨教了线上遇到的磁盘IO hang住的问题,Jeb表示,这个问题极难查找原因,因为磁盘的firmware、raid/sas卡的firmware、内核驱动都有嫌疑,而且他感觉,6Gb SATA口很多人反映稳定性不如3Gb的,更不如SAS口,所以google在服务器定制的时候,干脆在每个sata口上加了个reset芯片,一旦发生io hang住的情况,自己调那个芯片硬件reset那个sata口(相当于插拔硬盘,只不过不需要人肉了),就返回io error了。我于是专门问了这个reset芯片的价格:一个0.6美元。
边吃饭还边请教了百度的谢广军同学对于已经mount了的磁盘,插拔后怎么做到盘符绑定,原来用udev可以。回头我试试。

下午是我厂的文卿同学介绍ext4的进展。extent status tree终于进入upstream,以前aio会等在ext4元数据分配这个地方,现在有了extent status tree,等待少了很多。以前ext4的"打洞“只支持extent的文件,现在也支持间接块式的文件,甚至还支持bigalloc下的打洞。另外,bigalloc和delay allocation合用会有warning的那个问题也解决了,当然,Ted否决了我的patch以后,用了一个也不咋高级的方案。算了,不提这些了。谢广军同学对bigalloc表示了兴趣,当然,目前还在观望,主要看其他屌丝(比如我们)有没有把bigalloc的坑踩完。文卿同学说到了online fsck的那个需求,
文卿:目前能支持online fsck的文件系统就是三个,linux上的btrfs,freebsd上的zfs和ffs,btrfs太不稳定,zfs和ffs并发IO的性能不如ext4,用户不接受。所以目前我们还在想办法。另外,我们现在也在做ext4的quota功能,但是subtree的dir quota不准确,也需要改进。rhel7以后就默认xfs了,在这之前,ext4还是得发挥余热....
广军:不是吧,我们百度才不到20%的用的是ext4,还要推广呢,你这就”发挥余热“了?!
我:看来终于有一个新东西我们比百度的同学推得快了

来自oracle的Bob Liu同学介绍了zswap。zswap其实就是把要swap到硬盘的page先压缩再存磁盘,这样可以减少IO延迟,但是会多耗一点CPU。这个功能最早是在IBM的power架构上做的,用的是power带的协处理器来做LZO压缩,所以比较合适。

来自苏州柯达的majianpeng同学介绍了他所在公司的监控系统对文件系统和存储的需求。他们一开始用的是IPSAN做后端存储,但是发现成本太高,于是改用自己开发的用户态的文件系统来合并小文件为大文件(类似淘宝的TFS),现在已经成本很低了,也满足了需求。我很好奇的问jianpeng同学何以在软raid社区发了那么多patch,他说那不是他的工作是他的兴趣爱好属“不务正业”,我很感慨,我应该向他好好学习。


clsf-2013

ext4磁盘碎片查看

子团兄最近在测试ext4的bigalloc特性,cluster为256K,放入了16个大文件,每个文件25GB。反馈我说碎片很多,我觉得很奇怪便问是怎么看出来碎片多的,他说是用fsck看的:

#fsck.ext4 -f -y /dev/sdi1
e4fsck 1.42 (29-Nov-2011)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sdi1: 27/7631216 files (59.3% non-contiguous), 104148800/488377984 blocks

看起来"non-contiguous“占到了59.3%,似乎碎片很多的样子。
我翻了一下代码,这个值是在e2fsprogs包里计算出来的:

e2fsck/unix.c

static void show_stats(e2fsck_t ctx)
{
....
    frag_percent_total = ((10000 * (ctx->fs_fragmented +
                    ctx->fs_fragmented_dir))
                  / inodes_used);
....

其实就是用该文件系统中"fragmented“的文件数加上"fragmented”的目录数,再除以一共创建出来的inode数(也就是总文件数加总目录数)。但是哪种文件称为"fragmented“呢,看看扫描extent结构的代码:

e2fsck/pass1.c

static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                             struct process_block_struct *pb,
                             blk64_t start_block, blk64_t end_block,
                             ext2_extent_handle_t ehandle)
{       
....
                if ((pb->previous_block != 0) &&
                    (pb->previous_block+1 != extent.e_pblk)) {
....
                        pb->fragmented = 1;
                }
....

只要这个extent与上一个extent物理块上不是连上的,这个文件就算是"fragmented“了(目录亦如此)。即使用上bigalloc特性,一个cluster配成256KB,那么一个block group就是4K * 8 * 256K = 8G大小,对于25G大小的文件来说,怎么都不可能连续,因为跨block group了,16个大文件那就算16个"fragmented“,除以inode总数27(这个inode总数包括了文件、目录、甚至journal本身也算一个inode)那就是59.3%了。
这样计算出来的"non-contiguous“只能反映非连续文件占总文件数的比例,不能说明磁盘的碎片多与不多。大文件几乎不可能extent相连一点空都不留,但因此就说碎片严重并不合理,因它是由几个不相连的大块组成的;比如一个25G的文件由4个8G的大块组成,我们不能因为它是"fragmented“的就说碎片很严重,毕竟才4个碎片。换个角度,我如果在该ext4里创建100个4KB的小文件,那non-contiguous就是16/127=12.6%,这并不能表示碎片情况变好了,因为多了这么多小文件,其实磁盘上碎片更多了。

要综合评估磁盘的碎片状况到底是好是坏并不容易,推荐的办法是用filefrag -v看看磁盘里某几个大文件的碎片情况,如果它们的碎片很少,而文件系统里的小文件也不多,那基本可以认为磁盘碎片不严重。当然,最彻底的办法是用dumpe2fs查看每个block group里block bitmap被分配的情况。

集群里机器hang住 备忘1

今天和刘毅同学一起研究了一下集群里机器hang住的现象。
所谓“hang住”,就是磁盘抽风(当然,也可能是sas/raid卡抽风),对发给它的io都不返回,造成许多访问它的进程都进入“D”状态,应用停止工作,等在read/write等系统调用上,严重的甚至终端命令都无法返回。

几个主要的场景都出现了ext4的报错:

EXT4-fs (sdx): delayed block allocation failed for inode 98838775 at logical offset 2048 with
 max blocks 2048 with error -5

有的还伴随CDB错误:

sd 0:0:8:0: [sdx] CDB: Read(10): 28 00 c0 c0 00 57 00 00 08 00
end_request: I/O error, dev sdi, sector 3233808471

分析了一下,分两种情况。

第一种情况——kernel没报CDB错误,但是ext4的delay alloc报错且应用hang住了。看/var/log/messages,前面有这么几行:

Jul 31 15:24:01 kernel: : [1391835.617793] EXT4-fs error (device sdx): 
ext4_init_block_bitmap: Checksum bad for group 1664
Jul 31 15:24:02 kernel: : [1391835.749685] EXT4-fs error (device sdx): 
ext4_mb_generate_buddy: EXT4-fs: group 1664: 0 blocks in bitmap, 24544 in gd

ext4已经发现checksum不对了,还记得这个“ext4_mb_generate_buddy”在之前的实验中遇到过,block-group一旦数据被破坏,报的就是这个错误。虽然ext4有uninit_bg,但是这依赖于硬盘中那个小小的struct ext4_group_desc中的flag带有EXT4_BG_BLOCK_UNINIT这个bit,如果fio破坏了这个bit,把它给从1变0了,那就相当没有开启uninit_bg,ext4上来就认为这个group已经初始化,一检查检验和就发现不对了。后面一切逻辑也都不对了。看来ext4对裸盘读写不是完全免疫的,只是比ext3抗磨一些。

第二种情况,有CDB错误但是delay alloc还是hang住了。发生读CDB错误,那ext4的代码在分配文件空间的时候(就是delay alloc开始往磁盘上落的时候),读到元数据就是错的,分配空间失败,那就一定报错

fs/ext4/inode.c
mpage_da_map_and_submit()

        blks = ext4_get_blocks(handle, mpd->inode, &map,
                               &new, get_blocks_flags);
        if (blks < 0) {
                ....
                ext4_msg(mpd->inode->i_sb, KERN_CRIT,
                         "delayed block allocation failed for inode %lu at "
                         "logical offset %llu with max blocks %zd with "
                         "error %d", mpd->inode->i_ino,
                         (unsigned long long) next,
                         mpd->b_size >> mpd->inode->i_blkbits, err);
                printk(KERN_CRIT "This should not happen!!  "
                       "Data will be lost\n");
                ....

总的来说,虽然都发生delay alloc的报错,但并不是ext4本身的问题,只因为它是个热路径,所以每次下层的错误都是它先倒霉。所以,首先,要确保mkfs之后不再用fio读写裸盘,再观察一段时间,看是否还有无CDB错误但hang住的情况;其次,如果可能,慢慢分批把机器的mpt2sas驱动升级,因为没有磁盘真正损坏却这么多CDB错误,mpt2sas驱动有很大的嫌疑。

先mkfs后写裸盘

步骤是这样:

1. mkfs.ext4格盘
2. 用fio工具随机写裸盘
3. mount盘为ext4文件系统并开始使用

发现一切使用正常,很多块盘都是这样做的,无一出错,使用了很久dmesg里连WARN都没有。但是一旦换成mkfs.ext3,使用一段时间就有报错了。
这个步骤的顺序肯定是错的,应该先写裸盘再mkfs,但是同事的问题是:为什么ext4不怕而ext3就不行了?

用dumpe2fs查看ext4的feature,嫌疑最大的是uninit_bg,因为带上这个ext4默认的标记后,mkfs.ext4就不会把block group的信息初始化为0,而是等mount后由内核ext4在使用到该block group时再临时初始化,所以在mount前即使block group被其它工具写坏了也不怕。代码见:

e2fsprogs
misc/mke2fs.c
main() --> ext2fs_initialize()

ext2fs_initialize()
{
        for (i = 0; i < fs->group_desc_count; i++) {                                        
                /*
                 * Don't set the BLOCK_UNINIT group for the last group                      
                 * because the block bitmap needs to be padded.                             
                 */
                if (csum_flag) {                                                            
                        if (i != fs->group_desc_count - 1)
                                ext2fs_bg_flags_set(fs, i,
                                                    EXT2_BG_BLOCK_UNINIT);                  
                        ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);                   
......

其中EXT2_BG_LOCK_UNINT和EXT2_BG_INODE_UNINIT就是用于标记该block group在用时才初始化的:

ext4_read_inode_bitmap()
{
        ext4_lock_group(sb, block_group);
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
                ext4_init_inode_bitmap(sb, bh, block_group, desc);
                set_bitmap_uptodate(bh);
                set_buffer_uptodate(bh);
                ext4_unlock_group(sb, block_group);
                unlock_buffer(bh);
                return bh;
        }                                                                                   
        ext4_unlock_group(sb, block_group);                                             k
......

ext4_init_inode_bitmap即是把inode bitmap全部清0

做个实验确认一下:

1. mkfs.ext4 -O ^uninit_bg /dev/sdc
2. fio跑32K的随机写,十分钟
3. mount -t ext4 /dev/sdc /test/
4. for i in `seq 1 9000`; do mkdir /test/dawu$i; ./falloc -p /test/dawu$i/1 -o 0 -l 100M ; done
(之所以在根目录下创建这么多目录,是因为ext4会把根目录下的目录均匀到不同的block group去,有助于问题重现)

dmesg里会有错误:
[ 6808.192101] EXT4-fs error (device sdc): ext4_mb_generate_buddy: EXT4-fs: group 7416: 25800 clusters in bitmap, 32768 in gd
[ 6808.192978] EXT4-fs error (device sdc): ext4_mb_generate_buddy: EXT4-fs: group 7417: 25304 clusters in bitmap, 32768 in gd
[ 6808.193635] EXT4-fs error (device sdc): ext4_mb_generate_buddy: EXT4-fs: group 7418: 25304 clusters in bitmap, 32768 in gd
....
如果带上uninit_bg参数格盘,同样的步骤,没有任何错。
uninit_bg本来是用来加快mkfs的速度的,没想到歪打正着,还不怕少量随机写裸盘的影响,不过还是不建议这样做,万一哪天随机写把super block写坏了,那什么文件系统都没辙了。
感谢舞爷的刨根问底,我又长见识了。

1 2 3