LinuxのROM起動化

動機

突然自宅サーバ兼ディスクトップが応答しなくなりました。帰って原因を 調べると、Disk I/Oエラーです。今後の対策として「なるべく頑丈にしたい」 と考え、これを計画しました。

システム構成の構想

HDDに問題が生じても動作継続可能にすることが目的です。
Media Dir R/W type 説明
CF / ROcramfs基本システム一式
CF /boot ROext2 カーネルおよびgrubの設定ファイルを置く
CF /etc.org ROext2 起動時に使用する標準の設定ファイルを置く。
RAM/etc RWtmpfs 実行中に使用している設定ファイルを置く。起動時に/etc.orgからコピー
RAM/tmp RWtmpfs テンポラリ。起動時は空。
RAM/dev RWtmpfs パーミション書き換えたりするので。
HDD/var RWbind 動作中に変更される不揮発のデータ。
HDD/home RWbind ユーザのデータ。
HDD/usr RWbind 各種プログラム
HDD/lib/moduleRWbind カーネルモジュール。
考察
  1. CFカードは読み込み専用で使用します。理由は書き換え寿命があることです。
  2. 注意点はcramfsが256Mまでしか対応していないことです。ディスクトッ プ目的のシステムは全部は入りません。/usrはHDDにおきます。
  3. 基本的に変更しないものだけcramfsに入れます。理由はcramfsは ReadOnly専用だから。
  4. 変更するもの、かつ動作に必須のものはCFに入れます。具体的には/etc と/bootがこれに該当します。
  5. 変更するもの、かつ揮発性のものはtmpfsにします。/etcはReadOnlyにし たいのですが、ここにデータを置くプログラム (/etc/mtab,/etc/netconfig)があります。
  6. サーバ用途でHDDを長時間とめるため、本来も/varもtmpfsにしたいので すが容量不足で止まるのが怖いのでHDD上にします。
  7. ReadOnlyで書き換える可能性のある部分はext2です。Jurnal機能なんて 無意味ですから。HDD上の不揮発のデータのある部分は、趣味でreiserfs にしています。

圧縮つきファイルシステムの比較

性能は ここを参照。cramfsは圧縮率はやや低めですが、HDDに限定すれば一番速 いようです。これを使用します。

システムs 説明
cramfs 小容量ROM用。読み込み専用。
cloop Knoppixで使われている。読み込み専用。
squashfs cloopを上回る性能?。読み込み専用。
jffs2 MTDと連動するためF-ROM専用。書き込み可能。

起動シーケンス

非常に大雑把ですが
  1. CF上のgrub起動
  2. CF上のカーネルをメモリに読み込み
  3. カーネル実行
    1. HW初期化
    2. initrd読み込み&linuxrc実行
      1. cramfsのカーネルモジュール読み込み
      2. Rootフィアルシステム マウント
      3. bootパーティションをマウント
      4. etc.orgをtmpfs(etc)にコピー
      5. devをtmpfs(dev)にコピー
      6. /mnt以下を作成
      7. tmpfs(tmp)をマウント
      8. Rootファイルシステムとinitrdをswap
      9. /bin/initを実行(以下inittabの内容に従う)

1st step:既存のLinuxを元にUSB起動

最終的にはCF-IDE変換のコネクタを噛ませますが、まずは手持ちの256M CF カードをUSB接続して起動しました。64Mあれば問題ないでしょう。

カードのフォーマット

USBカードリーダに差し込んで、

# fdisk /dev/sda
sda1に10M(/boot)、sda2に10M(/etc)、sda3に残り(/)を割り当てます。
# mkfs.ext2 /dev/sda1
# mkfs.ext2 /dev/sda2

ルートファイルシステム作成

cramfsツール作成

cramfs用のツールをここから落し

$ tar xfvz cramfs-1.1.tar.gz 
$ cd cramfs-1.1
$ make
# cp cramfsck mkcramfs /usr/sbin/

内容作成

動作に最低限必要な物をコピーします。また、マウントポイントを作成します。

$ mkdir TARGET
$ cd TARGET
# cp -a /bin /dev /lib /sbin .
# mkdir -p boot etc etc.org home initrd mnt opt proc root sys tmp usr var
$ cd ..

cramfs作成&書き込み

# mkcramfs TARGET target.cramfs
# cp target.cramfs /dev/sda3 

initrd作成

linuxrc作成

起動に必要な処理を書きます。

#! /bin/sh

