[Linux]ハードディスクが壊れる予兆を知る

S.M.A.R.T.の情報からハードディスクの健康状態を確認できますが、時にはS.M.A.R.T.の状態がgoodであってもエラーがあって突然壊れてしまう場合もあります。
これまでの経験から、ハードディスクが壊れる前に起こりうる状況についてまとめました。

なお、当方、ハードディスク並びにUSBメモリでの故障しか経験していないため、SSDでは当てはまらないケースがあるかもしれません

また、この記事で取り上げたメッセージはファイルシステム、Linuxカーネルのバージョンやディストリビューションの違いによって差異があるかもしれません。大まかな意味は変わらないと思いますので、メッセージ内容は参考程度に留めてください

# ディスクが壊れたと疑う前のチェック

まず最初に、ハードディスク自体の故障を疑う前にディスクの設置環境を確認してみましょう。ハードディスクは正常であっても次のようなことがあれば故障と同じ症状が現れることがあります

* ハードディスクとマザーボードのコネクタの接触が悪くなっていませんか？
  * 別のケーブルに交換したり、ポートを変えてみて挙動が変化が無いか確認してみてください
  * 偶にですが、ハードディスクではなくマザーボード側の不良でディスクエラー状態になることもあります。別のPCに載せ替えするか、USBのハードディスクケースに移すのも良いでしょう
* 電源が弱っていませんか？
  * 電源ユニットは長時間使っていると部品の劣化により電圧が不安定になったり、本来の電圧を出せなくなってきます
  * テスターがあれば電圧をチェックできますが、無ければ電源ユニットを交換したり、別の系統の電源に変えてみてください
  * USBのハードディスクケースであればそれに繋ぐACアダプターを変えてみてください
* 埃が溜まっていませんか？
  * 埃が静電気を帯びることがあるため電気的なノイズ源になりえます。ノイズによってデータが化けてエラーになる可能性もありますので、溜まっていたら掃除しましょう
  * 端子部分が汚れていたらアルコールで洗浄するのも良いでしょう
* 互換性の問題
  * USB3.1のハードディスクケースだと、問題ないPCもあればエラーが出るPCもありました。速度が遅くなりますがUSB2.0のUSBハブを経由すれば改善しました
  * 逆にUSB2.0のハードディスクケースをUSB3.1のポートに繋いでエラーになることもありました (私のPCが良くない物なのかもしれませんが可能性の一つとして考えてください)
  * 対応容量を超えたハードディスクを載せた場合 (例えば2TBまでしか対応していないマザーボードで4TBのハードディスクを接続するなど) フォーマット時は問題なくても、データを書き込んでいく内に正しく読み書き出来なくなってエラーになることもあり得ます
  * 販売時期が異なるハードディスクとマザーボード、ハードディスクケースの組み合わせは相性問題でエラーを引き起こすことがあるかもしれません。BIOSの更新やハードディスクのファームウェアの更新があればアップデートしてみると良いでしょう

載せ替えする時や、点検の時などはハードディスクに衝撃を与えたり落下したりしないように注意してください

以上を踏まえて、設置環境に問題ないと判断してからハードディスクの故障チェックをするのが良いでしょう

# 入力/出力エラー(I/O error)が発生する

読込みや書込み処理中でエラーが発生するとカーネルメッセージに `入力/出力エラー` が残ります。以下のようなメッセージが残っていればエラーが発生している状態です

カーネルメッセージの確認には `dmesg` コマンドを使います。 `-T` オプションを付けることで発生日時が出力されます

```shell-session
$ dmesg -T
...(省略)...
[月  1月 13 04:05:52 2020] print_req_error: I/O error, dev sdb, sector 181900984
[月  1月 13 04:05:52 2020] EXT4-fs warning: 15 callbacks suppressed
[月  1月 13 04:05:52 2020] EXT4-fs warning (device sdb2): ext4_end_bio:323: I/O error 10 writing to inode 78372887 (offset 0 size 0 starting block 22737624)
[月  1月 13 04:05:52 2020] buffer_io_error: 79 callbacks suppressed
[月  1月 13 04:05:52 2020] Buffer I/O error on device sdb2, logical block 21424063
...(省略)...
```

こういったエラーは連続して発生するため、大量に出てログが溢れてしまうことも少なくありません

コピー中にエラーが発生して気が付くこともあります

