Linux - 使用 GPT 修复 RAID1 阵列上的坏块

bli*_*ann 22 software-raid badblocks smart

tl; dr:我将如何修复 RAID1 阵列中 1 个磁盘上的坏块?

但是请阅读整篇文章,了解我已经尝试过的内容以及我的方法中可能存在的错误。我已经尝试尽可能详细,我真的希望得到一些反馈

这是我的情况:我在 RAID1 阵列中设置了两个 2TB 磁盘(相同型号)mdadm。大约 6 个月前,当 SMART 报告它时,我注意到了第一个坏块。今天我注意到了更多,现在正在尝试修复它。

这个 HOWTO 页面似乎是每个人都链接到的一篇文章来修复 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
Run Code Online (Sandbox Code Playgroud)

有了这个,我们得出错误存在于 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
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)

所以块 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
Run Code Online (Sandbox Code Playgroud)

如果无法读取该块,我不希望这会起作用。但是,确实如此。我重复使用/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 
Run Code Online (Sandbox Code Playgroud)

我希望写入坏块会使磁盘将该块重新分配给一个好的块,但是运行另一个 SMART 测试显示不同:

# 1  Short offline       Completed: read failure       90%     12170         3212761936
Run Code Online (Sandbox Code Playgroud)

回到第 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
Run Code Online (Sandbox Code Playgroud)

我还使用了具有以下输出的坏块。输出很奇怪,似乎格式错误,但我尝试测试作为块输出的数字,但 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
Run Code Online (Sandbox Code Playgroud)

不知道从这里去哪里。badblocks肯定找到了一些东西,但我不确定如何处理所提供的信息......


编辑 2

更多命令和信息。

我觉得自己像个白痴,忘记了最初的内容。这是 的 SMART 值/dev/sda。我有 1 个 Current_Pending_Sector 和 0 个 Offline_Uncorrectable。

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
Run Code Online (Sandbox Code Playgroud)

根据其中一个答案:看来我确实 switchseekskipfor dd. 我使用的是seek,因为这就是HOWTO 所使用的。使用这个命令会导致dd挂起:#dd if=/dev/sda1 of=/dev/null bs=4096 count=1 skip=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
Run Code Online (Sandbox Code Playgroud)

感谢所有帮助过的人。=)

der*_*ert 26

坦率地说,所有这些“戳行业”的答案都是疯狂的。他们冒着(可能是隐藏的)文件系统损坏的风险。如果数据已经消失了,因为该磁盘存储了唯一的副本,这将是合理的。但是镜子上有一个非常好的副本。

你只需要让 mdraid 擦洗镜子。它会注意到坏扇区,并自动重写它。

# echo 'check' > /sys/block/mdX/md/sync_action    # use 'repair' instead for older kernels
Run Code Online (Sandbox Code Playgroud)

您需要将正确的设备放在那里(例如,md0 而不是 mdX)。这将需要一段时间,因为默认情况下它会执行整个数组。在足够新的内核上,您可以先将扇区号写入 sync_min/sync_max,以将其限制为数组的一部分。

这是一个安全的操作。您可以在所有 mdraid 设备上执行此操作。事实上,您应该定期在所有 mdraid 设备上执行此操作。您的发行版可能附带一个 cronjob 来处理这个问题,也许您需要做一些事情来启用它?


系统上所有 RAID 设备的脚本

不久前,我编写了这个脚本来“修复”系统上的所有 RAID 设备。这是为只有“修复”才能修复坏扇区的旧内核版本编写的;现在只做检查就足够了(修复在较新的内核上仍然可以正常工作,但它也会重新复制/重建奇偶校验,这并不总是你想要的,尤其是在闪存驱动器上)

# echo 'check' > /sys/block/mdX/md/sync_action    # use 'repair' instead for older kernels
Run Code Online (Sandbox Code Playgroud)

如果你想做check而不是repair,那么这个(未经测试的)第一个块应该可以工作:

#!/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
Run Code Online (Sandbox Code Playgroud)


小智 5

我刚刚遇到了与 RAID1 阵列几乎相同的问题。坏扇区就在分区之一的开头 - /dev/sdb2 的扇区 16。我按照上面的说明操作:在验证文件系统未使用逻辑块 2 并小心获取 dd seek 并以正确的方式跳过之后,将 1 个文件系统块清零:

# dd if=/dev/zero of=/dev/md0 bs=4096 count=1 seek=2
Run Code Online (Sandbox Code Playgroud)

这是做什么的?它没有修复坏扇区。我现在知道,这是因为 /dev/md0 没有直接映射到 /dev/sdb2,您必须考虑 RAID DATA OFFSET!更多关于这个下面。它所做的是在我的文件系统上产生了一个小但可能具有破坏性的粪便。事实证明,/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)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,数据偏移量为 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
Run Code Online (Sandbox Code Playgroud)

有效!