ジャンル不定の日記です。

/をsquashfsで/etcと/homeだけext2にした

Orange pi R1のSPIフラッシュにOSのせるためにrootfsを圧縮ファイルシステムのsquashfsにした上で書き込みできるようにoverlayfsを使うつもりだったが、
難しくて断念して/etcと/homeだけ書き換えできるようにした。

まずrootfsをoverlayfsにするつもりだったが、
overlayfsは2つ以上のディレクトリを重ねるシステムなので、片方にリードオンリーなsquashfsを使って書き換えできるようにするには2つのファイルシステムを先にマウントする必要がある。
なのでkernel起動パラメータroot=の部分で指定することはできない。

squashfsで起動したあとでoverlayfsをマウントして/を変更する手段として、chroot pivot_root switch_rootを考えたが、
  chroot : 現在のプロセスのみ/を変更する。
  pivot_root : 元の/には別のファイルシステムがマウントされていてはいけない。元の/と新/は別のファイルシステムでなければいけない。
  switch_root : 元の/にあるファイルは全削除される。
らしい。
システム全体を変更したいのでchrootはナシ。
switch_rootは、元の/のファイルが削除されるというのはなんでだろ?マウントポイントがなくなるだけではないの?initramfsで使われることが多いみたいだが一時的なramディスクでないと問題あり?
pivot_rootはなんか制約が多い。新/が別のファイルシステムだと/の下にマウントしなきゃいけないから2つのファイルシステムは必ず存在することになるのでわかりにくい。

まあとりあえず実際にpivot_rootとかswitch_rootを試してみようかと思ったが、起動中のシステムでやろうとしてもエラーでうまく行かなかった。
initrdとinitramfsも試そうとしたが、どうもkernelパラメータからroot=を外すとkernel panicしちゃうんでなにか間違えてる・・・
miZyとかopenWRTは/がoverlayfsだったりするので方法はあるはずだが・・・

というわけでうまく行かなかったのだが、
書き換えが必要なのは /etc と /home だけだよね。
そこをどうにかしようと考えて、rwなパーティションを/mnt/rwにマウントして、その下のディレクトリを/etcと/homeにマウントすることにした。

ディレクトリ作ったりしてる作業中に、rootfsの/etcをrw/etcに全コピーしてして/etcを消すときに気づいたが、
linux起動時は/sbin/initが実行されて、/etc/inittabが処理され、/etc/fstabに記載されたデバイスがマウントされる。
/etc/inittabが別デバイス上じゃ読めないじゃん!

ということで再度悩んだが、
kernel起動パラメータのinit=で/sbin/init以外を指定すればinitプログラムを代えることができる!
と気づいた。

/init.sh
#!/bin/sh
/bin/mount -t proc proc /proc
/bin/mount /dev/mmcblk0p3 /mnt/rw
/bin/mount -o bind /mnt/rw/etc /etc
/bin/mount -o bind /mnt/rw/home /home
exec /sbin/init
kernel起動パラメータで最初に実行するinit。
rwデバイスをマウントして、下にあるetcとhomeを/etcと/homeにbindする。
最初procをマウントしなかったらデバイスのmountができなかった。
マウントしたら本来の/sbin/initを実行。

/etc/inittab (の起動処理の部分)
# Startup the system
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mkdir -p /dev/pts /dev/shm
::sysinit:/bin/mount -a
#::sysinit:/sbin/swapon -a
rootfsの/etcは空にしてるんでrwデバイス側。先に/init.shでbindされるんで/etc/inittabとして扱える。
procのマウントは/init.sh側に移したのでコメントアウト。
メモリは256MBも積んでるがストレージ(SPIフラッシュ)は16MBしかないのでswap要らん。というわけでkernelビルド時に無効にしてるんでswaponもコメントアウトしといた。
/dev/ptsと/dev/shmは最初からあるからmkdirする必要あるのか?思って一旦コメントアウトしたが、/devにdevtmpfsがkernelにマウントされるから無くなるんだね。mkdirしないとエラー出た。
mkdirするには/をrwでremountする必要があるってことみたい。

/etc/fstab
# <file system> <mount pt>      <type>  <options>       <dump>  <pass>
/dev/root       /               ext2    rw,noauto       0       1
proc            /proc           proc    defaults        0       0
devpts          /dev/pts        devpts  defaults,gid=5,mode=620,ptmxmode=0666   0       0
tmpfs           /dev/shm        tmpfs   mode=0777       0       0
tmpfs           /tmp            tmpfs   mode=1777       0       0
tmpfs           /run            tmpfs   mode=0755,nosuid,nodev  0       0
sysfs           /sys            sysfs   defaults        0       0
/dev/mmcblk0p3  /mnt/rw         ext2    rw,noauto       0       0
これもrwデバイス側。
/mnt/rwは手動マウントするんで追加しなくても起動するが、シャットダウン時に自動アンマウントさせるためにnoautoで追加しといた。
これでumountしてくれる?

こんな感じで、/をsquashfsにした上で/etcの変更ができるシステムができた。
# df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/root                 6016      6016         0 100% /
devtmpfs                116652         0    116652   0% /dev
/dev/mmcblk0p3            9911       920      8479  10% /mnt/rw
/dev/mmcblk0p3            9911       920      8479  10% /etc
/dev/mmcblk0p3            9911       920      8479  10% /home
tmpfs                   125356         0    125356   0% /dev/shm
tmpfs                   125356        28    125328   0% /tmp
tmpfs                   125356        24    125332   0% /run
/は6MBになった。
他にboot用のパーティションがzImageとかで頑張っても4MBまでしか削れない。
余裕もたせてboot=6MB,root=8MBで残り2MBくらいか?
と思ったが、どうせ書き込み用のイメージ化しなきゃいけないんだし最適化するスクリプトでも作るか。
そうすると10MBくらいに収まるんで残りのrwは6MBくらい使えるか?