LinuxのHDDの自己診断がエラーの場合に壊れたファイルを特定する

ALL
スポンサーリンク

LinuxのHDDの自己診断でエラーの場合に壊れたファイルを特定する手順の説明です。
今回の実例では、HDDのSMART情報を確認した際に、Current_Pending_Sector の値が1になっていて、不良セクタが存在していました。
そこでHDDの自己診断を行うとエラーが見つかり、壊れたファイルを特定しました。

スポンサーリンク

ディスクのSMART情報確認と自己診断

まず、Linux での HDDのSMART情報の確認方法です。
次の記事の「SMART情報表示」までの手順でディスクのSMART情報を確認します。

Linuxでの HDDの S.M.A.R.T.情報の取得と、HDD自己診断の実施方法
・物理HDDの確認
・HDDが SMART対応か確認
・SMART情報表示

以下の説明では、HDDのデバイス名は /dev/sda とします。

SMART情報を確認してみると、Current_Pending_Sector の値が1になっていました。

# smartctl /dev/sda -A
=== START OF READ SMART DATA SECTION ===
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   200   200   051    Pre-fail  Always       -       139
  3 Spin_Up_Time            0x0027   139   138   021    Pre-fail  Always       -       4041
  4 Start_Stop_Count        0x0032   100   100   000    Old_age   Always       -       57
  5 Reallocated_Sector_Ct   0x0033   200   200   140    Pre-fail  Always       -       0
  7 Seek_Error_Rate         0x002e   200   200   000    Old_age   Always       -       0
  9 Power_On_Hours          0x0032   086   086   000    Old_age   Always       -       10588
 10 Spin_Retry_Count        0x0032   100   253   000    Old_age   Always       -       0
 11 Calibration_Retry_Count 0x0032   100   253   000    Old_age   Always       -       0
 12 Power_Cycle_Count       0x0032   100   100   000    Old_age   Always       -       55
192 Power-Off_Retract_Count 0x0032   200   200   000    Old_age   Always       -       30
193 Load_Cycle_Count        0x0032   200   200   000    Old_age   Always       -       26
194 Temperature_Celsius     0x0022   107   099   000    Old_age   Always       -       36
196 Reallocated_Event_Count 0x0032   200   200   000    Old_age   Always       -       0
197 Current_Pending_Sector  0x0032   200   200   000    Old_age   Always       -       1
198 Offline_Uncorrectable   0x0030   100   253   000    Old_age   Offline      -       0
199 UDMA_CRC_Error_Count    0x0032   200   200   000    Old_age   Always       -       0
200 Multi_Zone_Error_Rate   0x0008   100   253   000    Old_age   Offline      -       0

HDDの自己診断(short)を実行してみます。
自己診断について詳しくは、Linuxでの HDDの S.M.A.R.T.情報の取得と、HDD自己診断の実施方法 の「HDDの自己診断」を参照して下さい。

次のコマンドで自己診断(short)を実行します。

# smartctl -t short /dev/sda
=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===
Sending command: "Execute SMART Short self-test routine immediately in off-line mode".
Drive command "Execute SMART Short self-test routine immediately in off-line mode" successful.
Testing has begun.
Please wait 2 minutes for test to complete.
Test will complete after Sat Sep 17 12:40:10 2016
Use smartctl -X to abort test.

しばらくして、自己診断の結果を確認します。

# smartctl -l selftest /dev/sda
=== 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       <strong>Completed: read failure</strong>       90%     10590         267381314

Status が ‘Completed: read failure’ でエラーになっていました!!
LBA_of_first_error 列はエラーが起こった箇所を示します。
(正しくは、最初に読み込みエラーが起こったセクタ番号です)

今回の例では、LBA_of_first_error は 267381314 です。

さて、エラーによってディスクのどの inode が壊れているかどうかは、以降の手順で確認します。
更に以降の手順で、inode から壊れたファイル名を特定します。

エラー箇所(inode)の特定作業

LBA_of_first_error が示す箇所は、どの inode なのかを、以下の作業で特定します。

今回の例では、LBA_of_first_error は 267381314 で、これはエラーが起こったセクタ番号を示します。
このセクタがどのパーティション上にあるかを確認します。

まず、fdisk を下記のように実行します。

# fdisk -lu /dev/sda
Disk /dev/sda: 500.0 GB, 500000514048 bytes
255 heads, 63 sectors/track, 60788 cylinders, total 976563504 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0000f3ff
   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048   973062143   486530048   83  Linux