```shell-session
$ cp error-file.bin /tmp
cp: `error-file.bin' の読み込みエラー: 入力/出力エラーです
```

環境変数のLANGが指定されていないか、LANG=Cの場合は英語で「Input/output error」または「I/O error」と出ます

```shell-session
$ cp error-file.bin /tmp
cp: error reading 'error-file.bin': Input/output error
```

入力/出力エラーはディスクの不良になった場所にアクセスした時に発生します。部分的なエラーだと普段は気が付きにくいので、ddコマンドでディスク全体を読み込みさせてみると確実にエラーの有無を把握できます

問題がなければ最後まで読み込みできますが、エラーがあれば以下のように中断します

```shell-session
# dd if=/dev/sdd of=/dev/null bs=1024K
dd: `/dev/sdd' の読み込みエラー: 入力/出力エラーです
27+3 レコード入力
27+3 レコード出力
28594176 バイト (29 MB) コピーされました、 6.44647 秒、 4.4 MB/秒
```

ディスク容量次第で時間がかかりますので、余裕がある時に行うのが良いでしょう

# カーネルメッセージにcritical medium errorが出る

ハードディスクのセクターにエラーが検出されると"critical medium error"のメッセージが出力されます

```shell-session
$ dmesg
...(省略)...
[ 2909.160643] sd 4:0:0:0: [sdc] UNKNOWN(0x2003) Result: hostbyte=0x00 driverbyte=0x08
[ 2909.160659] sd 4:0:0:0: [sdc] Sense Key : 0x3 [current]
[ 2909.160664] sd 4:0:0:0: [sdc] ASC=0x11 ASCQ=0x0
[ 2909.160670] sd 4:0:0:0: [sdc] CDB: opcode=0x28 28 00 38 a3 0c 20 00 00 20 00
[ 2909.160675] blk_update_request: critical medium error, dev sdc, sector 950209568
```

この状態では、確実にエラーが発生しています。データが読めるうちにバックアップを取っておきましょう

# readdirでエラーが発生する

カーネルメッセージに readdir のエラーが大量にある場合は、どこかのディレクトリが壊れている状態です

```
$ dmesg
...(省略)...
[253651.861356] EXT2-fs (sdc1): error: ext2_check_page: bad entry in directory #7939: : directory entry across blocks - offset=84692, inode=42003, rec_len=5668, name_len=28
[253651.877830] EXT2-fs (sdc1): error: ext2_readdir: bad page in #7939
[253789.279076] EXT2-fs (sdc1): error: ext2_readdir: bad page in #7939
[340177.935191] EXT2-fs (sdc1): error: ext2_check_page: bad entry in directory #7939: : directory entry across blocks - offset=84692, inode=42003, rec_len=5668, name_len=28
[340177.951443] EXT2-fs (sdc1): error: ext2_readdir: bad page in #7939
```

以下のコマンドでシステム全体のディレクトリ階層を開いていけば、途中でエラーになって壊れているディレクトリが特定出来るかもしれません

```shell-session
# ls -lR / > /dev/null
```

## ファイルシステムの破損との切り分け

上記のメッセージは ext2 形式のパーティションで発生していますが、ext2 はジャーナリング機構を持たないために、書き込み途中の電源断でも簡単にファイルシステムが壊れてエラーが発生します。ディスクが壊れているのであれば、前述の入力/出力エラー(I/O error)も同時に発生してる可能性が高いのでそちらで切り分けするのでも良いでしょう

電源断もしてないし、フォーマットしてもすぐに再発する場合はソフト的なトラブルもあるかもしれませんが、ハード的な故障の可能性も否定できないと思います

fsckを実行してファイルシステムのエラーを修復してみるのも良いかもしれませんが、この状態でファイルシステムに手を加えるのは、本当にディスクが壊れた状態だと破損箇所が大きくなったり、トドメを挿してアクセスできなくなってしまうかもしれませんので、実行する前に残しておきたいファイルをバックアップするのが良いでしょう

readdirのエラーが大量に出ている時にfsckを実行すると、保存されていた場所(ディレクトリ)を見失ったファイル群が大量に lost+found のディレクトリに移動されます。これらの整理は非常に手間ですので、fsckは実行しないで必要なファイルだけ抜き出して、フォーマットし直すのが良いと思います (個人的な経験則です)

### 参考: SDカード(FATファイルシステム)の破損の場合

先日、SDカードの調子が悪くなったのでその時に表示されたエラーメッセージを載せます。「read failed」が「I/O error」に相当し、「Directory bread failed」が「readdir: bad page」のエラーに相当しているようです。このように、使用しているファイルシステムやカーネルなどによってメッセージが若干変わる可能性がありますので、特定ワードのチェックだけでなく、普段からカーネルメッセージを観測していた方がいいでしょう