load_modules()
{
	insmod /lib/modules/"`uname -r`"/kernel/fs/cramfs/cramfs.ko 
}

mount_root_partition()
{
	while [ -z "`cat /proc/partitions | grep sda3`" ] ; do
		sleep 1;
		echo "Searching root partition"
	done
	mkdir -p /newroot
	mount -t cramfs /dev/sda3 /newroot
}

mount_etc_partition()
{
	mount -t tmpfs tmpfs /newroot/etc
	mount -t ext2 -o ro /dev/sda2 /newroot/etc.org
	cp -a /newroot/etc.org/* /newroot/etc
}

make_dev_partition()
{
	cd /newroot
	tar cf /dev.tar dev
	mount -t tmpfs tmpfs dev
	tar xf /dev.tar
	rm /dev.tar
	cd /
}

make_mnt_partition()
{
	mount -t tmpfs tmpfs /newroot/mnt
	mkdir -p /newroot/mnt/data
	mkdir -p /newroot/mnt/sys
}

mount_tmp_partition()
{
	mount -t tmpfs tmpfs /newroot/tmp
}

mount_boot_partition()
{
	mount -t ext2 -o ro /dev/sda1 /newroot/boot
}

change_root()
{
	cd newroot
	pivot_root . initrd
}

echo "Load Module"
load_modules
mount -t proc proc proc

echo "Mount Root/Boot/Etc/Tmp"
mount_root_partition
mount_boot_partition
mount_etc_partition
mount_tmp_partition

echo "Make Dev/Mnt"
make_dev_partition
make_mnt_partition

echo "Swap Root"
umount /proc
change_root
# mount -t proc proc /newroot/proc

echo "Start init daemon"
exec chroot . /sbin/init < /dev/console > /dev/console 2>&1

Busybox作成

BuxyBoxのページから取得して、解凍。

# cd ~/busybox-1.01
# make menuconfig(static link、insmod、sysctlを有効にする)
# make
#  make install PREFIX=TARGET

initrdに焼き込

# dd count=20480 if=/dev/zero of=initrd
# mkfs.ext2  initrd 
# mount -o loop initrd /mnt/usb2/
# cd /mnt/usb2/
# mkdir -p etc usr var home boot mnt opt proc sys tmp root
# chmod 777 tmp
# chmod 700 root
Busyboxを入れる
# cp -a ~/buxybox-1.01/TARGET/* .
自作のlinuxrcを使用するように設定
# rm linuxrc
# cp ~/linuxrc .
書き込み
# umount /mnt/usb2/
# gzip -9 initrd
# mount /dev/sda1 /mnt/boot
# cp initrd.gz /mnt/boot
# umount /mnt/boot

ブートパーティション作成

カーネル作成

カーネルのコンフィグレーションを変更し、ramdiskをカーネルに組み込み、 initrdを有効にします。また、reiserfs、cramfs、usbなどをモジュール(or組 み込み)にします。モジュールにしたもので起動に必要なものは、initrdの中 にコピーしておきlinuxrcでinsmodしておきます。

カーネル&Grubインストール

# mount /dev/sda1 /mnt/boot
# grub-install --root-directory=/mnt/boot /dev/sda
# cp -a /boot/* /mnt/boot
# cp -a vmlinuz /mnt/boot
# mkdir /mnt/boot/etc
# cp -a /etc/grub.conf /mnt/boot/etc
# vi /mnt/boot/etc/grub.conf
/mnt/boot/etc/grub.confに以下の設定を追加。
title RomBoot

root (hd0,0)
kernel (hd0,0)/vmlinuz rw ramdisk=66000 root=/dev/ram0 init=/linuxrc
initrd (hd0,0)/initrd.gz
# umount /mnt/boot

/etcパーティション作成

# mount /dev/sda2 /mnt/etc
# cp -a /etc/* /mnt/etc
# vi /mnt/etc/fstab
# vi /mnt/etc/rc.d/rc.S

fstabは、Rootをマウントしないようにし、また、linuxrcで操作しないマ ウント(主にbindマウントする物)を追記します。

rc.Sには、initrdのアンマウント&メモリ解放を追記します。

# umount /initrd
# blockdev --flushbufs /dev/ram0

2nd step:CFカードをIDE接続して起動

作成中

参考文献/サイト

goto TOP
このドキュメントはフリーです。
勝手に再配布/変更しても構いません
$Date: 2006/11/07 03:20:40 $
$Revision: 1.1.1.1 $