Linux - 使用 GPT 修復 RAID1 陣列上的壞塊
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 找到稍後用於確定塊號的起始扇區(因為我不能使用 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_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
根據其中一個答案:看來我確實切換
seek
了skip
fordd
。我使用的是尋求,因為那是與 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
or/dev/md0
嗎?我不想通過直接寫入一個磁碟而不更新另一個磁碟來導致 RAID 陣列出現任何問題。編輯 3
直接寫入塊會產生文件系統錯誤。我選擇了一個快速解決問題的答案:
# 1 Short offline Completed without error 00% 14211 - # 2 Extended offline Completed: read failure 30% 12244 3212761936
感謝所有幫助過的人。=)
坦率地說,所有這些“戳行業”的答案都是瘋狂的。他們冒著(可能是隱藏的)文件系統損壞的風險。如果數據已經消失,因為該磁碟儲存了唯一的副本,那將是合理的。但是鏡子上有一個非常好的副本。
你只需要讓 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