```shell-session
[4017890.833938] FAT-fs (sdg1): FAT read failed (blocknr 2604)
[4017890.842727] FAT-fs (sdg1): FAT read failed (blocknr 2604)
[4017890.851543] FAT-fs (sdg1): FAT read failed (blocknr 2604)
[4017890.856724] FAT-fs (sdg1): unable to read inode block for updating (i_pos 303130633)
[4017890.856931] FAT-fs (sdg1): unable to read inode block for updating (i_pos 303130634)
[4017890.860642] FAT-fs (sdg1): FAT read failed (blocknr 2604)
[4017890.869436] FAT-fs (sdg1): FAT read failed (blocknr 2604)
[4017890.871586] fat__get_entry: 75040 callbacks suppressed
[4017890.871595] FAT-fs (sdg1): Directory bread(block 17975184) failed
[4017890.871667] FAT-fs (sdg1): Directory bread(block 17975185) failed
[4017890.871735] FAT-fs (sdg1): Directory bread(block 17975186) failed
[4017890.871804] FAT-fs (sdg1): Directory bread(block 17975187) failed
```

# DMAコマンドでretryやtimeoutが出る

dmesgで以下のメッセージが出ていた場合、このメッセージも壊れる予兆ということなので気を付けておきましょう。今は問題なく動いているようでも、入力/出力エラーが出る、壊れる前の段階かもしれません

```shell-session
$ dmesg
...(省略)...
[  535.203520] ata3.00: exception Emask 0x0 SAct 0x1e SErr 0x0 action 0x6 frozen
[  535.203820] ata3.00: failed command: READ FPDMA QUEUED
[  535.204076] ata3.00: cmd 60/10:08:80:df:9b/00:00:00:00:00/40 tag 1 ncq 8192 in
         res 40/00:00:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout)
[  535.204257] ata3.00: status: { DRDY }
[  535.204478] ata3.00: failed command: READ FPDMA QUEUED
[  535.204772] ata3.00: cmd 60/08:10:98:df:9b/00:00:00:00:00/40 tag 2 ncq 4096 in
         res 40/00:01:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout)
[  535.205244] ata3.00: status: { DRDY }
[  535.205459] ata3.00: failed command: READ FPDMA QUEUED
[  535.205748] ata3.00: cmd 60/10:18:b0:df:9b/00:00:00:00:00/40 tag 3 ncq 8192 in
         res 40/00:00:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout)
[  535.206245] ata3.00: status: { DRDY }
[  535.206466] ata3.00: failed command: READ FPDMA QUEUED
[  535.207342] ata3.00: cmd 60/08:20:c8:df:9b/00:00:00:00:00/40 tag 4 ncq 4096 in
         res 40/00:00:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout)
[  535.210545] ata3.00: status: { DRDY }
[  535.211501] ata3: hard resetting link
[  535.523094] ata3: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[  535.523573] ata3.00: configured for UDMA/133
[  535.523579] ata3.00: device reported invalid CHS sector 0
[  535.523581] ata3.00: device reported invalid CHS sector 0
[  535.523583] ata3.00: device reported invalid CHS sector 0
[  535.523586] ata3.00: device reported invalid CHS sector 0
[  535.523596] ata3: EH complete
```

`failed` とか `hard resetting link` とか出ているように、エラーで失敗した所をOSが一生懸命アクセスしようとしている所が見えています

# 読み書きに時間がかかるようになる

数MB程度の小さなファイルであっても、1分以上かかるような異常に時間がかかる場合、ハードディスクでエラーが多発している可能性があります。

OSで検知できないエラーがハードディスク内で起きていれば S.M.A.R.T.でエラーログ出てるかもしれません。smartctlで確認してみましょう

