ディスクレス (diskless) サーバを多数運用しようとしたときネックとなるのが、 NAS (Network Attached Storage) サーバの性能。 多数のディスクレスサーバを賄え、かつ高信頼な NAS サーバとなると、 どうしても高価なものになりがちであり、 NAS サーバ本体の価格もさることながら、 ディスクが壊れたときの交換体制などの保守運用費用も高くつく。
それでも、多数のハードディスク内蔵サーバ (つまり一般的なサーバ) を 運用して各サーバのディスクを日々交換し続ける (運用台数が多くなると、 毎週のようにどこかのディスクが壊れると言っても過言ではない) よりは、 ディスクを一ヶ所の NAS にまとめたほうがまだ安い、 というわけで NAS/SAN へのシフトは今後も進むだろう。 そもそも CPU やメモリなどとハードディスクとでは、 故障率のケタが違うのだから、 両者の台数を同じように増やせば破綻するのは当たり前。 要は、滅多に故障しないものは増やしてもいいが、 普通に故障するものは増やしてはいけない。 サーバの部品で故障する確率が桁違いに高いのはハードディスクだから、 大規模負荷分散環境においてディスクレス化は論理的必然だろう。
ハードディスクの故障率が高いのは可動部品が多いから、 というわけでハードディスクをフラッシュメモリで 置き換えようとする傾向もあるようだ。 確かに高価な NAS サーバを導入するよりは、 各サーバにフラッシュメモリを搭載する方が安上がりである可能性もある (比較的低容量であれば)。 しかしながら、 以下に述べるように NAS サーバを普通の PC サーバで実現できてしまえば、 ディスクレス化のほうが安いのは当たり前である。 サーバの台数が多くなればなるほど、 各サーバにディスク/フラッシュメモリを必要としない ディスクレス方式の方が有利になる。
とはいえ、 PC サーバの価格に慣れてしまうと、 超高価な専用サーバの世界にはもう戻れない。 そこで、 どうすればサーバ群のディスクレス化を、 低コストで行なうことができるか考えてみる。 そもそもなぜ NAS サーバが高価かと言えば、 高パフォーマンス性と高信頼性を兼ね備えようとするから。 多数のディスクレスサーバにストレージサービスを提供するのだから 高パフォーマンス性は譲れない。 となると犠牲にしてよいのは高信頼性ということになる。
信頼できなくてもよい、 つまり時々ディスクが壊れて、 書込んだはずのデータが失われても良いなら、 そこそこ高性能な PC サーバで用が足りてしまうだろう。 壊れた場合に備えて冗長化しておけば、 高信頼ではないものの、無停止性は達成できる。 もちろんマスターサーバが壊れてスレーブサーバに切り替われば、 マスターサーバにしか書込めなかったデータは失われる。
そんな NAS サーバは使えない、と言われてしまいそうであるが (^^;)、 ディスクに書込むデータで消えては困るデータとは何だろうか? 例えば Web サーバなどでは、 永続化が必要なデータは DB サーバへ書込むのが普通で、 それ以外のデータは消えては困るとは必ずしも言えないのではないか? というか消えては困るデータは DB サーバへ書けばいいのである。
さらに考えを一歩進めて、 ディスクに書込むデータは消えてもよい、 と割りきってしまうことができれば、 NAS サーバにデータを書く必要性すらなくなってしまう。 つまり NAS サーバのディスクを読み込み専用 (Read Only 以下 RO と略記) でマウントし、 書き込みはローカルな読み書き可能な (Read Write 以下 RW と略記) RAM ディスクに対して行なう。 NAS サーバは RO だから 内容が同じ NAS サーバを複数台用意して負荷分散させれば、 高パフォーマンスと故障時のフェールオーバを同時に達成できてしまう。 NAS サーバのクラスタリングが難しいのはデータを書込もうとするからであって、 書込む必要がなければ話は一気に単純になる。
もちろん全く何も書込めない NAS サーバというのはナンセンスだろう。 ここで「書く必要がない」と言っているのは、 アプリケーション実行中にアプリケーションの動作に同期して (つまり動作結果を) 「書く」必要性である。 アプリケーションとは非同期な書込み、 例えば何らかのコンテンツを配信する Web サーバを考えたとき、 あらかじめ大量の「コンテンツ」を NAS サーバへ事前に保存しておく場合や、 あるいは「コンテンツ」を定期的に更新する場合は、 (アプリケーションの動作結果とは無関係な書き込みなので) Web アプリケーションが NAS へ書込む必要はない。
むしろ、 大量の「コンテンツ」を NAS サーバに集中することは、 コンテンツ更新が素早く行なえるというメリットとなる。 多数の Web サーバそれぞれにハードディスクを内蔵して 同じコンテンツをコピーしていては、 コンテンツの更新頻度が上がってくると 全 Web サーバの内容を同期させるのが難しくなってくるからだ。
ここで重要なのは、 上記「RO NAS サーバ + RW ローカル RAM ディスク」が、 ディスクレスサーバ上で動くソフトウェア (例えば Web アプリケーションやミドルウェア) から見ると、 普通の RW ローカルディスク (つまり普通に書込み可能なハードディスク) に見えなければならないという点である。 もしソフトウェア側で特別な対応が必要だと、 ソフトウェアの改修コストがかかってしまう。 ハードウェアのコストを下げようとして ソフトウェアのコストが上がってしまっては本末転倒である。 ディスク上のデータが RO な NAS サーバから読み込まれたものであり、 ディスクへ書込んだデータが、実は RAM ディスクに書込んだだけで、 再起動によって消えてしまうものであったとしても、 ソフトウェアから見れば、 普通の RW ハードディスクディスクのように 振る舞わなければならないのである。
このように、
複数のディスク (RO NAS と RW RAM ディスク) を重ねて
一つのディスクとして見せる仕掛けを、
重ね合わせ可能な統合ファイルシステム (Stackable Unification File System)
と呼ぶ。
Linux 2.6.20 以降の場合、
二種類の統合ファイルシステムが利用可能である。
後発の Aufs (Another Unionfs) を利用して、
ディスクレスサーバを作ってみた。
(あいかわらず) 前フリが長いが (^^;)、ここからが本題である。
まず、Aufs のページの手順に従い、 CVS からダウンロードして make すると、 Linux モジュール aufs.ko ができる。
senri:/usr/src % mkdir aufs.wcvs senri:/usr/src % cd aufs.wcvs senri:/usr/src/aufs.wcvs % cvs -d:pserver:anonymous@aufs.cvs.sourceforge.net:/cvsroot/aufs login Logging in to :pserver:anonymous@aufs.cvs.sourceforge.net:2401/cvsroot/aufs CVS password:(改行) senri:/usr/src/aufs.wcvs % cvs -z3 -d:pserver:anonymous@aufs.cvs.sourceforge.net:/cvsroot/aufs co aufs cvs checkout: Updating aufs U aufs/COPYING U aufs/History U aufs/Kconfig.in U aufs/README U aufs/ksize.patch U aufs/lhash-2.6.22.patch U aufs/lhash.patch U aufs/local.mk ...(中略)... U aufs/util/fsck.aufs U aufs/util/mount.aufs U aufs/util/umount.aufs senri:/usr/src/aufs.wcvs % cd aufs senri:/usr/src/aufs.wcvs/aufs % make KDIR=/usr/src/linux-2.6.20.19 -f local.mk make -C /usr/src/linux-2.6.20.19 M=/usr/src/aufs.wcvs/aufs/fs/aufs modules make[1]: Entering directory `/usr/src/linux-2.6.20.19' make -C /usr/src/linux-2.6.20.19 O=/usr/src/linux-2.6.20.19 modules CC [M] /usr/src/aufs.wcvs/aufs/fs/aufs/module.o CC [M] /usr/src/aufs.wcvs/aufs/fs/aufs/super.o CC [M] /usr/src/aufs.wcvs/aufs/fs/aufs/sbinfo.o CC [M] /usr/src/aufs.wcvs/aufs/fs/aufs/xino.o ...(中略)... make[1]: Leaving directory `/usr/src/aufs.wcvs/aufs/util' ln -s util/aufs.5 aufs.5 ln -s util/aufind.sh aufind.sh test -x util/mount.aufs || chmod a+x util/mount.aufs ln -s util/mount.aufs mount.aufs ln -s util/auplink auplink ln -s util/aulchown aulchown ln -s util/umount.aufs umount.aufs senri:/usr/src/aufs.wcvs/aufs %
できた aufs.ko を /lib/modules/2.6.20.19 下にコピーして (2.6.20.19 は上の実行例におけるカーネルのバージョン) depmod を実行すれば、 aufs を使ってみることができる。
senri:/usr/src/aufs.wcvs/aufs # mkdir /lib/modules/2.6.20.19/kernel/fs/aufs senri:/usr/src/aufs.wcvs/aufs # cp aufs.ko /lib/modules/2.6.20.19/kernel/fs/aufs/ senri:/usr/src/aufs.wcvs/aufs # depmod -a
試しに使ってみる。 RO ディレクトリ /boot の「上」に、 RW ディレクトリ /tmp/rw を「重ねて」、 /mnt へマウントする。 すると、/mnt には /boot 下と同じファイル群が現われる。
senri:/ # mkdir /tmp/rw senri:/ # mount -t aufs -o br:/tmp/rw:/boot=ro none /mnt senri:/ # ls -lt /mnt total 6928 -rw-r--r-- 1 root root 1733404 Sep 9 20:47 initz-2.6.20.19 -rw-r--r-- 1 root root 1202608 Sep 9 16:20 linuz-2.6.20.19 -rw-r--r-- 1 root root 1513158 Sep 8 10:09 initz-2.6.22.6-co-0.8.0 -rw-r--r-- 1 root root 2613070 Sep 8 10:04 linux-2.6.22.6-co-0.8.0 drwxr-xr-x 2 root root 2048 Apr 8 11:53 grub
「mv /mnt/grub /mnt/grub2」などと /mnt に変更を加えても、 元のディレクトリ /boot は RO なので変化せず、 変更は /tmp/rw に対して行なわれる。
senri:/ # mv /mnt/grub /mnt/grub2 senri:/ # ls -lt /mnt /boot /mnt: total 6928 -rw-r--r-- 1 root root 1733404 Sep 9 20:47 initz-2.6.20.19 -rw-r--r-- 1 root root 1202608 Sep 9 16:20 linuz-2.6.20.19 -rw-r--r-- 1 root root 1513158 Sep 8 10:09 initz-2.6.22.6-co-0.8.0 -rw-r--r-- 1 root root 2613070 Sep 8 10:04 linux-2.6.22.6-co-0.8.0 drwxr-xr-x 2 root root 2048 Apr 8 11:53 grub2 /boot: total 6928 -rw-r--r-- 1 root root 1733404 Sep 9 20:47 initz-2.6.20.19 -rw-r--r-- 1 root root 1202608 Sep 9 16:20 linuz-2.6.20.19 -rw-r--r-- 1 root root 1513158 Sep 8 10:09 initz-2.6.22.6-co-0.8.0 -rw-r--r-- 1 root root 2613070 Sep 8 10:04 linux-2.6.22.6-co-0.8.0 drwxr-xr-x 2 root root 2048 Apr 8 11:53 grub senri:/ # ls -lta /tmp/rw total 8 drwxr-xr-x 4 root root 2048 Sep 15 16:42 . drwxrwxrwt 29 root root 2048 Sep 15 16:41 .. -r--r--r-- 2 root root 0 Sep 15 16:10 .wh..wh.aufs drwx------ 2 root root 2048 Sep 15 16:10 .wh..wh.plink -r--r--r-- 2 root root 0 Sep 15 16:10 .wh.grub drwxr-xr-x 2 root root 2048 Apr 8 11:53 grub2
「/tmp/rw/.wh.名前」というファイルは、 「/mnt/名前」が削除されたことを示し、 「.wh.」から始まらないファイル/ディレクトリは、 そのまま「/mnt」に現われる。 上の例で言うと、 「mv /mnt/grub /mnt/grub2」という変更を行なったことにより、 「/tmp/rw/.wh.grub」というファイルが作られて「/mnt/grub」が見えなくなり、 「/tmp/rw/grub2」というディレクトリが作られて「/mnt/grub2」が現われた。
ちなみに、「.wh.」から始まるファイルを作ろうとすると、
senri:/ # touch /mnt/.wh.grub3 touch: setting times of `/mnt/.wh.grub3': Operation not permitted
などと、エラーになる。
では次に、NFS マウントしたディレクトリの上に重ねあわせを行なってみる。 残念なことに現在の Linux カーネルのパス名ルックアップ関数 lookup_one_len には、 少々問題があるらしい。 この関数は引数のファイル名からハッシュ値を算出し、 ファイルシステムのハッシュリストを検索して、 ファイル名に対応する dentry 構造体を返すのであるが、 その際、そのファイルに至るディレクトリの dentry 構造体の参照カウンタを +1 してしまう。 この挙動が NFS に混乱をもたらす (らしい ^^;)。
NFS に影響を及ぼさない形で参照カウンタを元に戻すには、 nameidata 構造体を独自に設定した上でルックアップを行なう必要があるが、 現在の Linux カーネルにはそのようなインタフェースが無い。 そこで aufs では、 カーネル内の関数を一つ (__lookup_hash 関数) モジュールから呼び出せるようにするべく、 EXPORT_SYMBOL(__lookup_hash) するパッチ (lhash.patch) をあてている。 このパッチをあててカーネルを再構築した後に、 aufs の AUFS_LHASH_PATCH オプションを y に設定すればよい。
senri:/usr/src/linux-2.6.20.19 # patch -p1 < /usr/src/aufs.wcvs/aufs/lhash.patch patching file fs/namei.c patching file include/linux/namei.h
local.mk の「CONFIG_AUFS_LHASH_PATCH」の設定を以下のように「y」に変更し、
再度「make KDIR=/usr/src/linux-2.6.20.19 -f local.mk」を実行して
aufs.ko を作り直す。
CONFIG_AUFS_LHASH_PATCH = y
以上で NFS マウントしたディレクトリの上に、 別のファイルシステムを重ねることが可能になった。 試しに NFS マウントしてみる、といいたいところだが、 Linux 起動時に NFS マウントするには、 まずネットワークを使えるようにしなければならない。 ネットワーク・インタフェース (NIC) の認識は、 「initramfs (initrd) の init を busybox だけで書いてみた」で説明した方法でハードウェアに応じたモジュールを読み込めばよい。 その後「ifconfig eth0 up」を実行して NIC を有効にし、 DHCP クライアント udhcpc (busybox に含まれる) を使って IP アドレスを割当てる。
[ 4.132912] 8139too Fast Ethernet driver 0.9.28 [ 4.133116] ACPI: PCI Interrupt 0000:04:01.0[A] -> GSI 19 (level, low) -> IRQ 19 [ 4.133944] eth0: RealTek RTL8139 at 0xf8858000, 00:0b:97:xx:xx:xx, IRQ 19 [ 4.134062] eth0: Identified 8139 chip type 'RTL-8101' # ifconfig eth0 up [ 11.128281] eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1 # udhcpc udhcpc (v1.7.0) started eth0 Link encap:Ethernet HWaddr 00:0B:97:XX:XX:XX UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:3 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:180 (180.0 B) TX bytes:0 (0.0 B) Interrupt:19 Base address:0x8000 Sending discover... Sending select for 192.168.1.132... Lease of 192.168.1.132 obtained, lease time 172800 # route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
これでネットワークにアクセスできるようになったので、 NFS サーバ 192.168.1.1 の /fs/nfs/puppy ディレクトリを /mnt へ RO マウントし、 その上に RW なディレクトリ /.rw を重ねて、 /.root へマウントしてみる。 NFS マウントオプションとして nolock を指定しているが、 これは aufs では重ね合わせ後のファイルシステムにおいて ファイル・ロック機能をサポートしているため、 重ね合わせ前のファイルシステムにはロック機能が不要という理由による。
ディレクトリ名から想像される通り、 このディレクトリは 1CD Linux の一つ、 Puppy Linux の ルートディレクトリをコピーしたものである。 Puppy Linux を使う必然性は何もなく、 /sbin/init が起動可能なルートディレクトリならなんでもいいのであるが、 手軽に実験してみたいときなど、 1CD Linux のルートディレクトリはサイズがコンパクトなので便利。
# mount -onolock,ro 192.168.1.1:/fs/nfs/puppy /mnt # ls -lt /mnt drwxr-xr-x 21 0 0 4096 Sep 9 21:09 etc drwxrwxrwt 2 0 0 4096 Sep 9 20:39 tmp drwxr-xr-x 25 0 0 4096 Sep 5 22:50 root drwxr-xr-x 11 0 0 4096 Jul 18 03:49 usr drwxr-xr-x 7 0 0 4096 Jul 17 19:50 dev drwxr-xr-x 4 0 0 4096 Jul 17 19:48 lib drwxr-xr-x 2 0 0 4096 Mar 13 2007 bin drwxr-xr-x 2 0 0 4096 Aug 10 2006 sbin drwxr-xr-x 11 0 0 4096 Aug 9 2006 var drwxr-xr-x 11 0 0 4096 Apr 7 2006 mnt drwxr-xr-x 4 0 0 4096 Dec 12 2003 proc # mkdir /.rw /.root # mount -t aufs -o br:/.rw:/mnt=ro none /.root [ 67.794180] aufs 20070820 # mount rootfs on / type rootfs (rw) none on /proc type proc (rw) 192.168.1.1:/fs/nfs/puppy on /mnt type nfs (ro,vers=3,rsize=32768,wsize=32768,hard,nolock,proto=udp,timeo=7,retrans=3,sec=sys,addr=192.168.1.1) none on /.root type aufs (rw,xino=/.rw/.aufs.xino,br:/.rw=rw:/mnt=ro)
これで /.root に Puppy Linux のルートディレクトリが RW な形でマウントできた。 続いて pivot_root を行なって /.root を / へマウントしなおし、 /sbin/init を exec すれば Puppy Linux をブートすることができる。
というわけで、 いよいよ initramfs の /init にて NFS マウントと AUFS の重ねあわせを行なうわけであるが、 一つ問題がある。 initramfs では pivot_root ができない。 initramfs の / (root) は何もマウントしていない状態なので、 /.root と交換 (pivot) できるものが無いのである。
解決策としては二通りあって、 一つは構わず /.root を / へマウントしてしまう方法。 もう一つは、 いったん tmpfs を / へマウントしてから、 NFS と AUFS をマウントし、pivot_root する方法。
initramfs の流儀からすれば、 前者の方法が望ましいかも知れないが、 /.rw や /mnt ディレクトリが見えなくなってしまう (見えない方がいい、というケースもありそうであるが)。 /init スクリプトを書く前に、 実際に手入力で実行してみる:
# cd /.root # mount --move . / # mount rootfs on / type rootfs (rw) none on /proc type proc (rw) 192.168.1.1:/fs/nfs/puppy on /mnt type nfs (ro,vers=3,rsize=32768,wsize=32768,hard,nolock,proto=udp,timeo=7,retrans=3,sec=sys,addr=192.168.1.1) none on / type aufs (rw,xino=/.rw/.aufs.xino,br:/.rw=rw:/mnt=ro) # umount /proc # exec sbin/chroot . bin/sh bin/sh-3.00# mount -t proc none /proc bin/sh-3.00# mount 192.168.1.1:/fs/nfs/puppy on /mnt type nfs (ro,vers=3,rsize=32768,wsize=32768,hard,nolock,proto=udp,timeo=7,retrans=3,sec=sys,addr=192.168.1.1) none on / type aufs (rw,xino=/.rw/.aufs.xino,br:/.rw=rw:/mnt=ro) none on /proc type proc (rw) bin/sh-3.00# ls -la /.rw /mnt ls: /.rw: No such file or directory /mnt: total 40 drwxr-xr-x 11 root root 4096 Apr 7 2006 . drwxr-xr-x 14 root root 0 Sep 15 18:36 .. drwxr-xr-x 2 root root 4096 Apr 22 2003 cdrive drwxr-xr-x 2 root root 4096 Apr 22 2003 cdrom drwxrwxrwt 2 root root 4096 Sep 15 18:12 data drwxr-xr-x 2 root root 4096 Apr 22 2003 flash drwxr-xr-x 2 root root 4096 Apr 22 2003 floppy drwxr-xr-x 2 root root 4096 Sep 21 2004 msdos drwxr-xr-x 2 root root 4096 May 25 2003 ram1 drwxr-xr-x 2 root root 4096 Mar 4 2005 swap drwxr-xr-x 2 root root 4096 Jan 5 2004 zip
/.root ディレクトリへ cd し、 「mount --move . /」を実行することによって、 Puppy Linux のルートディレクトリを / へマウントする。 続いて chroot を exec して / を Puppy Linux のルートディレクトリへ切り替える。 通常であればここで /sbin/init を起動して Puppy Linux に制御を渡すのであるが、 ここでは実験のため /bin/sh を exec した。
ここでマウントポイントを確認してみると、 「192.168.1.1:/fs/nfs/puppy on /mnt」と表示されるが、 NFS マウントした /mnt ディレクトリは見えず、 Puppy Linux の /mnt ディレクトリしか見えない。 もちろん /.rw というディレクトリも存在しない。 chroot したのだから、 旧ルート下のこれらのディレクトリが見えなくなるのは当然であるが、 /.rw などを参照したいケースもあるだろう。 そういうときはもう一つの方法である pivot_root する方法を使う。
すなわち、 initramfs の /init スクリプト の冒頭で、 次のように tmpfs をマウントして initramfs の内容を全て tmpfs へコピーし、 switch_root して再度自分自身 (/init スクリプト) を呼び出せばよい。
if [ -z "$INIT_TMPFS" ]; then mount -t tmpfs none /mnt cd /mnt cp -a `echo /* | sed 's@/mnt @ @'` . mkdir mnt export INIT_TMPFS=1 exec switch_root . /init fi
自分自身を呼び出す前に export INIT_TMPFS=1 することによって、 呼び出しが繰り返されることを防いでいる。 これで / には tmpfs がマウントされる。 mount コマンドで確認してみると、 「none on / type tmpfs (rw)」と表示されるので、 tmpfs が / にマウントできていることが分かる:
# mount rootfs on / type rootfs (rw) none on / type tmpfs (rw) none on /proc type proc (rw)
続いて NFS と /.rw を AUFS で重ねて /.root へマウントした後、 pivot_root する。
# mount -onolock,ro 192.168.1.1:/fs/nfs/puppy /mnt # mkdir /.rw /.root # mount -t aufs -o br:/.rw:/mnt=ro none /.root [ 422.703779] aufs 20070820 # cd /.root # mkdir initrd # pivot_root . initrd # mount -t proc none /proc # mount none on /initrd type tmpfs (rw) 192.168.1.1:/fs/nfs/puppy on /initrd/mnt type nfs (ro,vers=3,rsize=32768,wsize=32768,hard,nolock,proto=udp,timeo=7,retrans=3,sec=sys,addr=192.168.1.1) none on / type aufs (rw,xino=/initrd/.rw/.aufs.xino,br:/initrd/.rw=rw:/initrd/mnt=ro) none on /proc type proc (rw) # ls -la /initrd/.rw total 0 drwxr-xr-x 5 root root 120 Sep 15 19:09 . drwxrwxrwt 17 root root 360 Sep 15 19:07 .. -r--r--r-- 1 root root 0 Sep 15 19:07 .wh..wh.aufs drwx------ 2 root root 40 Sep 15 19:07 .wh..wh.plink drwxr-xr-x 2 root root 60 Sep 15 19:28 etc drwxr-xr-x 2 root root 40 Sep 15 19:09 initrd
pivot_root 実行前の / は、 上記実行例のように /initrd にマウントされるので、 NFS マウントしたディレクトリは /initrd/mnt で見ることができるし、 重ねあわせの RW ディレクトリは /initrd/.rw で見ることができる。
以上の実験結果を踏まえて、 「initramfs (initrd) の init を busybox だけで書いてみた」で書いた /init スクリプトに、 NFS および AUFS をマウントする機能を追加してみた:
#!/bin/ash export PATH="/bin:/sbin:/usr/bin:/usr/sbin" KERNVER="`uname -r`" FILES=`echo /* | sed 's@/mnt @ @'` if [ -n "$AUFS" ]; then if [ -z "$INIT_TMPFS" ]; then mount -t tmpfs none /mnt cd /mnt cp -a $FILES . mkdir mnt export INIT_TMPFS=1 exec switch_root . /init fi fi mount -t proc none /proc ROOTFLAG="ro" INIT="/sbin/init" for p in `cat /proc/cmdline`; do v=`echo $p | sed 's/.*=//'` case $p in root=*) ROOT=$v ;; rootfstype=*) ROOTPARM="-t $v" ;; rootflags=*) ROOTFLAG=$v ;; nfsroot=*) NFSROOT=`echo $v | sed 's/,.*//'` NFSOPTS=`echo $v | sed 's/[^,]*,*//'` NFSPARM='-t nfs' if [ -n "$NFSOPTS" ]; then NFSPARM="$NFSPARM -o $NFSOPTS" unset NFSOPTS fi ;; init=*) INIT=$v ;; esac done unset p v ROOTPARM="$ROOTPARM -o $ROOTFLAG" unset ROOTFLAG hwclock --hctosys mount -t sysfs none /sys for d in /sys/bus/pci/devices/*; do if [ -r $d/vendor -a -r $d/device ]; then read VENDOR < $d/vendor read DEVICE < $d/device pat=`echo "^\([^ ][^ ]*\) *$VENDOR *$DEVICE .*" | sed 's/0x/0x0*/g'` mod=`sed -n "s/$pat/\1/p" /lib/modules/$KERNVER/modules.pcimap` if [ -n "$mod" ]; then for m in $mod; do modprobe $m done fi fi done unset d pat mod m VENDOR DEVICE umount /sys modprobe af_packet modprobe unix modprobe ext3 modprobe xfs if [ -n "$NFSROOT" ]; then ifconfig lo 127.0.0.1 if ifconfig eth0; then ifconfig eth0 up sleep 3 udhcpc --retries=2 mount -t nfs $NFSPARM $NFSROOT /mnt fi elif [ -n "$ROOT" ]; then mount $ROOTPARM $ROOT /mnt fi if [ -n "$INIT_DEBUG" ]; then set exec /bin/sh fi umount /proc if [ -n "$AUFS" ]; then mkdir /.rw /.root mount -t aufs -o br:/.rw:/mnt=ro none /.root cd /.root if [ -n "$INIT_TMPFS" ]; then test -d initrd || mkdir initrd pivot_root . initrd initrd/bin/busybox rm -rf `echo $FILES /.root | sed 's@/@initrd/@g'` exec $INIT else cp -a /bin/busybox . rm -rf $FILES ./busybox mount --move . / exec ./busybox chroot . /bin/sh -c "rm ./busybox; exec $INIT" fi fi exec switch_root /mnt $INIT
ブートパラメータとして「INIT_DEBUG=1」を指定すると、 この /init スクリプトは /sbin/init を起動する代わりに /bin/sh を実行する。 つまり initramfs 環境でコマンドラインの手入力が可能になるので、 /init スクリプトのデバッグに役立つ。 実は前述した実行例は、 このデバッグ環境を利用したものである。
「nfsroot=」で NFS の設定を行なう。 そして「AUFS=1」を指定した場合は RW な tmpfs を重ねてマウントする。 例えば上述の例の、 NFS サーバ 192.168.1.1 の /fs/nfs/puppy ディレクトリをマウントする場合であれば、 次のようにブートパラメータを設定すればよい (pxelinux ブートローダの場合):
label puppy kernel boot/vmlinuz append initrd=boot/initrd.gz AUFS=1 nfsroot=192.168.1.1:/fs/nfs/puppy,ro,nolock root=/dev/nfs
[vfs] lookup_one_len関数
スタッカブルファイルシステムでのlookupに利用する。 普通に下層レイヤのlookup関数を呼び出せばいい気がするけれど、どうも駄目らしい。 static struct dentry *myiop_lookup(struct inode *dir, struct dentr
Comment by fs_n314 — 2008年4月16日 @ 02:32