令和の今頃になってSSDを使うのを止めた話

<!-- https://qiita.com/belgianbeer/items/37ca20884b29b0e8514e -->
# 令和の今頃になってSSDを使うのを止めた話

## それは電源の故障から始まった

ある日曜日のこと、自宅でPC(Windows)から自宅のFreeBSDサーバーをアクセスしようとして、なぜか反応しないことに気付きました。pingでも反応が無く「え？まさか…ひょっとして…電源が逝っちゃった?」と思いながらサーバーの設置場所に行くとやっぱり電源が落ちてました。こりゃダメだなというのはすぐにわかったのですが、一応と思い電源スイッチを押してみても電源は入らない。ということでサーバーの電源が壊れました。

## SSDだけで仮運用

サーバーには次のように3台のストレージデバイスがあり、SSDがFreeBSDのシステム、2台のHDDがデータ用のRAID 1(mirror)で、いずれもZFSです。

<table>
  <caption> SSD使用時のストレージ構成 </caption>
  <thead>
    <tr>
      <th align="center"> デバイス </th> <th align="center"> 種類 </th> <th align="center"> 容量 </th> <th align="center"> 用途 </th>
    </tr>
  </thead>
  <tr>
    <td align="center"> ada0 </td> <td align="center"> SSD </td> <td align="center"> 250 GB </td> <td> FreeBSDのシステム、ブート、スワップ </td>
  </tr>
  <tr>
    <td align="center"> ada1 </td> <td align="center"> HDD </td> <td align="center"> 6 TB </td> <td> /home を含むデータ領域 (ada2 と ZFSミラーを構成) </td>
  </tr>
  <tr>
    <td align="center"> ada2 </td> <td align="center"> HDD </td> <td align="center"> 6 TB </td> <td> /home を含むデータ領域 (ada1 と ZFSミラーを構成) </td>
  </tr>
</table>

自宅のサーバーではあるものの外部からCVSやGitのリポジトリなどを利用する関係で常時稼働していないと困るので、一時的な措置としてSSDを抜き出し、SATA/USB変換ケーブルで余っていたノートPCに取り付けてサーバーが復活するまでの代替機として稼働させました。もちろんHDD内の必要なデータ(常時必要なものはごく一部)はSSDにコピーしています。

## サーバーの復活と不調

3週間ぐらいで新しい電源を入手できたので、臨時運用のノートPCからSSDを外してサーバの筐体に戻し、元通りの構成にして稼働させました。しかし稼働して翌日にはコンソールに次のようなメッセージがを出力してサーバーとして正常な動作が出来ない状態に陥りました。

```console
ahcich0: Timeout on slot 20 port 0
ahcich0: is 00000002 cs 00000000 ss 00000000 rs 00100000 tfd 50 serr 00000000 cmd 00047417
(aprobe0:ahcich0:0:0:0): ATA_IDENTIFY. ACB: ec 00 00 00 00 40 00 00 00 00 00 00
(aprobe0:ahcich0:0:0:0): CAM status: Command timeout
(aprobe0:ahcich0:0:0:0): Error 5, Retries exhausted
```

こうなるとリセットするしか手はありません。リセットすればしばらく問題は無いのですが、短い場合は数時間、長くてもせいぜい翌々日には同様の状態に陥ります。

## 対処方法を検討

状況を整理してみます。

- ahcich0はSSDが接続してあるコントロールチャンネルなので、SSDのアクセスでトラブルが起きている。実際HDDへの読み書きではトラブルは発生しない。
- 交換した電源は以前と同じ容量の250Wであるが、電源が壊れる以前はまったく問題が無かった。

SSDが不良になったというのは考えにくいので、今回のSSDの接続し直しでケーブルの接触などに不具合が発生したのもありうると思いケーブルを交換してみましたが状況は改善しませんでした。

今回交換した電源は同じ250Wなのに実際には容量が不足していて、SSDの書き込み時に電力不足に陥っているのかもしれません(SSDの書き込み時の電力消費はHDDよりも大きい)。そうなると新たに別の電源ユニットを購入して交換する方法が考えられます。ただ別の電源を購入するにも微妙に入手しにくいタイプ(Frex ATX)で、交換したところで実際に消費している電力を計測したわけでは無いので、まったく違うものが原因である可能性も残っています。

## 解決策

数日経過して、ふと「SSDへのアクセスでトラブルが起きるのだから、SSDを止めればいい」ということに気付きました。SSDはほぼ純粋にFreeBSDのシステムとして利用しているだけで、データ領域は元々HDDを使っていますし、自分のホームもHDDにあります。そもそも本サーバーの当初はHDDだけで、通常の利用ではパフォーマンス面での問題はまったくありませんでした。ただHDDだけではfreebsd-updateに時間がかかるので、システム部だけをSSDにして独立させたという経緯があります。本サーバーの現状を考えるとSSDを止める(サーバーから抜く)のがトラブル対処として間違いないという判断となりました。

## 作業手順

SSDを抜くためには、HDDだけでサーバーが動作できるようにSSD上のシステムをHDDに移す必要があります。しかし現状HDDはデータ保存しか考慮していなかったため全体を1パーティションで構成していて、FreeBSDの起動に必要なブートコードを置く領域が有りません。

```console
$ gpart show ada0    # SSDのパーティション情報の表示
=>       40  488397088  ada0  GPT  (233G)
         40       1024     1  freebsd-boot  (512K)
       1064        984        - free -  (492K)
       2048    8388608     2  freebsd-swap  (4.0G)
    8390656  480006144     3  freebsd-zfs  (229G)
  488396800        328        - free -  (164K)

$ gpart show ada1    # HDDのパーティション情報の表示 (ada2も同じ構成)
=>         40  11721045088  ada1  GPT  (5.5T)
           40  11721045088     1  freebsd-zfs  (5.5T)

$
```

そこでSSDを抜くには、2台のHDDを、HDD1、HDD2として次の手順を実行する必要があります。

1. HDD1とHDD2で構成されているZFSミラーを解除してHDD1をフリーにする
2. HDD1のパーティションを作り直し、ブート、データ、スワップの各領域を用意する
3. HDD1にブートコードを書き込む
4. SSDのシステムデータをHDD1にコピーする
5. 電源を切ってSSDをシステムから撤去する
6. HDD2のデータをHDD1の残りの領域にコピーする
7. HDD2のパーティションを作り直してHDD1と同じにする
8. HDD1とHDD2のデータ領域をZFSでミラーにする

手順はそれなりにありますが、注意して行えば難しいところはありません。実際この手順に従って作業を行ったのですが、具体的な作業については「[ZFSルートのストレージを交換する](https://qiita.com/belgianbeer/items/b751c2036c7ee698fde2)」で記載しました。

## 構成変更後

こうしてシステムがSSDからHDDに変わったわけですが、トラブルが解消したことでサーバーとして正常稼働するようになりました。パフォーマンス面も通常利用においては全く問題ありません。気になるのはFreeBSDの新しいリリースが出たときに`freebsd-update upgrade -r ...`の実行にどのぐらい時間がかかるかですが、こればっかりは時間がかるようになるのは仕方ないかなと思っています。

ところで当サーバーではFreeBSDのソースを/usr/srcに展開してあったのですが、[freebsd-update実行時に/usr/srcにソースがあるとHDDでは顕著に時間がかかる](https://qiita.com/belgianbeer/items/a5ffcee86d2c660747f6)ので、/usr/src 内のファイルは全て削除しました。同様にデバッグ用のファイルも/usr/lib/debug にも一式あったのですが、これらもカーネル用のものを除いて削除しています。