TL;DR:我该如何修复 RAID1 阵列中 1 个磁盘上的坏块?
但请阅读整篇文章,了解我已经尝试过的内容以及我的方法中可能出现的错误。我已经尽力尽可能详细,我真的希望得到一些反馈
这是我的情况:我有两个 2TB 磁盘(相同型号)设置在由mdadm
.大约 6 个月前,当 SMART 报告它时,我注意到第一个坏块。今天我注意到了更多,现在正在努力解决它。
本指南页面似乎是每个人都链接到修复 SMART 报告的坏块的一篇文章。这是一个很棒的页面,充满了信息,但是它相当过时,并且不能解决我的特定设置。这是我的配置的不同之处:
- 我在 RAID1 阵列中使用两个磁盘,而不是一个磁盘。一个磁盘报告错误,而另一个则正常。 HOWTO 只考虑了一个磁盘,这会带来各种问题,例如“我在磁盘设备还是 RAID 设备上使用此命令”?
- 我使用的是 GPT,fdisk 不支持。我一直在使用 gdisk,我希望它能给我提供我需要的相同信息
那么,让我们开始吧。这就是我所做的,但它似乎不起作用。请随时仔细检查我的计算和方法是否有错误。报错的磁盘为/dev/sda:
# smartctl -l selftest /dev/sda
smartctl 5.42 2011-10-20 r3458 [x86_64-linux-3.4.4-2-ARCH] (local build)
Copyright (C) 2002-11 by Bruce Allen, http://smartmontools.sourceforge.net
=== START OF READ SMART DATA SECTION ===
SMART Self-test log structure revision number 1
Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error
# 1 Short offline Completed: read failure 90% 12169 3212761936
由此,我们得出错误位于 LBA 3212761936 上。按照 HOWTO,我使用 gdisk 查找起始扇区,以便稍后在确定块号时使用(因为我无法使用 fdisk,因为它不支持 GPT):
# gdisk -l /dev/sda
GPT fdisk (gdisk) version 0.8.5
Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: present
Found valid GPT with protective MBR; using GPT.
Disk /dev/sda: 3907029168 sectors, 1.8 TiB
Logical sector size: 512 bytes
Disk identifier (GUID): CFB87C67-1993-4517-8301-76E16BBEA901
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 3907029134
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)
Number Start (sector) End (sector) Size Code Name
1 2048 3907029134 1.8 TiB FD00 Linux RAID
使用tunefs
我发现块大小为4096
。使用此信息和 HOWTO 中的计算,我得出结论,有问题的块是((3212761936 - 2048) * 512) / 4096 = 401594986
。
然后,HOWTO 指示我debugfs
查看该块是否正在使用(我使用 RAID 设备,因为它需要 EXT 文件系统,这是令我困惑的命令之一,因为我一开始不知道是否应该使用 / dev/sda 或 /dev/md0):
# debugfs
debugfs 1.42.4 (12-June-2012)
debugfs: open /dev/md0
debugfs: testb 401594986
Block 401594986 not in use
所以块 401594986 是空的,我应该能够毫无问题地重写它。不过,在写入之前,我尝试确保它确实无法被读取:
# dd if=/dev/sda1 of=/dev/null bs=4096 count=1 seek=401594986
1+0 records in
1+0 records out
4096 bytes (4.1 kB) copied, 0.000198887 s, 20.6 MB/s
如果无法读取该块,我不希望它起作用。然而,确实如此。我重复使用/dev/sda
、/dev/sda1
、/dev/sdb
、/dev/sdb1
、/dev/md0
和 +-5 到块号来搜索坏块。这一切都有效。我耸耸肩,继续提交写入和同步(我使用 /dev/md0 因为我认为修改一个磁盘而不是另一个可能会导致问题,这样两个磁盘都会覆盖坏块):
# dd if=/dev/zero of=/dev/md0 bs=4096 count=1 seek=401594986
1+0 records in
1+0 records out
4096 bytes (4.1 kB) copied, 0.000142366 s, 28.8 MB/s
# sync
我希望写入坏块会使磁盘将块重新分配给好块,但是运行另一个 SMART 测试会显示不同的结果:
# 1 Short offline Completed: read failure 90% 12170 3212761936
回到方块 1。那么基本上,我如何修复 RAID1 阵列中 1 个磁盘上的坏块?我确信我没有做正确的事情......
感谢您的时间和耐心。
编辑1:
我尝试运行一个长时间的 SMART 测试,相同的 LBA 返回为错误(唯一的区别是它报告剩余 30%,而不是 90%):
SMART Self-test log structure revision number 1
Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error
# 1 Extended offline Completed: read failure 30% 12180 3212761936
# 2 Short offline Completed: read failure 90% 12170 3212761936
我还使用了带有以下输出的坏块。输出很奇怪,似乎格式错误,但我尝试测试作为块输出的数字,但 debugfs 给出错误
# badblocks -sv /dev/sda
Checking blocks 0 to 1953514583
Checking for bad blocks (read-only test): 1606380968ne, 3:57:08 elapsed. (0/0/0 errors)
1606380969ne, 3:57:39 elapsed. (1/0/0 errors)
1606380970ne, 3:58:11 elapsed. (2/0/0 errors)
1606380971ne, 3:58:43 elapsed. (3/0/0 errors)
done
Pass completed, 4 bad blocks found. (4/0/0 errors)
# debugfs
debugfs 1.42.4 (12-June-2012)
debugfs: open /dev/md0
debugfs: testb 1606380968
Illegal block number passed to ext2fs_test_block_bitmap #1606380968 for block bitmap for /dev/md0
Block 1606380968 not in use
不知道从这里去哪里。badblocks
肯定发现了一些东西,但我不确定如何处理所提供的信息......
编辑2
更多命令和信息。
我觉得自己像个白痴,忘记了最初包含这一点。这是 的 SMART 值/dev/sda
。我有 1 个 Current_Pending_Sector 和 0 个 Offline_Un Correctable。
SMART Attributes Data Structure revision number: 16
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
1 Raw_Read_Error_Rate 0x002f 100 100 051 Pre-fail Always - 166
2 Throughput_Performance 0x0026 055 055 000 Old_age Always - 18345
3 Spin_Up_Time 0x0023 084 068 025 Pre-fail Always - 5078
4 Start_Stop_Count 0x0032 100 100 000 Old_age Always - 75
5 Reallocated_Sector_Ct 0x0033 252 252 010 Pre-fail Always - 0
7 Seek_Error_Rate 0x002e 252 252 051 Old_age Always - 0
8 Seek_Time_Performance 0x0024 252 252 015 Old_age Offline - 0
9 Power_On_Hours 0x0032 100 100 000 Old_age Always - 12224
10 Spin_Retry_Count 0x0032 252 252 051 Old_age Always - 0
11 Calibration_Retry_Count 0x0032 252 252 000 Old_age Always - 0
12 Power_Cycle_Count 0x0032 100 100 000 Old_age Always - 75
181 Program_Fail_Cnt_Total 0x0022 100 100 000 Old_age Always - 1646911
191 G-Sense_Error_Rate 0x0022 100 100 000 Old_age Always - 12
192 Power-Off_Retract_Count 0x0022 252 252 000 Old_age Always - 0
194 Temperature_Celsius 0x0002 064 059 000 Old_age Always - 36 (Min/Max 22/41)
195 Hardware_ECC_Recovered 0x003a 100 100 000 Old_age Always - 0
196 Reallocated_Event_Count 0x0032 252 252 000 Old_age Always - 0
197 Current_Pending_Sector 0x0032 100 100 000 Old_age Always - 1
198 Offline_Uncorrectable 0x0030 252 100 000 Old_age Offline - 0
199 UDMA_CRC_Error_Count 0x0036 200 200 000 Old_age Always - 0
200 Multi_Zone_Error_Rate 0x002a 100 100 000 Old_age Always - 30
223 Load_Retry_Count 0x0032 252 252 000 Old_age Always - 0
225 Load_Cycle_Count 0x0032 100 100 000 Old_age Always - 77
# mdadm -D /dev/md0
/dev/md0:
Version : 1.2
Creation Time : Thu May 5 06:30:21 2011
Raid Level : raid1
Array Size : 1953512383 (1863.01 GiB 2000.40 GB)
Used Dev Size : 1953512383 (1863.01 GiB 2000.40 GB)
Raid Devices : 2
Total Devices : 2
Persistence : Superblock is persistent
Update Time : Tue Jul 3 22:15:51 2012
State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0
Name : server:0 (local to host server)
UUID : e7ebaefd:e05c9d6e:3b558391:9b131afb
Events : 67889
Number Major Minor RaidDevice State
2 8 1 0 active sync /dev/sda1
1 8 17 1 active sync /dev/sdb1
根据答案之一:看来我确实切换了seek
和skip
for dd
。我使用的是 find ,因为这就是 HOWTO 所使用的。使用此命令会导致dd
挂起: # dd if=/dev/sda1 of=/dev/null bs=4096 count=1skip=401594986
使用该块(..84、..85、..87、..88)周围的块似乎工作得很好,并且使用 /dev/sdb1 和块401594986
读取也很好(正如预期的那样,该磁盘通过了 SMART 测试) )。现在,我的问题是:当在该区域上写入以重新分配块时,我是否使用/dev/sda1
或/dev/md0
?我不想直接写入一个磁盘而不更新另一个磁盘,从而导致 RAID 阵列出现任何问题。
编辑3
写入块会直接产生文件系统错误。我选择了一个可以快速解决问题的答案:
# 1 Short offline Completed without error 00% 14211 -
# 2 Extended offline Completed: read failure 30% 12244 3212761936
感谢所有提供帮助的人。 =)
答案1
坦率地说,所有这些“刺激行业”的答案都是疯狂的。他们面临(可能是隐藏的)文件系统损坏的风险。如果数据已经消失了,因为该磁盘存储了唯一的副本,这是合理的。但镜子上有一个完美的副本。
您只需要让 mdraid 擦洗镜子即可。它会注意到坏扇区,并自动重写它。
# echo 'check' > /sys/block/mdX/md/sync_action # use 'repair' instead for older kernels
您需要在其中放置正确的设备(例如,md0 而不是 mdX)。这将需要一段时间,因为默认情况下它会处理整个数组。在足够新的内核上,您可以首先将扇区号写入sync_min/sync_max,以将其限制为仅数组的一部分。
这是一个安全的操作。您可以在所有 mdraid 设备上执行此操作。事实上,你应该定期在所有 mdraid 设备上执行此操作。您的发行版可能附带一个 cronjob 来处理这个问题,也许您需要做一些事情来启用它?
适用于系统上所有 RAID 设备的脚本
不久前,我编写了这个脚本来“修复”系统上的所有 RAID 设备。这是为较旧的内核版本编写的,其中只有“修复”才能修复坏扇区;现在只需进行检查就足够了(修复在较新的内核上仍然可以正常工作,但它也会重新复制/重建奇偶校验,这并不总是您想要的,尤其是在闪存驱动器上)
#!/bin/bash
save="$(tput sc)";
clear="$(tput rc)$(tput el)";
for sync in /sys/block/md*/md/sync_action; do
md="$(echo "$sync" | cut -d/ -f4)"
cmpl="/sys/block/$md/md/sync_completed"
# check current state and get it repairing.
read current < "$sync"
case "$current" in
idle)
echo 'repair' > "$sync"
true
;;
repair)
echo "WARNING: $md already repairing"
;;
check)
echo "WARNING: $md checking, aborting check and starting repair"
echo 'idle' > "$sync"
echo 'repair' > "$sync"
;;
*)
echo "ERROR: $md in unknown state $current. ABORT."
exit 1
;;
esac
echo -n "Repair $md...$save" >&2
read current < "$sync"
while [ "$current" != "idle" ]; do
read stat < "$cmpl"
echo -n "$clear $stat" >&2
sleep 1
read current < "$sync"
done
echo "$clear done." >&2;
done
for dev in /dev/sd?; do
echo "Starting offline data collection for $dev."
smartctl -t offline "$dev"
done
如果你想代替check
,repair
那么这个(未经测试的)第一个块应该可以工作:
case "$current" in
idle)
echo 'check' > "$sync"
true
;;
repair|check)
echo "NOTE: $md $current already in progress."
;;
*)
echo "ERROR: $md in unknown state $current. ABORT."
exit 1
;;
esac
答案2
我刚刚在 RAID1 阵列上遇到了几乎相同的问题。坏扇区位于其中一个分区的开头 - /dev/sdb2 的第 16 扇区。我按照上面的说明进行操作:在验证文件系统未使用逻辑块 2 并小心地以正确的方式进行 dd 查找和跳过之后,并将 1 个文件系统块归零:
# dd if=/dev/zero of=/dev/md0 bs=4096 count=1 seek=2
这是做什么的?它没有修复坏扇区。我现在知道,这是因为 /dev/md0 没有直接映射到 /dev/sdb2,您必须考虑 RAID 数据偏移!下面详细介绍这一点。它所做的只是我的文件系统上的一个小但可能具有毁灭性的粪便。事实证明 /dev/md0 的逻辑块 2 包含有用的文件系统元数据,并且在两个磁盘上都很好,直到我拉屎了两个都通过写入 /dev/md0 进行复制。幸运的是, e2fsck -y /dev/md0 解决了这个问题(在发出大量惊人的输出之后),没有明显的数据丢失。经验教训:如果 debugfs icheck 显示“未找到块”,并不一定意味着相应的扇区未被使用。
回到数据偏移量:使用 mdadm 查找偏移量,如下所示:
# mdadm --examine /dev/sdb2
/dev/sdb2:
Magic : a92b4efc
Version : 1.2
Feature Map : 0x0
Array UUID : ef7934b9:24696df9:b89ff03e:b4e5a05b
Name : XXXXXXXX
Creation Time : Sat Sep 1 01:20:22 2012
Raid Level : raid1
Raid Devices : 2
Avail Dev Size : 1953241856 (931.38 GiB 1000.06 GB)
Array Size : 976620736 (931.38 GiB 1000.06 GB)
Used Dev Size : 1953241472 (931.38 GiB 1000.06 GB)
Data Offset : 262144 sectors
Super Offset : 8 sectors
State : clean
Device UUID : f3b5d515:446d4225:c2191fa0:9a9847b8
Update Time : Thu Sep 6 12:11:24 2012
Checksum : abb47d8b - correct
Events : 54
Device Role : Active device 0
Array State : AA ('A' == active, '.' == missing)
在本例中,数据偏移量为 262144 个扇区,每扇区 512 字节。如果您从 /dev/md0 进行 dd 并将其与偏移量为 131072K 的原始分区中的数据进行比较,您会发现它们匹配。因此,就我而言,/dev/sdb2 的逻辑块 2(扇区 16--23)甚至不在文件系统中;它们位于 RAID 超级块中,您可以在此处阅读: https://raid.wiki.kernel.org/index.php/RAID_superblock_formats- 对于版本 1.2,它由 256 字节 + 阵列中每个设备 2 字节组成,全部从 4096 字节开始,所以在我的例子中,没有使用坏扇区。 /dev/sdc2(RAID1 阵列的另一半)的相应扇区为零,因此我认为这样做是安全的:
# dd if=/dev/zero of=/dev/sdb2 bs=4096 count=1 seek=2
有效!
答案3
如果运行 debian,您很可能在 /etc/cron.d/mdadm 中有一份工作。这将/usr/share/mdadm/checkarray --cron --all --idle --quiet
在每个月的第一个星期日运行。当出现无法纠正的硬件错误时,手动运行该错误以加快重写速度。
答案4
如果您有 sw-raid1 并且直接将数据写入其中一个成员,您将立即获得损坏的 raid。如果 sdaX 或 sdbX 是 mdX 的一部分,请勿将数据写入其中。如果您写入 mdX,您会将数据复制到两个驱动器,如果您从 mdX 读取,您将从其中一个驱动器读取数据。