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 のステータス概観でも、スワップが機能しているのがわかる:
コメント
コメントを投稿