Ubuntu再起動時にSDカードが認識されない問題の対処

背景

我が家ではMELE quieter3cというファンレスPCにUbuntuを入れて自宅サーバとして稼働させている。同PCをファイルサーバとしても使おうと、安価な1TBのMicroSDカードを挿入してそこを参照する形でSambaを構成した。
構築直後は正常に動いていたが、サーバを再起動するとSDカードが認識されず、ファイル共有が動かない。SDカードを抜いて挿せば再び認識されるが、ずっと挿しっぱなしで運用したいので解決法を調べた。

参照したサイト

結局ここの方法に従った。MELE quieter 3qという姉妹製品の事例だったから再現性高いかと思って採用したけど、ハードウェアやBIOSというよりはOSレベルの問題だったんじゃないかと思っている。 unix.stackexchange.com

全てが終わった後で見つけた記事。試してないがこれで十分だったんじゃないかという気がしている。 qiita.com

調査結果と今回の対応方法

調査結果

  • LinuxにおいてSDカードはmmcというドライバによって認識される
  • echo 1 > /sys/class/mmc_host/mmc0/device/removeによってmmc0(mmcによって認識されている0番目のデバイス)を切断し、物理的にデバイスを取り出したのと同じ状態を作ることができる
  • echo 1 > /sys/class/pci_bus/0000\:00/rescanによってPCIバス上の全てのデバイスを再スキャンし、物理的に接続されているデバイスを認識させることができる
  • MELE quieter3cには128GBのeMMCストレージ(最近の小型PCによく搭載されているマザーボード上に組み込まれたストレージ)があり、その名の通りこれもmmcによって制御される
  • eMMCとSDカードが読み込まれる順序は一定でなく、SDカードがmmc0になったりmmc1になったりする
  • mmcの読み込み順によってパーティションを指定するときのパスが変わり、/dev/mmcblk0p1になったり/dev/mmcblk1p1になったりする
  • mmcデバイスとして接続されているが中身が読み込まれていない状態は/sys/class/mmc_host/mmc#配下にmmc#:0001のようなフォルダが存在するか否かによって見分けられる

今回の対応

以下のようなシェルスクリプトを作り、OS起動後に実行するようにした。
本当はメタデータ的なものを参照して該当のMMCデバイスがSDカードであることを確認したかったが、やり方が分からなかった&自分の環境だとこれで問題なく動くのでこれで運用している。

echo '+ checking mmc devices'
mmcdev=nodevice
while read -r line; do # ヒアストリングで指定しているmmcデバイス(/sys/class/mmc_host/配下)でループを回す
  echo "  - checking $line"
  ls /sys/class/mmc_host/$line | egrep -v 'device|power|subsystem|uevent' # mmc#:0001が存在すれば$?が0になる = 該当のmmcデバイスが認識されている
  if [ $? -ne 0 ]; then
    mmcdev=$line
    break
  fi
done<<EOF # ls | while read line ...とするとループの外の変数が見えなくなるため普段使わない書き方になった
$(ls /sys/class/mmc_host)
EOF

if [ $mmcdev = 'nodevice' ]; then
  echo '  - no empty mmc devices found'
  exit 0
else
  echo "  - sdcard should be recognized at $mmcdev"
fi
mmcnum=${mmcdev:3}

echo '+ rescanning sdcard'
echo 1 > /sys/class/mmc_host/${mmcdev}/device/remove
echo 1 > /sys/class/pci_bus/0000\:00/rescan
echo '  - waiting for 10 seconds...'
sleep 10

echo '+ checking device status'
fdisk -l | grep /dev/mmcblk${mmcnum}
if [ $? -eq 0 ]; then
  echo '  - sdcard was found'
else
  echo '  - failed to recognize sdcard'
  exit 1
fi

echo '+ mounting sdcard'
mount ${devpath} /mnt/sdcard
status=$?
if [ $status -eq 0 ]; then
  echo "  - success. ${devpath} -> /mnt/sdcard"
else
  echo "  - mount failed with status $status"
  exit $status
fi

echo '+ starting smbd'
systemctl start smbd
status=$?
if [ $status -eq 0 ]; then
  echo '  - success'
else
  echo '  - failed to start smbd'
  exit $status
fi