/dev/sda2       973064190   976562175     1748993    5  Extended
/dev/sda5       973064192   976562175     1748992   82  Linux swap / Solaris

Start、End 列は各パーティションの開始セクタ、終了セクタです。
/dev/sda1 はセクタ 2048~973062143 で、LBA_of_first_error の 267381314 はこの範囲内です。
従って、エラーが起こったパーティションは /dev/sda1 だということが分かります。
このパーティションの開始セクタ(今回の例では 2048)をメモしておきます。
後ほど、この値を使用します。

ここで、該当パーティションの System 列が「Linux LVM」と表示された場合は、作業方法が異なります。
以下のサイトに詳しい手順が説明されていますので、そちらを参照して下さい。

ぱぱらくだ日記: Linux LVMでのCurrent_Pending_Sectorの対処方法

ここでは、System列が「Linux」の場合の手順になります。

エラーが起こったセクタ(LBA_of_first_error)が、ファイルシステム上のどのブロック番号かを調べます。

該当パーティション(この例では /dev/sda1)のブロックサイズを調べます。

# tune2fs -l /dev/sda1 | grep 'Block size:'
Block size:               4096

ブロックサイズは 4096 でした。

ブロック番号を次の式で計算します。
計算結果の小数点以下は切り捨てます。

ブロック番号=(L-S)*512/B
L:LBA_of_first_error の値(今回の例では 267381314 )
S:エラーが起こったパーティションの開始セクタ番号(今回の例では 2048)
B:ブロックサイズ(今回の例では 4096 )

ブロック番号は、(267381314-2048)*512/4096 = 33422408.25 となり、小数点以下切り捨てして 33422408 になります。

次に、ブロック番号から inode情報を調べます。

debugfs コマンドを実行します。実行後、「debugfs:」と出て入力待ちになります。

# debugfs
debugfs 1.41.12 (17-May-2010)
debugfs:

「open /dev/sda1」と入力します。

しばらく経つと、再度 debugfs: と表示されて入力待ちになります。

「icheck ブロック番号」と入力します。
今回の例では、「icheck 33422408」と入力します。

しばらく待つと、該当ブロック上の inode番号が表示されます。

Block   Inode number
33422408        <block not found>

この例では と表示されています。
該当箇所は未使用です。幸運にもファイルは配置されていません。
debugfs: で quit と入力して debugfs を終了し、早急に必要なファイルをバックアップしましょう。

“Inode number” で数値が表示されたら、それは inode番号です。
該当箇所にファイルが配置されており、残念ながら、そのファイルは壊れています。

Block   Inode number
33422408        8241259

以降の手順では、どのファイルが壊れているかを特定します。

壊れたファイルを特定する

debugfs コマンドの続きです。

debugfs: と表示されて入力待ちになっている状態で、「ncheck inode番号」と入力します。
今回の例では、「icheck 8241259」と入力します。

しばらくすると、結果が出ます。

Inode   Pathname
8241259 /var/lib/mysql/ibdata1

指定したinodeに対応するファイルが表示されます。
この例では、/var/lib/mysql/ibdata1 です。

これ、MySQL のデータベースファイルでした!!!!ショックです。

debugfs: で quit と入力して、debugfsの終了です。

さて、壊れていたファイルですが、復旧はあきらめなくてはなりません。

コピーでバックアップも出来ません。次のようにエラーになります。

# cp -a /var/lib/mysql/ibdata1 /tmp/ibdata1
cp: reading `/var/lib/mysql/ibdata1': 入力/出力エラーです

MySQL のデータベースファイルなので、mysqldump でバックアップとろうとしても、これも失敗します。

mysqldump: Error 2013: Lost connection to MySQL server during query when dumping table `data` at row: 16278730

今回の例では、この後、HDDは壊れて起動できなくなりました。
皆さんも同様の状態になったら、早急にその他必要なファイルをバックアップしましょう。

参考

大徳日記 » 不良セクタの直し方
Digital SeeTake: HDDの異常を検知する「SMART」と不良セクタの修復
Bad block HOWTO for smartmontools (現在存在しないので、 InternetArchives上のリンクを記載しています)
ぱぱらくだ日記: Linux LVMでのCurrent_Pending_Sectorの対処方法

コメント