当 ATA 停止响应时,md RAID 中的设备失败

Del*_*tik 6 linux raid io mdadm raid6

我已经创造5个1TB HDD分区/dev/sda1/dev/sdb1/dev/sdc1/dev/sde1,和/dev/sdf1在a)中RAID 6阵列称为/dev/md0使用mdadm在Ubuntu 14.04 LTS可信赖的塔尔羊。

命令 sudomdadm --detail /dev/md0用于显示处于活动同步状态的所有驱动器。

然后,为了测试,我/dev/sdb通过/dev/sdb1在阵列中仍处于活动状态时运行这些命令来模拟长 I/O 阻塞:

hdparm --user-master u --security-set-pass deltik /dev/sdb
hdparm --user-master u --security-erase-enhanced deltik /dev/sdb
Run Code Online (Sandbox Code Playgroud)

警告

不要在你关心的数据上尝试这个!
由于此 ATA 操作,我最终损坏了 455681 个 inode。我承认我的疏忽。

用于安全擦除的 ATA 命令预计将运行 188 分钟,阻止所有其他命令至少那么长时间。

md原本希望像一个合适的 RAID 控制器一样丢弃没有响应的驱动器,但令我惊讶的是,它/dev/md0也被阻塞了。

mdadm --detail /dev/md0 查询被阻止的设备,因此它会冻结并且不会输出。

这是/proc/mdstat我无法使用时的布局mdadm --detail /dev/md0

root@node51 [~]# cat /proc/mdstat 
Personalities : [raid6] [raid5] [raid4] [linear] [multipath] [raid0] [raid1] [raid10] 
md0 : active raid6 sdf1[5] sda1[0] sdb1[4] sdc1[2] sde1[1]
      2929887744 blocks super 1.2 level 6, 512k chunk, algorithm 2 [5/5] [UUUUU]

unused devices: <none>
Run Code Online (Sandbox Code Playgroud)

我试图mdadm /dev/md0 -f /dev/sdb1强行失败/dev/sdb1,但这也被阻止了:

root@node51 [~]# ps aux | awk '{if($8~"D"||$8=="STAT"){print $0}}' 
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      3334  1.2  0.0  42564  1800 ?        D    03:21   3:37 parted -l
root      4957  0.0  0.0  13272   900 ?        D    06:19   0:00 mdadm /dev/md0 -f /dev/sdb1
root      5706  0.0  0.0  13388  1028 ?        D    06:19   0:00 mdadm --detail /dev/md0
root      7541  0.5  0.0      0     0 ?        D    Jul19   6:12 [kworker/u16:2]
root     22420  0.0  0.0  11480   808 ?        D    07:48   0:00 lsblk
root     22796  0.0  0.0   4424   360 pts/13   D+   05:51   0:00 hdparm --user-master u --security-erase-enhanced deltik /dev/sdb
root     23312  0.0  0.0   4292   360 ?        D    05:51   0:00 hdparm -I /dev/sdb
root     23594  0.1  0.0      0     0 ?        D    06:11   0:07 [kworker/u16:1]
root     25205  0.0  0.0  17980   556 ?        D    05:52   0:00 ls --color=auto
root     26008  0.0  0.0  13388  1032 pts/23   D+   06:32   0:00 mdadm --detail /dev/md0
dtkms    29271  0.0  0.2  58336 10412 ?        DN   05:55   0:00 python /usr/share/backintime/common/backintime.py --backup-job
root     32303  0.0  0.0      0     0 ?        D    06:16   0:00 [kworker/u16:0]
Run Code Online (Sandbox Code Playgroud)

更新(2015 年 7 月 21 日):在我等待了整整 188 分钟以清除 I/O 块后,当我看到md将完全空白的部分视为完全完好时,我的惊讶变成了恐惧/dev/sdb

我认为这md至少会看到奇偶校验不匹配,然后会下降/dev/sdb1

惊慌失措,我又跑mdadm /dev/md0 -f /dev/sdb1了,因为 I/O 块已经解除,命令很快完成。

随着输入/输出错误的出现,文件系统损坏已经发生。仍然惊慌失措,我懒惰地卸载了 RAID 阵列中的数据分区,reboot -nf因为我认为它不会变得更糟。

e2fsck分区上咬指甲后,455681 个 inode 使其成为lost+found.

我已经重新组装了数组,现在数组本身看起来很好:

root@node51 [~]# mdadm --detail /dev/md0
/dev/md0:
        Version : 1.2
  Creation Time : Mon Feb 16 14:34:26 2015
     Raid Level : raid6
     Array Size : 2929887744 (2794.16 GiB 3000.21 GB)
  Used Dev Size : 976629248 (931.39 GiB 1000.07 GB)
   Raid Devices : 5
  Total Devices : 5
    Persistence : Superblock is persistent

    Update Time : Tue Jul 21 00:00:30 2015
          State : active 
 Active Devices : 5
Working Devices : 5
 Failed Devices : 0
  Spare Devices : 0

         Layout : left-symmetric
     Chunk Size : 512K

           Name : box51:0
           UUID : 6b8a654d:59deede9:c66bd472:0ceffc61
         Events : 643541

    Number   Major   Minor   RaidDevice State
       0       8        1        0      active sync   /dev/sda1
       1       8       97        1      active sync   /dev/sdg1
       2       8       33        2      active sync   /dev/sdc1
       6       8       17        3      active sync   /dev/sdb1
       5       8      113        4      active sync   /dev/sdh1
Run Code Online (Sandbox Code Playgroud)

