OpenWrt のストレージを Extroot 化する

(公式ガイド:👉 Extroot configuration

今、例として使用している Buffalo WZR-HP-AG300H は、フラッシュストレージのサイズが 32MB であり、Python や gcc などの開発ツールを使おうとするとすぐに容量不足でアプリがインストールできなくなってくる。また、後に判明したことだが、RAM 容量は 128MB で OpenWrt の文書では特に少ないと扱われてはいないものの、pip で Python のモジュールをインストールする処理の中で gcc でのコンパイル作業を伴うような大掛かりな処理が発生すると、128MB では不足して OpenWrt 自体が落ちて(リブートして)しまったことがあるので、Swap メモリーも必要になる。

まず、フラッシュストレージのサイズは、外部 USB ストレージを使い(参考:OpenWrt で外部 USB ストレージを使う)、Extroot 化することで限界を突破できる。そして Swap メモリーについては、Extroot 化したのち、Swap ファイルによって行えばよい。

原理

OpenWrt のファイルシステムは、overlay ファイルシステムという方式が採られている(参考)。パーティションが内部的には

  • rootfs (/rom, compressed, not writable)
  • rootfs_data (/overlay, uncompressed, writable)

から構成されており、論理的には

  • overlay (/, 未修正のファイルは compressed, writable)

システム内に存在する各ファイルを扱うようになっている。

Extroot の場合、上のような元々の overlay パーティションとは別に、もう一つの overlay パーティションを外部ストレージに用意して使う形にする。Extroot 化前の元々の overlay パーティションにあった内容を全部コピーして使うことで、緊急時には Extroot 化前の状態に戻してフォールバックできる余地を残すためである。

必要なツール等の準備等

公式ガイドによると、ツールのインストールに一定の容量が必要なので、フラッシュ容量が 8MB 未満の場合は、カスタムイメージを作って対処するしかないようだが、僕が今回の例として使用している WZR-HP-AG300H の場合は、32MB じゃるのでこの点については気にしなくてよい。

次の条件として、block コマンドでマウントできる状態であることが条件となり、ファイルシステムは ext2/3/4、f2fs、btrfs、ntfs、ubifs のどれかである必要があるようだ(FAT16/32 は不可)。

僕の場合は、f2fs を使うことにする。公式ガイドの例では、ext4 を使っているので、その点でコマンド内容は f2fs 用に適宜変更してある。


opkg update
opkg install block-mount kmod-fs-f2fs e2fsprogs parted

ここでは block-mount コマンド、f2fs 用のドライバー(この例では kmod-fs-f2fs だが、その人の使おうとするファイルシステムによって異なる)、e2fsprogs、parted をインストールして用意している。

外部 USB ストレージのパーティショニング

先程インストールした parted コマンドを使って、早速、用意した外部 USB ストレージ(ここでは /dev/sda とする)を Extroot 用にパーティショニングする(当然、既存のデータは既存のパーティショニングもろとも消去される)。

parted -s /dev/sda -- mklabel gpt mkpart extroot 2048s -2048s
-s (--script)
非対話モード
--
コマンド中で使用している -2048s の - が不正なコマンドラインオプションと扱われないためのもの
mklabel gpt mkpart extroot 2048s -2048s
対話モードで選択する内容をコマンドとして指定している
mklabel gpt
GPT (GUID Partition Table) 形式のパーティションテーブルの新規作成
mkpart extroot 2048s -2048s
GPT に extroot 名でパーティションを作成。
2048セクター目から開始し、後ろから 2048 セクター目で終了する範囲をパーティションとして確保する

このコマンドの実行結果は、特に何も出力されない。以上までが準備作業となる。

rootfs_data の設定変更

この作業により、元々 rootfs_data として /overlay にマウントされていたルーターのフラッシュの領域を、/rwm にマウントするようにして、Extroot 化後に設定変更を行うなどする際に、必要であれば元々の /overlay にもアクセスできる道を残してしておく。


DEVICE="$(block info | sed -n -e '/MOUNT="\S*\/overlay"/s/:\s.*$//p')"
echo $DEVICE
/dev/mtdblock8

echo 以下のコマンドとその出力(/dev/mtblock8)は確認のためのもので余計だが、今回の例ではフラッシュの /dev/mtblock8 が、元々の /overlay としてマウントされていたことがわかる。block info と sed コマンドの組み合わせで抽出したそれをシェルの DEVICE 変数に格納して、次の uci コマンドを使った作業で使おうとしている。


uci -q delete fstab.rwm
uci set fstab.rwm="mount"
uci set fstab.rwm.device="${DEVICE}"
uci set fstab.rwm.target="/rwm"
uci commit fstab

block コマンドは二重にマウントすることはないので、現状では /dev/mtblock8 は /overlay にマウントされているから、この設定がすぐに反映されて /rwm にマウントされるようなことはない。後に Extroot 設定が終ってから再起動をすると、外部 USB ストレージに用意した extroot の方が /overlay としてマウントされるから、その時には /dev/mtblock8 を /rwm にマウントするこの設定が有効に機能する。後になってから Extroot を無効化したくなった場合には /rwm/upper/etc/config/fstab からブート設定にアクセスしていじればよい。

Extroot の設定

改めて block info で、ストレージの一覧を確認して、外部 USB ストレージを特定する:


block info
/dev/mtdblock1: TYPE="jffs2"
/dev/mtdblock7: UUID="f2a55d6e-309946aa-bb072152-6d7a44ae" VERSION="4.0" MOUNT="/rom" TYPE="squashfs"
/dev/mtdblock8: MOUNT="/overlay" TYPE="jffs2"
/dev/sda1: UUID="c42949b9-6c3a-4530-b937-0cd575d986a7" VERSION="1.14" TYPE="f2fs"

/dev/mtblock* はルーターのフラッシュだから、/dev/sda1 が外部 USB ストレージであることを確認できる。もし、/dev/sda1 が未フォーマットの状態だと何も表示されないので、その場合は ls -l /dev/sd* で sda1 が存在することを確認してもいい。

確認できたら、改めて、シェルの DEVICE 変数に /dev/sda1 を手動でセットし直してから……


DEVICE="/dev/sda1"

以下のフォーマット作業を行う。ここでは f2fs ファイルシステムを選んでいるので、予め f2fs-tools をインストール(opkg install f2fs-tools)しておく必要がある(ちなみに、mkfs.f2fs コマンドの場合、label オプションは -L ではなくて -l であった)。


mkfs.f2fs -l extroot ${DEVICE}

	F2FS-tools: mkfs.f2fs Ver: 1.14.0 (2020-08-24)

Info: Disable heap-based policy
Info: Debug level = 0
Info: Label = extroot
Info: Trim is enabled
Info: [/dev/sda1] Disk Model: Storage Media   
Info: Segments per section = 1
Info: Sections per zone = 1
Info: sector size = 512
Info: total sectors = 3911681 (1910 MB)
Info: zone aligned segment0 blkaddr: 512
Info: format version with
  "Linux version 5.10.176 (builder@buildhost) (mips-openwrt-linux-musl-gcc (OpenWrt GCC 11.2.0 r20134-5f15225c1e) 11.2.0, GNU ld (GNU Binutils) 2.37) #0 Thu Apr 27 20:28:15 2023"
Info: [/dev/sda1] Discarding device
Info: This device doesn't support BLKSECDISCARD
Info: This device doesn't support BLKDISCARD
Info: Overprovision ratio = 4.630%
Info: Overprovision segments = 92 (GC reserved = 51)
Info: format successful

(念のため fsck.f2fs -f /dev/sda1 してもよい)

これでフォーマットされたパーティションが用意できたので、uci コマンドで extroot を /overlay としてマウントする設定を追加する:

eval $(block info ${DEVICE} | grep -o -e 'UUID="\S*"')
eval $(block info | grep -o -e 'MOUNT="\S*/overlay"')
uci -q delete fstab.extroot
uci set fstab.extroot="mount"
uci set fstab.extroot.uuid="${UUID}"
uci set fstab.extroot.target="${MOUNT}"
uci commit fstab
eval $(block info ${DEVICE} | grep -o -e 'UUID="\S*"')
grep -o でマッチ部分のみを取り出しており、取り出した文字列(UUID=)で eval した結果、シェル変数 UUID に値がセットされる(echo $UUID で確認できる)。
eval $(block info | grep -o -e 'MOUNT="\S*/overlay"')
上の場合と同様に、取り出した文字列(MOUNT=)で eval した結果、シェル変数 MOUNT に値がセットされる(echo $MOUNT で確認できる)。

現状の overlay パーティションの内容を extroot に全てコピーする

今回の例において、DEVICE = /dev/sda1、MOUNT = /overlay がそれぞれ値としてセットされている。


mount ${DEVICE} /mnt

まず、外部 USB ストレージを /mnt にマウントし……


tar -C ${MOUNT} -cvf - . | tar -C /mnt -xf -

tar コマンドで、現状の overlay パーティションの内容をマウントした外部 USB ストレージ(extroot パーティション)に全てコピーする。

-C
Directory
-c
create
-v
verbose
-f Archive
指定された Archive 変数が - であれば、tar コマンドは標準出力に書き出すか、または標準入力から読み込む。標準出力に書き出す場合は、-c フラグを使用しなければならない。
-x
File パラメーターを指定しないと、 tar コマンドはすべてのファイルをアーカイブから取り出します。

つまり、現行(現在のブート状態で)の /overlay(-C ${MOUNT})の内容すべて(.)を tar 化し(-c)て標準出力に出力し(-cf -)、パイプ(|)で次の tar コマンドにリレーして読み出し(-xf -)て /mnt に解凍(-C /mnt)する。


reboot

リブートすると、次のブート以降は uci で行った fstab の変更された設定内容を反映して /mnt(外部ストレージ)を /overlay としてマウントするようになる。


確認作業

リブート後、LuCI で以下の 2 つについて確認する。

(1) System > Mount Points で /dev/sda1 が /overlay としてマウントされているのがわかる。

(2) System > Software の Free space が 88% (1.65GiB) に爆増している。

さらに、CUI コマンドでもいつくか確認できる。


grep -e /overlay /etc/mtab
/dev/sda1 /overlay f2fs rw,lazytime,relatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,alloc_mode=reuse,fsync_mode=posix 0 0
overlayfs:/overlay / overlay rw,noatime,lowerdir=/,upperdir=/overlay/upper,workdir=/overlay/work 0 0

(1) grep コマンドで /etc/mtab を抽出しても、/dev/sda1 が /overlay としてマウントされていることを確認できる。


df /overlay /
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1              1953792    218900   1734892  11% /overlay
overlayfs:/overlay     1953792    218900   1734892  11% /

(2) df コマンドで /overlay と / で自由容量を比較して、一致していることを確認する。


block info; uci show fstab; logread | sed -n -e "/- preinit -/,/- init -/p"

(3) このコマンドを実行した結果も、特に問題(“block: extroot: UUID mismatch” error)は発生していなかったことを確認できた。


Opkg リストの保存

デフォルトでは RAM(/var/opkg-lists)に保持しているので、ルーターのリブート時に消失してしまうが、Extroot 化で容量的に余裕ができ、外部ストレージ上のファイル(/usr/lib/opkg/lists)として保存できるようになり、リブートに影響されなくなる。さらに、RAM の空き容量も増やせるので、一挙両得。

やり方は、上のスクリーンショットのように LuCI 上で、System > Software > Configuration で /etc/opkg.conf の該当箇所を /var/opkg-lists → /usr/lib/opkg/lists に変更してから、改めて System > Software > Actions > Update lists する方法と、CUI 上で次のコマンドによって設定を変更する方法とがある(後者の方が手っ取り早いと思う)。


sed -i -e "/^lists_dir\s/s:/var/opkg-lists$:/usr/lib/opkg/lists:" /etc/opkg.conf
opkg update

Swap メモリーの設定

今回の例として使用している WZR-HP-AG300H は RAM 容量が 128MB なので、その 2 倍の 256MB(👉 What's the right amount of swap space for a modern Linux system?)をスワップメモリーとして設定しようと思う。

まず、スワップ用の容量分のサイズの空ファイルを extroot パーティション上に作成(やや時間を要する)した上で、スワップファイル化する。


DIR="$(uci -q get fstab.extroot.target)"
dd if=/dev/zero of=${DIR}/swap bs=1M count=256
256+0 records in
256+0 records out
mkswap ${DIR}/swap
Setting up swapspace version 1, size = 268431360 bytes

用意したスワップファイルを fstab に登録し、fstab をリブートする。


uci -q delete fstab.swap
uci set fstab.swap="swap"
uci set fstab.swap.device="${DIR}/swap"
uci commit fstab
service fstab boot

スワップが有効になっているかを確認する:


cat /proc/swaps
Filename				Type		Size		Used	Priority
/overlay/swap                           file		262140		0	-2

LuCI のステータス概観でも、スワップが機能しているのがわかる:

コメント

このブログの人気の投稿

清水俊史『上座部仏教における聖典論の研究』

シークエンスパパともの先見の明

シークエンスパパとも 本物の霊能力