mdadmのアレイのデバイス名が変わって使えなくなった場合の復旧方法

# 概要

Linux上でソフトウェアRAIDを構築するmdadmをラズパイで動かしてしばらく運用していたのですが、接続していたHDDのデバイス名が勝手に変わってしまい使えなくなる事態が発生しました。何とか復旧できたので、その方法をご紹介します。

#### 注意事項
本記事でご紹介する方法はmdadmについての知識が不十分な筆者が試行錯誤で行ったものなので「ベストな方法ではない」ことにご注意願います。筆者が失敗したり紆余曲折した内容をもとに、同じ問題に直面した方がより良い解決方法を模索していただくきっかけになれば幸いです。
また本記事でご紹介する復旧コマンドは、**接続ディスクの状況によっては保存されているファイルの内容を書き換えてしまう可能性がある**ことにもご注意ください。


# 環境情報

* マシン名
    * Raspberry Pi 4 Model B 4GB
* OS
    * Ubuntu 22.04 LTS
* mdadmのバージョン
    * v4.2 - 2021-12-30
* 構成
    * 2台のHDDでRAID1を構築（同じデータが2台のHDDに存在）
    * xfsでフォーマット

# 初期構築

ラズパイにUSB接続した２台のHDDが、OSから ``/dev/sda``,``/dev/sdb``として認識されており、次のコマンドで構築しました。

* RAID1を構築して ``/dev/md127`` として認識させる
  ```
  sudo mdadm --create /dev/md127 --level=1 --raid-devices=2 /dev/sda /dev/sdb
  ```
* xfsでファイルシステムを作る
  ```
  sudo mkfs.xfs /dev/md127
  ```

あとは指定ディレクトリにマウントして、しばらくはこのまま問題なく運用できていました。
この後に示すトラブル時の結果と比較できるようにするため、現時点の正常な状態がわかるコマンド出力を以下に記載します。
```
$ sudo mdadm --detail /dev/md127
（出力省略）
    Number   Major   Minor   RaidDevice State
       0       8       16        0      active sync   /dev/sda
       1       8       48        1      active sync   /dev/sdb
```

# デバイス名が勝手に変わる現象が発生...

ところがある時、マウントしたディレクトリにアクセス出来なくなる事態が発生...
``/dev/md127``の状況を以下のコマンドで確認すると、2つのHDDのデバイスがどっちもRAIDアレイとして認識されていないことを確認します。
```
$ sudo mdadm --detail /dev/md127
（出力省略）
    Number   Major   Minor   RaidDevice State
       0       8        0        0      active sync   missing
       -       0        0        1      removed
```

HDDのデバイス名を確認すると、もともと``/dev/sda``,``/dev/sdb``という名前だったものが``/dev/sdc``,``/dev/sdd``に変わっているではありませんか...
```
$ lsblk | grep ^sd
sdc           8:16   0   1.8T  0 disk
sdd           8:48   0   1.8T  0 disk
```

## 少し余談だが重要かもしれない話
「デバイス名が変わってしまう」という事象は、以下記事のように例えばOSが再起動した際などによく発生するようです。今回の事象が発覚した時点での記憶があやふやなのですが、再起動によって変わってしまった可能性も高そうです...

https://chimyblog.com/linux-dev-naming/

なのでもし仮に「RAIDアレイを最初に構築する時（または構築後）に各ディスクのUUIDを指定する」ことができれば全て解決だと思います。例えば以下のようなコマンドが実行できるのであれば（あくまでも妄想です）。
```
sudo mdadm --create /dev/md127 --level=1 --raid-devices=2 \
/dev/disk/by-uuid/[uuid-of-sda] \
/dev/disk/by-uuid/[uuid-of-sdb]
```
しかしながら、（私の知識が間違っていなければ）RAIDアレイを作成する前の段階で、ディスクには有効なUUIDは付与されていないはずです。なので少なくとも、RAIDアレイの構築前にディスクのUUID指定は無理という認識です。

RAIDアレイ構築後であればディスクにもUUIDとUUID_SUBが付与されるので、これを使ってデバイス名に依存しない設定ができるのかもしれません。
```
$ sudo blkid /dev/sdb
/dev/sda: UUID="[uuid]" UUID_SUB="[uuid-sub]" LABEL="[hostname]:0" TYPE="linux_raid_member"
```

### 重要かも！？
記事を書いた直後に知ったのですが、RAIDアレイ構築後に次のコマンドを使って``/etc/mdadm/mdadm.conf`` に現在構築中の情報を追記すれば、仮に再起動してデバイス名が変わってもRAIDアレイが使えそうです（だとしたら私の完全な知識不足...）

```
sudo bash -c 'mdadm --detail --scan | tee -a /etc/mdadm/mdadm.conf'
```