md没有我预期的两条保护线,这对我来说仍然很震惊:

  • 设备锁定时发生故障
  • 当设备返回的数据是垃圾时使设备发生故障

问题

  1. 为什么没有md响应的驱动器/分区不会失败?
  2. 当驱动器被阻塞时,我可以从阵列中删除驱动器/分区吗?
  3. 是否可以配置超时以便使md未响应 ATA 命令的驱动器自动发生故障?
  4. 为什么md继续使用数据无效的设备?

Del*_*tik 3

Deltik,您误解了 Linux Software RAID ( md) 的工作原理。

md从多个设备或分区中创建虚拟块设备,并且不知道您正在向虚拟设备传输什么数据或从虚拟设备传输什么数据。
你希望它可以做一些它没有设计做的事情。


答案

1. 为什么没有md响应的驱动器/分区不会出现故障?

这是因为md不知道是否

  • 驱动器正忙于处理md自身请求的 I/O 或
  • 由于某些外部情况(例如驱动器自身的错误恢复或在您的情况下是 ATA 安全擦除),驱动器被阻止,

因此md将等待查看驱动器返回的内容。驱动器最终没有返回任何读取或写入错误。如果存在读取错误,md则会自动从奇偶校验中修复它,如果存在写入错误,md则会导致设备故障(请参阅md手册页的“恢复”部分)。

由于既没有读取错误也没有写入错误,因此md在内核等待设备响应后继续使用该设备。

2. 当驱动器被阻止时,我可以从阵列中删除该驱动器/分区吗?

不可以/dev/md0。RAID 设备已被阻止,并且在该块被清除之前无法进行修改。

您将-f--fail标志传递给mdadm“管理”模式。
以下是其实际作用的演练:

这是该标志如何工作的源代码

case 'f': /* set faulty */
    /* FIXME check current member */
    if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) ||
        (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY,
                rdev))) {
        if (errno == EBUSY)
            busy = 1;
        pr_err("set device faulty failed for %s:  %s\n",
            dv->devname, strerror(errno));
        if (sysfd >= 0)
            close(sysfd);
        goto abort;
    }
    if (sysfd >= 0)
        close(sysfd);
    sysfd = -1;
    count++;
    if (verbose >= 0)
        pr_err("set %s faulty in %s\n",
            dv->devname, devname);
    break;
Run Code Online (Sandbox Code Playgroud)

注意来电write(sysfd, "faulty", 6)sysfd是文件前面设置的变量:
sysfd = sysfs_open(fd2devnm(fd), dname, "block/dev");

sysfs_open()是该文件中的一个函数:

int sysfs_open(char *devnm, char *devname, char *attr)
{
    char fname[50];
    int fd;

    sprintf(fname, "/sys/block/%s/md/", devnm);
    if (devname) {
        strcat(fname, devname);
        strcat(fname, "/");
    }
    strcat(fname, attr);
    fd = open(fname, O_RDWR);
    if (fd < 0 && errno == EACCES)
        fd = open(fname, O_RDONLY);
    return fd;
}
Run Code Online (Sandbox Code Playgroud)

如果您遵循这些函数,您会发现它mdadm /dev/md0 -f /dev/sdb1基本上是这样做的:

echo "faulty" > /sys/block/md0/md/dev-sdb1/block/dev
Run Code Online (Sandbox Code Playgroud)

该请求将等待,并且不会立即通过,因为/dev/md0被阻止。

3. 是否可以配置超时,以便md自动使不响应 ATA 命令的驱动器出现故障?

是的。事实上,默认情况下,超时时间是 30 秒

root@node51 [~]# cat /sys/block/sdb/device/timeout
30
Run Code Online (Sandbox Code Playgroud)

您的假设的问题在于您的驱动器实际上正忙于运行 ATA 命令(持续 188 分钟),因此它没有超时。

有关详细信息,请参阅Linux 内核 SCSI 错误处理文档

4. 为什么md继续使用数据无效的设备?

当 ATA 安全擦除完成时,驱动器没有报告任何问题,例如中止的命令,因此md没有理由怀疑存在问题。

此外,在您使用分区作为 RAID 设备而不是整个磁盘的情况下,内核的内存分区表不会被告知已擦除驱动器上的分区已消失,因此将继续md访问您的分区,/dev/sdb1就像没有任何问题一样。

这是来自md手册页

擦洗和不匹配

由于存储设备随时可能产生坏块,因此定期读取阵列中所有设备上的所有块以便及早捕获此类坏块非常有价值。这个过程称为擦洗

可以通过将检查修复写入设备sysfs目录中的文件md/sync_action来清理 md 数组。

请求清理将导致 md 读取阵列中每个设备上的每个块,并检查数据是否一致。对于 RAID1 和 RAID10,这意味着检查副本是否相同。对于 RAID4、RAID5、RAID6,这意味着检查奇偶校验块(或多个块)是否正确。

我们可以由此推断,奇偶校验通常不会在每次磁盘读取时进行检查。(此外,每次读取时检查奇偶校验都会增加完成读取所需的事务并运行奇偶校验与数据读取的比较,从而对性能造成很大的负担。)

在正常操作下,md只是假设它正在读取的数据是有效的,从而使其容易受到静默数据损坏的影响。就您而言,由于您擦除了驱动器,整个驱动器中的数据都已悄然损坏。

您的文件系统不知道损坏。您在文件系统级别看到输入/输出错误,因为文件系统无法理解为什么它有错误的数据。

为了避免静默数据损坏,首先,不要再做以前做过的事情。其次,考虑使用ZFS,这是一种专注于数据完整性并检测和纠正静默数据损坏的文件系统。