```shell-session
# smartctl -a /dev/sdc
smartctl 6.3 2014-07-26 r3976 [x86_64-linux-4.1.6] (local build)
Copyright (C) 2002-14, Bruce Allen, Christian Franke, www.smartmontools.org

...(省略)...

SMART Error Log Version: 1
ATA Error Count: 6 (device log contains only the most recent five errors)
        CR = Command Register [HEX]
        FR = Features Register [HEX]
        SC = Sector Count Register [HEX]
        SN = Sector Number Register [HEX]
        CL = Cylinder Low Register [HEX]
        CH = Cylinder High Register [HEX]
        DH = Device/Head Register [HEX]
        DC = Device Command Register [HEX]
        ER = Error register [HEX]
        ST = Status register [HEX]
Powered_Up_Time is measured from power on, and printed as
DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes,
SS=sec, and sss=millisec. It "wraps" after 49.710 days.

Error 6 occurred at disk power-on lifetime: 4810 hours (200 days + 10 hours)
  When the command that caused the error occurred, the device was active or idle.

  After command completion occurred, registers were:
  ER ST SC SN CL CH DH
  -- -- -- -- -- -- --
  40 51 00 33 9f 8f 68  Error: UNC at LBA = 0x088f9f33 = 143630131

  Commands leading to the command that caused the error were:
  CR FR SC SN CL CH DH DC   Powered_Up_Time  Command/Feature_Name
  -- -- -- -- -- -- -- --  ----------------  --------------------
  25 d0 08 30 9f 8f 68 00      06:11:01.048  READ DMA EXT
  25 d0 08 30 9f 8f 68 00      06:11:01.045  READ DMA EXT
  25 d0 10 f0 c1 50 6b 00      06:11:01.044  READ DMA EXT
  25 d0 f0 00 c1 50 6b 00      06:11:06.207  READ DMA EXT
  25 d0 10 f0 c0 50 6b 00      06:11:03.813  READ DMA EXT

Error 5 occurred at disk power-on lifetime: 4810 hours (200 days + 10 hours)
  When the command that caused the error occurred, the device was active or idle.

  After command completion occurred, registers were:
  ER ST SC SN CL CH DH
  -- -- -- -- -- -- --
  40 51 00 33 9f 8f 68  Error: UNC at LBA = 0x088f9f33 = 143630131

  Commands leading to the command that caused the error were:
  CR FR SC SN CL CH DH DC   Powered_Up_Time  Command/Feature_Name
  -- -- -- -- -- -- -- --  ----------------  --------------------
  25 d0 08 30 9f 8f 68 00      06:11:01.048  READ DMA EXT
  25 d0 10 f0 c1 50 6b 00      06:11:01.045  READ DMA EXT
  25 d0 f0 00 c1 50 6b 00      06:11:01.044  READ DMA EXT
  25 d0 10 f0 c0 50 6b 00      06:11:01.044  READ DMA EXT
  25 d0 f0 00 c0 50 6b 00      06:11:03.813  READ DMA EXT

Error 4 occurred at disk power-on lifetime: 4810 hours (200 days + 10 hours)
  When the command that caused the error occurred, the device was active or idle.

  After command completion occurred, registers were:
  ER ST SC SN CL CH DH
  -- -- -- -- -- -- --
  40 51 00 33 9f 8f 68  Error: UNC at LBA = 0x088f9f33 = 143630131

  Commands leading to the command that caused the error were:
  CR FR SC SN CL CH DH DC   Powered_Up_Time  Command/Feature_Name
  -- -- -- -- -- -- -- --  ----------------  --------------------
  25 d0 08 30 9f 8f 68 00      06:09:21.430  READ DMA EXT
  35 d0 08 18 18 a5 43 00      06:09:21.415  WRITE DMA EXT
  25 d0 08 08 89 6c 42 00      06:09:19.569  READ DMA EXT
  25 d0 10 c0 eb 4f 6b 00      06:09:18.184  READ DMA EXT
  25 d0 f0 d0 ea 4f 6b 00      06:09:17.955  READ DMA EXT

Error 3 occurred at disk power-on lifetime: 4810 hours (200 days + 10 hours)
  When the command that caused the error occurred, the device was active or idle.

  After command completion occurred, registers were:
  ER ST SC SN CL CH DH
  -- -- -- -- -- -- --
  40 51 00 33 9f 8f 68  Error: UNC at LBA = 0x088f9f33 = 143630131

  Commands leading to the command that caused the error were:
  CR FR SC SN CL CH DH DC   Powered_Up_Time  Command/Feature_Name
  -- -- -- -- -- -- -- --  ----------------  --------------------
  25 d0 08 30 9f 8f 68 00      06:09:17.571  READ DMA EXT
  25 d0 38 c8 9f 8f 68 00      06:09:17.571  READ DMA EXT
  25 d0 08 b0 9f 8f 68 00      06:09:19.569  READ DMA EXT
  25 d0 20 b0 e9 4f 6b 00      06:09:18.184  READ DMA EXT
  25 d0 e0 c8 e8 4f 6b 00      06:09:17.955  READ DMA EXT

Error 2 occurred at disk power-on lifetime: 4810 hours (200 days + 10 hours)
  When the command that caused the error occurred, the device was active or idle.

  After command completion occurred, registers were:
  ER ST SC SN CL CH DH
  -- -- -- -- -- -- --
  40 51 00 33 9f 8f 68  Error: UNC at LBA = 0x088f9f33 = 143630131

  Commands leading to the command that caused the error were:
  CR FR SC SN CL CH DH DC   Powered_Up_Time  Command/Feature_Name
  -- -- -- -- -- -- -- --  ----------------  --------------------
  25 d0 08 30 9f 8f 68 00      06:09:11.599  READ DMA EXT
  25 d0 10 10 9f 8f 68 00      06:09:09.454  READ DMA EXT
  25 d0 58 b0 9e 8f 68 00      06:09:09.386  READ DMA EXT
  25 d0 18 88 9e 8f 68 00      06:09:09.368  READ DMA EXT
  25 d0 10 58 9e 8f 68 00      06:09:09.367  READ DMA EXT

...(省略)...
```

S.M.A.R.T.のstatusでは問題無いように見えていてもエラーログが出ているケースもあるので、疑いのある場合はチェックしてみることおすすめします

エラーログが無ければ "No Errors Logged" となります

```shell-session
SMART Error Log Version: 1
No Errors Logged
```