# 復旧のために試行錯誤するも失敗
本題に戻ります。
とりあえずはデバイス名が変わってしまったHDDをRAIDアレイに追加することを試みますが、どちらも追加できません。
```
$ sudo mdadm --manage /dev/md127 --add /dev/sdc
mdadm: cannot load array metadata from /dev/md127
$ sudo mdadm --manage /dev/md127 --add /dev/sdd
mdadm: cannot load array metadata from /dev/md127
```
ChatGPTに相談してアレイの停止やumountをしてみても、エラーが出て状況は変わらず...
```
$ sudo mdadm --stop /dev/md127
mdadm: Cannot get exclusive access to /dev/md127:Perhaps \
a running process, mounted filesystem or active volume group?
$ sudo umount /dev/md127
umount: /dev/md127: not mounted.
```

# 解決策

おそらくベストな方法からはほど遠いですが、次の手順で解決しました。

## ``/dev/md127``を削除
本当は必要ないかもしれませんが、今回の試行錯誤の過程では削除しました。
```
sudo rm /dev/md127
```

## mdadmのRAIDアレイを再構築
``/dev/md0``に新たにRAIDアレイを構築します。

:::note warn
調査した限りだと「``mdadm --create ..``を実行した際、既にディスクに格納されているデータが残るかどうか？」がわかりませんでした（その辺が書いてあるWeb記事がなかなか見つからない...）。なので以下のコマンドを実行する場合は「既存のデータが書き換えられる」危険性も考慮し、ご自身の判断と責任で実行してください。
:::
```
$ sudo mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdc /dev/sdd
(出力)
mdadm: /dev/sdc appears to be part of a raid array:
       level=raid1 devices=2 ctime=Wed Jan 18 19:35:09 2023
mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90
mdadm: /dev/sdd appears to be part of a raid array:
       level=raid1 devices=2 ctime=Wed Jan 18 19:35:09 2023
Continue creating array? y # yを押下
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.
```

これで、以下のように二つのディスクが``/dev/md0``のRAIDアレイに仲間入りできました。
```
$ lsblk | grep -A 1 ^sd
sdc           8:16   0   1.8T  0 disk
└─md0         9:0    0   1.8T  0 raid1
sdd           8:48   0   1.8T  0 disk
└─md0         9:0    0   1.8T  0 raid1
```
また``/dev/md0``のファイルシステムもこれまで通りxfsになっているのを確認できています。
```
$ sudo parted /dev/md0 print
Model: Linux Software RAID Array (md)
Disk /dev/md0: 2000GB
Sector size (logical/physical): 512B/4096B
Partition Table: loop
Disk Flags:

Number  Start  End     Size    File system  Flags
 1      0.00B  2000GB  2000GB  xfs
```

## UUIDが重複してマウントできない...

「あとは実際にマウントして解決！」のはずが、マウントできません...

```
$ sudo mount /dev/md0 /path/to/mount
mount: /path/to/mount: wrong fs type, bad option, \
bad superblock on /dev/md0, missing codepage or \
helper program, or other error.
```

``/var/log/syslog``の内容を調べると、``/dev/md0``のUUIDが他のデバイスと重複していることがマウント失敗の原因のようです。
```
Dec  7 06:08:01 ubuntu kernel: [2594369.042898] XFS \
(md0): Filesystem has duplicate UUID \
xxxxxxxx-yyyy-zzzz-aaaa-bbbbbbbbbbbb - can't mount
```

:::note info
半分は推測ですが、前にRAIDアレイとして使っていた``/dev/md127``のUUIDがシステムにまだ残っていて、それが``/dev/md127``のUUIDと重なっているのが原因と思っています。なので``/dev/md127``に向けて``mdadm --create``を実行していたらこの問題は発生していなかったかもしれません。
:::

## UUIDを変更して解決

そこで、``/dev/md0``のUUIDを変更を以下コマンドで試みますが、失敗します...
```
$ sudo xfs_admin -U generate /dev/md0
ERROR: The filesystem has valuable metadata changes in a log which needs to
be replayed.  Mount the filesystem to replay the log, and unmount it before
re-running xfs_admin.  If you are unable to mount the filesystem, then use
the xfs_repair -L option to destroy the log and attempt a repair.
Note that destroying the log may cause corruption -- please attempt a mount
of the filesystem before doing this.
```
どうやら一回``/dev/md0``をどこかのパスにマウントする必要があるのですが、既にさっきマウントしようとして失敗している、という事実もあります。。。これはもはや詰んのだか...
しばらく絶望しかけましたが、[こちら](https://qiita.com/Jey/items/33479420a4ad270996ab)の記事を参考にして``-o nouuid``でマウントできました！

```
sudo mount -t xfs -o nouuid /dev/md0 /path/to/mount
```

一回アンマウントして、
```
sudo umount /path/to/mount
```
UUIDが変更できることを確認。
```
$ sudo xfs_admin -U generate /dev/md0
Clearing log and setting UUID
writing all SBs
new UUID = xxxxxxxx-yyyy-zzzz-aaaa-bbbbbbbbbbbc
```

次はオプションなしでRAIDアレイがマウントできることを確認できました！

```
$ sudo mount /dev/md0 /path/to/mount
(マウント成功)
$ $ df -h | grep md0
/dev/md0        1.9T  1.4T  531G  72% /path/to/mount
```