目前内核对ext4文件系统错误处理机制分为三种:1.不处理;2.内核panic;3.错误分区remount成只读形式。

处理机制的设定是在两个地方处理的,一个是在文件系统物理分区上设置,通过设置ext4文件系统分区的超级块中的“Errors behavior”参数,可以配置错误处理方式,一般默认处理方式是Continue(不处理),具体配置通过tune2fs搞定:

oen@oen ~ $ sudo tune2fs -l /dev/sda3 | head -n 10
tune2fs 1.42.5 (29-Jul-2012)</pre>
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux

另外一种方式则是通过配置mount参数搞定,参看man手册:

errors=continue / errors=remount-ro / errors=panic
Define the behaviour when an error is encountered. (Either ignore errors
and just mark the file system erroneous and continue, or remount the file
system read-only, or panic and halt the system.) The default is set in
the filesystem superblock, and can be changed using tune2fs(8).

mount参数通常情况下在fstab中mount参数中直接设定,一般情况下服务器环境中的系统分区都是通过mount设置错误处理参数,一般都要设定为errors=panic,如此宁可让系统重启,让双机保持系统稳定,也不能让业务进程挂死在只读分区上。

但很多情况下,没有设置挂载参数,最后文件系统错误也导致了分区只读,具体就要分析内核的实现了。

文件系统问题出错最终都要有ext4_handle_error函数处理:

static void ext4_handle_error(struct super_block *sb)
{
     if (sb->s_flags & MS_RDONLY)
     return;

     if (!test_opt(sb, ERRORS_CONT)) {
         journal_t *journal = EXT4_SB(sb)->s_journal;

         EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
         if (journal)
             jbd2_journal_abort(journal, -EIO);
     }
     if (test_opt(sb, ERRORS_RO)) {
         ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
         sb->s_flags |= MS_RDONLY;
     }
     if (test_opt(sb, ERRORS_PANIC))
     panic("EXT4-fs (device %s): panic forced after errorn",
     sb->s_id);
}

在代码第6行的判断中,如果系统默认不是EXT4_ERRORS_CONTINUE(即忽略不处理错误),则将journal置为aborted状态,然后结束;如果是挂载方式是只读,则将超级块的挂载标志位为MS_RDONLY;如果是panic,则打印panic告警并复位。

虽然系统默认不处理的情况下ext4_handle_error处理函数完美结束,但系统还在正常运行,如果系统需要对问题分区写入一些文件,此时IO会走JBD,获取handle原子操作,在ext4_journal_start_sb中判断journal状态,如果是aborted,则进入ext4_abort。

journal = EXT4_SB(sb)->s_journal;
if (is_journal_aborted(journal)) {
     ext4_abort(sb, __func__,
     "Detected aborted journal");
     return ERR_PTR(-EROFS);
 }

在ext4_abort中,如果分区状态不是只读,则将其分区置为只读。

void __ext4_abort(struct super_block *sb, )
{
    if ((sb->s_flags & MS_RDONLY) == 0) {
           ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
           sb->s_flags |= MS_RDONLY;
           EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
           if (EXT4_SB(sb)->s_journal)
               jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
           save_error_info(sb, function, line);
     }
     if (test_opt(sb, ERRORS_PANIC))
         panic("EXT4-fs panic from previous errorn");
}

真正工作中,文件系统的读写次数非常高,如果挂着参数不是panic,则文件系统出现bug,内核会将其置为只读状态。


ext4文件系统错误处理机制来自于OenHan

链接为:http://oenhan.com/ext4-fs-error-handle

4 thoughts on “ext4文件系统错误处理机制”

  1. “在代码第6行的判断中,如果系统默认不处理,则将journal置为aborted状态,然后结束”,这里第6行“if (!test_opt(sb, ERRORS_CONT)) ”表示的是如果系统默认不是ERRORS_CONT(不处理),则将journal置为aborted状态,如果是不处理的话,则不会执行任何操作退出函数了。

  2. “如果系统需要对问题分区写入一些文件,此时IO会走JBD,获取handle原子操作,在ext4_journal_start_sb中判断journal状态,如果是aborted,则进入ext4_abort。” 这里的“如果是aborted”的aborted状态是哪里置的呢?

发表回复