我曾创造五个 1TB HDD 分区(/dev/sda1
,,,,和)在/dev/sdb1
/dev/sdc1
/dev/sde1
/dev/sdf1
RAID 6在 Ubuntu 14.04 LTS Trusty Tahr 上/dev/md0
使用数组调用。mdadm
命令 sudomdadm --detail /dev/md0
用于显示所有驱动器主动同步。
然后,为了进行测试,我通过在阵列中仍然处于活动状态/dev/sdb
时运行以下命令来模拟长 I/O 阻塞:/dev/sdb1
hdparm --user-master u --security-set-pass deltik /dev/sdb
hdparm --user-master u --security-erase-enhanced deltik /dev/sdb
警告
请勿对您关心的数据进行此尝试!
由于这次 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>
我尝试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]
更新(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
对于我来说,这还是相当震惊的,因为md
我预期的两道防线并没有出现:
- 设备锁定时发生故障
- 当设备返回的数据为垃圾时,设备会失败
问题
md
为什么无响应的驱动器/分区不会失败?- 当驱动器被阻止时,我可以从阵列中删除驱动器/分区吗?
- 是否可以配置超时以便
md
自动使不响应 ATA 命令的驱动器失效? - 为什么要
md
继续使用具有无效数据的设备?
答案1
德尔蒂克,您误解了 Linux 软件 RAID(md
)的工作原理。
md
由多个设备或分区构成虚拟块设备,并且不知道您正在向虚拟设备传输什么数据。
您希望它能够完成它没有被设计做的事情。
答案
md
1. 为什么无响应的驱动器/分区不会失败?
这是因为md
不知道
- 驱动器正忙于处理其
md
自身请求的 I/O 或 - 由于某些外部情况(如驱动器自身的错误恢复或 ATA 安全擦除),驱动器被阻止,
因此md
将等待驱动器返回什么。驱动器最终没有返回任何读取或写入错误。如果存在读取错误,md
则会自动从奇偶校验中修复它,如果存在写入错误,md
则会导致设备故障(请参阅md
手册页)。
由于没有读取错误也没有写入错误,因此md
内核等待其响应后继续使用该设备。
2. 当驱动器被阻止时,我可以从阵列中删除驱动器/分区吗?
不可以。RAID/dev/md0
设备已被阻止,除非清除阻止,否则无法修改。
您已将-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;
请注意,调用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;
}
如果你跟踪这些功能,你会发现它mdadm /dev/md0 -f /dev/sdb1
本质上是这样做的:
echo "faulty" > /sys/block/md0/md/dev-sdb1/block/dev
/dev/md0
由于被阻止,该请求将处于等待状态并且不会立即通过。
3. 是否可以配置超时以便md
自动使不响应 ATA 命令的驱动器失效?
是的。事实上,默认情况下,超时时间为 30 秒:
root@node51 [~]# cat /sys/block/sdb/device/timeout
30
您的假设存在问题,因为您的驱动器实际上正忙于运行 ATA 命令(持续 188 分钟),因此并没有超时。
有关详情,请参阅Linux 内核 SCSI 错误处理文档。
4. 为什么要md
继续使用含有无效数据的设备?
当 ATA 安全擦除完成时,驱动器未报告任何问题,例如中止命令,因此md
没有理由怀疑存在问题。
此外,在您使用分区作为 RAID 设备而不是整个磁盘的情况下,内核的内存分区表并未被告知擦除驱动器上的分区已消失,因此md
会继续访问,/dev/sdb1
就像没有任何问题一样。
这是来自md
手册页:
清理和不匹配
由于存储设备随时可能出现坏块,因此定期读取阵列中所有设备上的所有块以尽早捕获此类坏块非常有价值。此过程称为擦洗。
可以通过以下方式擦除 md 数组:查看或者维修到文件md/sync_action在里面系统文件系统设备的目录。
请求清除将导致 md 读取阵列中每个设备的每个块,并检查数据是否一致。对于 RAID1 和 RAID10,这意味着检查副本是否相同。对于 RAID4、RAID5、RAID6,这意味着检查奇偶校验块(或多个块)是否正确。
由此我们可以推断,通常不会在每次磁盘读取时检查奇偶校验。(此外,每次读取时都检查奇偶校验会增加完成读取所需的事务量,并运行奇偶校验与数据读取的比较,这将严重影响性能。)
在正常运行下,md
只是假设它读取的数据是有效的,因此很容易受到静默数据损坏。就你的情况而言,由于你擦除了驱动器,所以整个驱动器上的数据都被悄无声息地损坏了。
您的文件系统没有意识到损坏。您在文件系统级别看到输入/输出错误,因为文件系统无法理解为什么它有坏数据。
为了避免静默数据损坏,首先,永远不要再做你做过的事.其次,考虑使用虚拟文件系统,一种专注于数据完整性并检测和纠正静默数据损坏的文件系统。