Raspbianのinitramfsをカーネルのアップデートに追従するようにした
Raspberry PIでrootfsのReadOnly化やUSB OTGとかで試してきて、ちょっとだけinitramfs使ってやりたいことやれるようになった。
だけど、apt-get upgrade
でカーネルが更新されると、既存のinitramfsを作りなおさなければならないことに気がついた。
しばらくはカーネルの更新があるたびに手作業で作りなおしていたんだけど、これなんとかならんかな…と思っていた。
ある日PCのubuntuでパッケージの更新をしていた時に、流れてくる出力にinitramfsを作りなおしているらしき表示があることに気がついた。 で、もしかしてaptの更新で動くフックがあるんじゃないかと思って探してみた。
対象はRaspbian Busterの2019-07-10のやつ。
initramfs-toolsのフック
目的のフックは/etc/kernel/postinst.d/initramfs-tools
にあった。
中身は次のようになっていた。
#!/bin/sh -e version="$1" bootopt="" command -v update-initramfs >/dev/null 2>&1 || exit 0 # passing the kernel version is required if [ -z "${version}" ]; then echo >&2 "W: initramfs-tools: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number" exit 2 fi # exit if kernel does not need an initramfs if [ "$INITRD" = 'No' ]; then exit 0 fi # absolute file name of kernel image may be passed as a second argument; # create the initrd in the same directory if [ -n "$2" ]; then bootdir=$(dirname "$2") bootopt="-b ${bootdir}" fi # avoid running multiple times if [ -n "$DEB_MAINT_PARAMS" ]; then eval set -- "$DEB_MAINT_PARAMS" if [ -z "$1" ] || [ "$1" != "configure" ]; then exit 0 fi fi # we're good - create initramfs. update runs do_bootloader # shellcheck disable=SC2086 INITRAMFS_TOOLS_KERNEL_HOOK=1 update-initramfs -c -k "${version}" ${bootopt} >&2
ざっと見た感じ、この仕組みに乗っかるならupdate-initramfs
で作ったほうが良さそう(自分はmkinitramfs
コマンドで作っていた)。
とりあえずmkinitramfs
で作っておいたinitrd.img
をupdate-initramfs -c -k $(uname -r)
で作りなおした。
ファイル名はinitrd.img-x.y.z-v7+
のようになるので、/boot/config.txt
のinitramfs
設定も修正しておいた。
また、スクリプトを見るに$INITRD
の値が設定されていないと更新はキャンセルされそう。
そこでこの値を設定する方法を探した。これは/etc/default/raspberrypi-kernel
にあった。
中身こんな感じ。
# Defaults for raspberrypi-kernel # Uncomment the following line to enable generation of # /boot/initrd.img-KVER files (requires initramfs-tools) #INITRD=Yes # Uncomment the following line to enable generation of # /boot/initrd(7).img files (requires rpi-initramfs-tools) #RPI_INITRD=Yes
rpi-initramfs-tools
ってなんだ?と思ったけど、特にそういうパッケージがあるわけではないみたい。
今のところ取り置きされているような感じなのだろうか…?とりあえずINITRD=Yes
のコメントアウトを解除した。
その状態でapt-get upgrade
でカーネルの更新をしてやると、出力に次のような表示が出てきて新しいカーネルバージョンでinitramfsが作りなおされていることが解る。
run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.19.66+ /boot/kernel.img run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.19.66+ /boot/kernel.img /etc/kernel/postinst.d/initramfs-tools: update-initramfs: Generating /boot/initrd.img-4.19.66+ run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.19.66-v7+ /boot/kernel7.img run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.19.66-v7+ /boot/kernel7.img /etc/kernel/postinst.d/initramfs-tools: update-initramfs: Generating /boot/initrd.img-4.19.66-v7+ run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.19.66-v7l+ /boot/kernel7l.img run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.19.66-v7l+ /boot/kernel7l.img /etc/kernel/postinst.d/initramfs-tools: update-initramfs: Generating /boot/initrd.img-4.19.66-v7l+
実際に/boot
の中身を見てみると
$ ls /boot/initrd.img-* /boot/initrd.img-4.19.66+ /boot/initrd.img-4.19.66-v7+ /boot/initrd.img-4.19.66-v7l+
となって、新たなバージョンのinitramfsができていることがわかった(手で作った旧バージョンは削除されていた)。
ただし、Raspbianの場合このままだと/boot/config.txt
のinitramfs
設定は古いままになってしまうので、
そこはひと手間かけてやる必要がありそう。
/etc/kernel/postinst.d/initramfs-tools
をカスタマイズ
ひとまず/etc/kernel/postinst.d/initramfs-tools
の末尾に次の処理を追加した。
# replace /boot/config.txt current_version="$(uname -r)" old_version_number=${current_version%-*} if echo $version | grep -Pq "^\d+\.\d+\.\d+\+$"; then old_version="$old_version_number+" else old_version="$old_version_number-${version#*-}" fi sed -i "s/initramfs initrd.img-$old_version/initramfs initrd.img-$version/g" "$bootdir/config.txt"
現在動作しているOSのバージョンを調べて更新対象のライブラリバージョンで/boot/config.txt
のinitramfs
設定を書き換える。
これで改めて確認し、Busterではアップデートに追従できるようになった。
Stretchに対応する
上記の修正をStretchでもやってみたところ、次のような出力が表示されて作りなおしに失敗した。
run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.19.66+ /boot/kernel.img run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.19.66+ /boot/kernel.img /etc/kernel/postinst.d/initramfs-tools: update-initramfs: Generating /boot/initrd.img-4.19.66+ run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.19.66-v7+ /boot/kernel7.img run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.19.66-v7+ /boot/kernel7.img /etc/kernel/postinst.d/initramfs-tools: update-initramfs: Generating /boot/initrd.img-4.19.66-v7+ run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.19.66-v7l+ /boot/kernel7l.img run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.19.66-v7l+ /boot/kernel7l.img /etc/kernel/postinst.d/initramfs-tools: update-initramfs: Generating /boot/initrd.img-4.19.66-v7l+ WARNING: missing /lib/modules/4.19.66-v7l+ Ensure all necessary drivers are built into the linux image! depmod: ERROR: could not open directory /lib/modules/4.19.66-v7l+: No such file or directory depmod: FATAL: could not search modules: No such file or directory depmod: WARNING: could not open /var/tmp/mkinitramfs_L5yf77/lib/modules/4.19.66-v7l+/modules.order: No such file or directory depmod: WARNING: could not open /var/tmp/mkinitramfs_L5yf77/lib/modules/4.19.66-v7l+/modules.builtin: No such file or directory *** 中略 *** Processing triggers for initramfs-tools (0.130) ... ln: failed to create hard link '/boot/initrd.img-4.19.66-v7l+.dpkg-bak' => '/boot/initrd.img-4.19.66-v7l+': Operation not permitted cp: error writing '/boot/initrd.img-4.19.66-v7l+.dpkg-bak': No space left on device dpkg: error processing package initramfs-tools (--configure): subprocess installed post-installation script returned error exit status 1 Processing triggers for libc-bin (2.24-11+deb9u4) ... Errors were encountered while processing: initramfs-tools E: Sub-process /usr/bin/dpkg returned an error code (1)
メッセージを読みながら調べてみると、更新処理がRaspberry PI4用のv7l+系のinitramfsを作ろうとするが、
StretchはRaspberry PI4に対応していないのでv7l+用のモジュールライブラリが見つからずにdepmodのエラーが出ている。失敗に終わったinitrd.img-4.19.66-v7l+ファイルはそのまま/boot
に残留する。
更にバックアップを取って新しく作ろうとするので、/boot
パーティションのディスクスペースが圧迫されて作成できずに落ちる…ということらしい。
そこで/etc/kernel/postinst.d/initramfs-tools
の$INITRD
のチェックの次に、下のような処理を追加した。
# skip ignore version lib if [ ! -e "/lib/modules/$version" ]; then echo "Not exist module libraries. [$version]" exit 0 fi
これでv7l+のような対応していないライブラリバージョンの生成はスキップされる。
また、/boot
パーティションの空き容量が深刻なので、/usr/sbin/update-initramfs
のbackup_initramfs
とbackup_booted_initramfs
の方にも手を入れた。
# backup initramfs while running backup_initramfs() { [ ! -r "${initramfs}" ] && return 0 #initramfs_bak="${initramfs}.dpkg-bak" initramfs_bak="/var/tmp/$(basename initramfs).dpkg-bak" [ -r "${initramfs_bak}" ] && rm -f "${initramfs_bak}" #ln -f "${initramfs}" "${initramfs_bak}" \ # || cp -a "${initramfs}" "${initramfs_bak}" mv "${initramfs}" "${initramfs_bak}" verbose "Keeping ${initramfs_bak}" } # keep booted initramfs backup_booted_initramfs() { #initramfs_bak="${initramfs}.dpkg-bak" initramfs_bak="/var/tmp/$(basename initramfs).dpkg-bak" *** 以下略 ***
デフォルトでは/boot
パーティションに作成されていたバックアップファイルを/var/tmp
に作成するように変更し、
既存バージョンのファイルを直接バックアップファイルにすることで、既存バージョンのファイルと、バックアップファイル、新しく作成するファイルで一時的に3つできてしまうことを避けるようにした。
これでapt-get upgrade
でカーネルの更新をして結果は次のようになった。
run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.19.66+ /boot/kernel.img run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.19.66+ /boot/kernel.img /etc/kernel/postinst.d/initramfs-tools: update-initramfs: Generating /boot/initrd.img-4.19.66+ run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.19.66-v7+ /boot/kernel7.img run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.19.66-v7+ /boot/kernel7.img /etc/kernel/postinst.d/initramfs-tools: update-initramfs: Generating /boot/initrd.img-4.19.66-v7+ run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.19.66-v7l+ /boot/kernel7l.img run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.19.66-v7l+ /boot/kernel7l.img /etc/kernel/postinst.d/initramfs-tools: Not exist module libraries. [4.19.66-v7l+] ** 以下省略 **
4.19.66-v7l+
用のライブラリは存在しないのでスキップされ、/boot
パーティション内でファイル容量食い過ぎることもないので、エラーになることなくinitramfsの更新までできた。