Seeed K.K.の中井です。
reComputer J2012でデモを作成していたのですが、開発中はrebootコマンドなどで安全に再起動やシャットダウンができるのですが、デモ中や設置・撤収時はやはり電源ぶち切りになってしまいます。デモ稼働中に電源をぶち切りしてしまった場合にはファイルシステムが壊れてしまう可能性があるので、やはりリードオンリー化が必要ですね。
早速overlayrootをインストールして試してみましたが、正常に利用することはできませんでした。
ということでinitrdを変更してreComputer J2012をリードオンリー化してみたのですが、ググってみてもJetson L4Tのリードオンリー化の情報が少なかったので、この記事に手順をまとめてみました。
リードオンリー化
リードオンリー化する方法として、今回は「OverlayFS」を利用したいと思います。 参考にした手順は下記になります。
やることは、下記3つです。
- Linux KernelにOverlayFSを組込む (デフォルト状態ではモジュールとなっている)
- initrdイメージをカスタマイズしてルートファイルシステムにOverlayFSを利用するように変更
- 作成したイメージで起動できるように変更
作業の前に
Linux KernelのバージョンとJetson Linux Driver Package (L4T)のバージョンを確認しておきます。 Linux Kernelのバージョンは「4.9.299-tegra」、L4Tのバージョンは「32.7.3」でした。
$ uname -a Linux reComputerJ2012 4.9.299-tegra #1 SMP PREEMPT Tue Nov 22 09:24:30 PST 2022 aarch64 aarch64 aarch64 GNU/Linux $ jetson_release Software part of jetson-stats 4.1.4 - (c) 2023, Raffaello Bonghi Model: NVIDIA Jetson Xavier NX Developer Kit - Jetpack 4.6.3 [L4T 32.7.3] NV Power Mode: MODE_10W_DESKTOP - Type: 5 jtop: - Version: 4.1.4 - Service: Active Libraries: - CUDA not installed! - cuDNN: Not installed - TensorRT: Not installed - VPI: Not installed - Vulkan: 1.2.70 - OpenCV not installed!
Linux Kernelの変更
reComputer J2012のeMMCではLinux Kernelなどをビルドするには容量が不足する可能性があるので、この記事では作業用PC(Linux)を用意してクロスビルドすることにします。とくに特別なビルド環境が必要なわけではないのですが公式ドキュメントに目を通しておくと良いと思います。
さて、先ほど確認したLinux Kernelバージョンをもとに下記からソースコードとツールチェーンをダウンロードします。
とりあえず必要なのは下記。
作業用PCでダウンロードしておきます。(なぜこのようなファイル名になっているのか。。)
$ ls
l4t-gcc-7-3-1-toolchain-64-bit
remack-sdksjetpack-463r32releasev73sourcest186publicsourcestbz2
一応アーカイブの種類を確認してファイル名を変更しておきます。
$ file remack-sdksjetpack-463r32releasev73sourcest186publicsourcestbz2 remack-sdksjetpack-463r32releasev73sourcest186publicsourcestbz2: bzip2 compressed data, block size = 900k $ file l4t-gcc-7-3-1-toolchain-64-bit l4t-gcc-7-3-1-toolchain-64-bit: XZ compressed data $ mv remack-sdksjetpack-463r32releasev73sourcest186publicsourcestbz2 remack-sdksjetpack-463r32releasev73sourcest186publicsources.tbz2 $ mv l4t-gcc-7-3-1-toolchain-64-bit l4t-gcc-7-3-1-toolchain-64-bit.tar.xz
ダウンロードしたソースコードのアーカイブとツールチェーンを展開します。
$ tar -xf remack-sdksjetpack-463r32releasev73sourcest186publicsources.tbz2 $ tar -xf l4t-gcc-7-3-1-toolchain-64-bit.tar.xz $ ls -d Linux_for_Tegra gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu l4t-gcc-7-3-1-toolchain-64-bit.tar.xz remack-sdksjetpack-463r32releasev73sourcest186publicsources.tbz2
後程Linux Kernelをビルドするときにクロスコンパイラを指定するので、ここでクロスコンパイラのプリフィックスを設定しておきます。PATHが通っていないのでフルパスで指定しておきます。
$ export CROSS_COMPILE_AARCH64=$(pwd)/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
Linux Kernelのソースコードを展開します。
$ cd Linux_for_Tegra/source/public/ Linux_for_Tegra/source/public$ tar -xf kernel_src.tbz2
続いてコンフィグレーションを行います。 デフォルト状態(tegra_defconfig)では、OverlayFSはモジュール(overlay.ko)となるように設定されているので、コンフィグレーションメニューからKernelイメージに組み込まれるように変更します。
Linux_for_Tegra/source/public$ cd kernel/kernel-4.9/ Linux_for_Tegra/source/public/kernel/kernel-4.9$ make ARCH=arm64 CROSS_COMPILE=$CROSS_COMPILE_AARCH64 tegra_defconfig Linux_for_Tegra/source/public/kernel/kernel-4.9$ make ARCH=arm64 CROSS_COMPILE=$CROSS_COMPILE_AARCH64 menuconfig File systems ---> <*> Overlay filesystem support ←<M>から<*>に変更
正しく変更できていれば、下記のように"y"になります。(モジュールとなっている場合は"m")
Linux_for_Tegra/source/public/kernel/kernel-4.9$ grep OVERLAY_FS .config CONFIG_OVERLAY_FS=y
続いてビルドします。LOCALVERSIONの付与を忘れずに。
Linux_for_Tegra/source/public/kernel/kernel-4.9$ make ARCH=arm64 CROSS_COMPILE=$CROSS_COMPILE_AARCH64 LOCALVERSION="-tegra"
ビルドが完了するとarch/arm64/boot/Image
にバイナリが作成されるので、reComputer J2012本体にコピーしておきます。下記はSCPで転送した例です。※reComputer側のユーザー名とIPアドレスは環境に合わせて変更する必要があります
Linux_for_Tegra/source/public/kernel/kernel-4.9$ scp arch/arm64/boot/Image jetson@192.168.1.127:/home/jetson/Image.new
initrdの変更
initrdについては「Drivers Package (BSP)」をダウンロード・展開して、
Linux_for_Tegra/nv_tegra/l4t_deb_packages/nvidia-l4t-initrd_32.7.3-20221122092958_arm64.deb
に含まれるものを変更するのが良いと思いますが、基本的に同じもののはずなので実機で使用しているinitrdイメージをコピーして変更します。
下記はSCPで実機から作業PCへコピーしている例です。一応作業PC側ではinitrd.origにリネームしています。
$ scp jetson@192.168.1.127:/boot/initrd ./initrd.orig
任意のディレクトリ(ここではinitrd_files)を作成しinitrdを展開します。
$ mkdir -p initrd_files $ cd initrd_files/ initrd_files$ gzip -cd ../initrd.orig | cpio -imd --quiet
初期化スクリプトのinitを変更します。ここではテキストエディタにnanoを使っていますが、お好きなもので構いません。
initrd_files$ nano init
--- init.orig 2023-02-07 13:59:22.646934066 +0900 +++ init 2023-02-07 14:28:56.296346799 +0900 @@ -142,11 +142,6 @@ echo "ERROR: ${rootdev} not found" > /dev/kmsg; exec /bin/bash; fi - mount /dev/${rootdev} /mnt/; - if [ $? -ne 0 ]; then - echo "ERROR: ${rootdev} mount fail..." > /dev/kmsg; - exec /bin/bash; - fi; elif [[ "${rootdev}" == sd* ]]; then if [ ! -e "/dev/${rootdev}" ]; then while [ ${count} -lt 50 ] @@ -214,13 +209,36 @@ # Disable luks-srv TA nvluks-srv-app -n > /dev/null 2>&1; +# create /mnt as mount point +mount -t tmpfs inittemp /mnt; +mkdir /mnt/lower; +mkdir /mnt/rw; +mount -t tmpfs root-rw /mnt/rw; +mkdir /mnt/rw/upper; +mkdir /mnt/rw/work; +mkdir /mnt/lower; +mount -o ro /dev/${rootdev} /mnt/lower; +if [ $? -ne 0 ]; then + echo "ERROR: ${rootdev} mount fail..." > /dev/kmsg; + exec /bin/bash; +fi; +mkdir /mnt/newroot; +mount -t overlay -o lowerdir=/mnt/lower,upperdir=/mnt/rw/upper,workdir=/mnt/rw/work overlayfs-root /mnt/newroot; +if [ $? -ne 0 ]; then + echo "ERROR: overlay fail..." > /dev/kmsg; + exec /bin/bash; +fi; + echo "Rootfs mounted over ${rootdev}" > /dev/kmsg; +mkdir /mnt/proc; +mkdir /mnt/sys; +mkdir /mnt/dev; mount -o bind /proc /mnt/proc; mount -o bind /sys /mnt/sys; mount -o bind /dev/ /mnt/dev; -cd /mnt; +cd /mnt/newroot; cp /etc/resolv.conf etc/resolv.conf echo "Switching from initrd to actual rootfs" > /dev/kmsg; -mount --move . / + exec chroot . /sbin/init 2;
initrdを作成し直して実機にコピーします。
initrd_files$ find . | cpio -H newc --owner root:root -o | gzip -9 -n > ../initrd.new initrd_files$ cd .. $ scp initrd.new jetson@192.168.1.127:/home/jetson/
作成したイメージで起動できるように変更
ここからは実機での作業です。
作成したLinux Kernelイメージ(Image.new)とinitrdイメージ(initrd.new)をbootディレクトリに配置、その後にextlinux.confを変更して作成した新しいイメージで起動するように変更していきます。
jetson@reComputerJ2012:~$ sudo cp Image.new initrd.new /boot/ jetson@reComputerJ2012:~$ cd /boot/extlinux/ jetson@reComputerJ2012:/boot/extlinux$ sudo vi extlinux.conf
--- extlinux.conf.orig 2023-02-07 14:44:23.728124577 +0900 +++ extlinux.conf 2023-02-07 15:20:19.949131799 +0900 @@ -5,6 +5,12 @@ LABEL primary MENU LABEL primary kernel + LINUX /boot/Image.new + INITRD /boot/initrd.new + APPEND ${cbootargs} root=/dev/nvme0n1p1 rw rootwait rootfstype=ext4 console=ttyTCU0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 + +LABEL original + MENU LABEL original kernel LINUX /boot/Image INITRD /boot/initrd APPEND ${cbootargs} root=/dev/nvme0n1p1 rw rootwait rootfstype=ext4 console=ttyTCU0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 ※APPENDの「root=/dev/nvme0n1p1」はルートデバイスとしてM.2 NVMe SSDを利用しているためです。 eMMCを利用している場合には「root=/dev/mmcblk0p1」などにする必要があります。
上記のようにextlinux.confを修正すると通常起動時には「primary kernel」が選択されOverlayFSが有効となった状態(=リードオンリー)で起動します。 シリアルコンソールを接続している場合には、下記のように「primary kernel」と「original kernel」を選択することができ、「original kernel」を選択するとOverlayFSが無効となった状態で起動します。
I> L4T boot options I> [1]: "primary kernel" I> [2]: "original kernel" I> Enter choice:
動作確認
これで作業は完了です。
実機を再起動させるとOverlayFSが有効となりリードオンリー化されて起動します。mountコマンドを実行するとoverlayが有効となっていることが確認できます。
jetson@reComputerJ2012:~$ mount | grep overlay overlayfs-root on / type overlay (rw,relatime,lowerdir=/mnt/lower,upperdir=/mnt/rw/upper,workdir=/mnt/rw/work)
変更履歴
日付 | 変更者 | 変更内容 |
---|---|---|
2023/2/8 | m.nakai | 作成 |