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


20

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

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

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

该HOWTO页似乎是每个人都可以链接以解决SMART报告的坏块的文章。这是一个很棒的页面,充满了信息,但是它已经过时了,无法解决我的特定设置。这是我的配置不同之处:

  • 我在RAID1阵列中使用了两个磁盘,而不是一个磁盘。一个磁盘报告错误,而另一个磁盘正常。HOWTO的编写只考虑了一个磁盘,这会引发各种问题,例如“我是否在磁盘设备或RAID设备上使用此命令”?
  • 我正在使用fdisk不支持的GPT。我一直在使用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查找了以后要用来确定块号的起始扇区(由于它不支持GPT,因此我无法使用fdisk):

# 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

我也将badblocks与以下输出配合使用。输出很奇怪,似乎格式错误,但是我尝试测试输出为块的数字,但是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_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

根据答案之一:看来我确实做了切换seekskipfor dd。我正在使用搜索,因为那是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

感谢所有提供帮助的人。=)


您能够读取该块,因此它没有损坏。因此,没有重新分配的扇区。我检查了您的fs块计算,似乎合法。当我进行坏块重新分配时,我发现有时智能短路测试不能正确报告有问题的块。同时,您可以运行长时间的脱机测试,smartctl -t long /dev/sda并查看第一个错误的LBA是否更改。
加里·拉曼宁

1
尝试/sbin/badblocks -sv /dev/sda检查磁盘。
jippie 2012年

我已经完成了两个建议,并相应地更新了帖子。仍然卡住。= /
blitzmann

smartctl是否报告Current_Pending_Sector计数为非零?Offline_Uncorrectable是否非零?
mgorven 2012年

请在问题中添加阵列状态:sudo mdadm -D /dev/md0
psusi 2012年

Answers:


20

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

您只需要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

这次真是万分感谢。我最近回到这个问题,希望最终解决它。我确实写入了/ dev / md0块,并且确实遇到了文件系统问题,但值得庆幸的是,经过数小时的恐怖并启动到恢复外壳后,所有修复都没有造成数据丢失。我将首先尝试您的方法,希望这将使我摆脱未决的领域。=)
blitzmann 2012年

您如何得知擦洗完成的时间?完成后会显示cat /sys/block/mdX/md/sync_action“ idle”吗?
乔恩·克拉姆2014年

@JonCram是的,你可以通过观看状态cat /proc/mdstat或者如果你想脚本吧,/sys/…/sync_completed
derobert

5

我刚刚在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 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)

在这种情况下,数据偏移为512字节的262144个扇区。如果您从/ 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

有效!


在这里操作。谢谢你提供信息。当我遇到这个问题时,我大步向前,将/ dev / md0级别的代码块清零。这是一个坏主意,因为我碰巧也把文件系统弄糟了。值得庆幸的是,经过大量的时间修复之后,一切似乎都很好,没有数据丢失。但是由于最初的恐慌,我完全忘了这篇文章。我最近在新公寓里设置了服务器,这又是我的待办事项清单之一,感谢您对问题的理解。当我深入研究这一点时,我将更新OP。=)
blitzmann 2012年

2

如果运行debian,则很可能在/etc/cron.d/mdadm中找到工作。这将在/usr/share/mdadm/checkarray --cron --all --idle --quiet 每个月的第一个星期日运行。遇到不可纠正的硬件错误时,请手动运行该命令以加快重写速度。


好吧,当手动运行它时,您可能要退出--cron
derobert

1

你弄混了你的dd论点。 seek使它寻求输出中的指定偏移。您想skip阻止输入


谢谢!我已经更新了原始帖子,以包含来自此的数据。如果您能告诉我如何从此处修复该块,我想我会给您答案。(我不确定是否应该直接写入/dev/sda1/或用于/dev/md0覆盖块)=)
blitzmann 2012年

@ryan,写md0应该是方法,尽管sda1也应该起作用。
psusi 2012年

0

如果您拥有sw-raid1,并且直接将数据写入其中一个成员,则您的RAID将立即遭到破坏。如果它们是mdX的一部分,请勿将数据写入sdaX或sdbX。如果写入mdX,则将数据复制到两个驱动器,如果从mdX读取,则将从其中一个驱动器读取数据。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.