生きることは忘れること

Raspberry PiにArch Linux ARMをLVMでインストールする

環境構築記録です。Raspberry Piでは普通はRaspberry Pi OSを使うところですが、筆者はほかの環境ではArch Linuxを使っているので、管理コスト低減のためにArch Linux ARMを使うことにしました。また、 /var/log のボリュームを分けたいので、柔軟性を持たせられるようにLVMで構成します。

使っているRaspberry PiはRaspberry Pi 4 Model Bです。

パーティショニングとファイルコピー

まず一旦LVMを使わずに普通にインストールします。この過程を経ずにやる方法がないかなといろいろ試したのですが、LVMを使うには後で出てくるようにinitramfsにフックを入れてやる必要があり、そのためには実機で操作しないと難しいと思います(もしかしたら何かしら術があるかもしれませんが)。

で、作業としては適当なマシンの上でISOイメージをダウンロードしてmicroSDに焼くだけ……と言いたいところですが、Arch Linux ARMのイメージは .iso ではなく .tar.gz なのでファイルシステムを作ってコピーしてあげる感じです。Raspberry Pi 4 | Arch Linux ARMに書いてある通りにやればいいです。Armv7とAarch64がありますが当然Aarch64を選びます。

注意事項として、Raspberry PiをmicroSDカードから起動するには、MBRでフォーマットされていて、先頭のbootパーティションはFAT32である必要があります。何も考えずに手癖でGPTとかext4とかでやると嵌まります(嵌まりました)。それと、後の手順でrootパーティションを dd することになるので小さめにしておくとよいです。rootパーティションは第2パーティションでなければならないので注意してください。

以下、bootパーティションを /mnt/boot に、ルートを /mnt/root にマウントしているとします。

Device Treeの修正

これでとりあえず起動するはずなのですが、私の手元ではブートの途中で以下のエラーが無限に繰り返される状態になってしまいました。

mmc1: error -22 whilst initialising SD card
mmc1: unrecognised SCR structure version 4

手順通りにインストールしただけなので、明らかに配布されているイメージの時点で問題があるということです。超絶探し回って試行錯誤しまくった結果、U-boot compilation on CM4 - Raspberry Pi Forums[SOLVED] Slackware aarch64 installer, C0 stepping RPi4 & Samsung EVO SD cardsに書かれていることを /mnt/boot/dtbs/broadcom/bcm2711-rpi-4-b.dtb に対してやると治りました(step by stepの手順は後者のページに詳しいです)。どうやらdevice treeの問題だったようです。device treeが何かという説明は私には手に負えないですが、Raspberry Piのハードウェアの仕様とbootパーティション内に置かれているファイルの記述とが整合しない状態になっていたということだと思います。

initramfs

さて、上でも少し触れましたが、LVM に Arch Linux をインストールする - ArchWikiに書かれている通り、LinuxをLVM構成でインストールした場合、initramfsにlvm2フックを追加する必要があります。

母艦で mkinitcpio にオプションを付けてinitramfsを作れないかと試したのですが上手くいかなかったので、実機で作業します。ちなみに別のmicroSDカードで起動して作成したinitramfsをまっさらなイメージに持ち込んでみるというのも試したのですが、これも上手くいきませんでした( lvm2 パッケージをインストールする際に pacman -Syu でシステムのフルアップデートをしたのでkernelもアップデートされて不整合が起きた……とかだと思っています)。

手順は上に貼ったArch Wikiの通りです。新しいinitramfsで起動するかどうかを一度試しておきましょう。 /boot をマウントしておくのを忘れずに(一敗)。

LVMパーティションの作成

LVMパーティションを作成して、 dd コマンドなどでrootパーティションをここにコピーしてあげます。LVMまわりの操作はLVM に Arch Linux をインストールする - ArchWikiLVM - ArchWikiを参照してください。LVMパーティション内を切り刻むのは後にして、とりあえず論理ボリュームを1個だけ作成しましょう。コピーの段取りはなんでもよいですが、筆者は

  1. 第2パーティションにrootがある
  2. 第4パーティションを作成
  3. dd if=/dev/mmcblk0p2 of=/dev/mmcblk0p4 bs=128K status=progress
  4. もとの第2パーティションを爆破して、LVMな第2パーティションを新たに作成
  5. dd if=/dev/mmcblk0p4 of=/dev/vga/root bs=128K status=progress

としました。最終的なLVMパーティションが第2パーティションになるのを諦めてもいいですし、パーティション番号を付け替えてあげてもいいです。この段階では起動しないので、次に進んでください。

カーネルパラメタの更新

rootパーティションの場所が変わったので、カーネルパラメタでrootがどこにあるのか教えてやる必要があります。前提として、Raspberry Pi 4 Model BのブートシークエンスはRaspi4B+ Boot Sequence の再整理とBoot LoaderのUART出力 - 備忘録などに詳しいです(Raspberry Pi 3以前とは異なっているので注意)。それで、 start4.elfconfig.txt に従ってカーネルを読み込んで起動するわけですが、Arch Linux ARMのイメージでは以下のようになっています。

  1. config.txtkernel は設定されていない(ので、config.txt - Raspberry Pi Documentationにあるように、デフォルト値である kernel7.imgkernel8.img が順に試される)。
  2. kernel8.img が存在するが、これはLinuxカーネルではなくU-Bootである。
  3. U-BootがU-Bootスクリプト boot.scr に従ってLinuxカーネルを読み込む。Linuxカーネルは Image というファイルで、U-Bootスクリプトでこれが指定されている。

U-Bootを噛ませないブートシークエンスの場合はカーネルパラメタは cmdline.txt で指定しますが、このブートシークエンスではLinuxカーネルを起動するのは start4.elf ではなくU-Bootなので、カーネルパラメタもU-Bootスクリプトで指定します。具体的には

$ sudo pacman -S uboot-tools
$ sudo -i
# cd /mnt/boot
# vi boot.txt
# ./mkscr

と叩きます。 boot.txtsetenv bootargs で始まる行がカーネルパラメタです。元はroot=PARTUUID=${uuid} となっているところを、 root=/dev/vga/root などと変えます(LVMのボリュームグループ名と論理ボリューム名は自分の作ったものを入れてください)。

ここまで来たら起動するはずなので、microSDカードをRaspberry Piにさして電源を入れましょう。

パーティションレイアウトの修正

後は仕上げです。論理ボリュームを切り刻んで /etc/fstab をいい感じにしてください。