步骤是这样:

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写坏了,那什么文件系统都没辙了。
感谢舞爷的刨根问底,我又长见识了。