レベル: 中級 M. Tim Jones, Consultant Engineer, Emulex
2006年 07月 31日 Linux® 初期 RAM ディスク (initrd) は、2 段階のブート・プロセスをサポートするためにシステムのブート中にマウントされる一時ルート・ファイル・システムです。initrd
には、実際のルート・ファイル・システムをマウントするための各種実行可能ファイルとドライバーが含まれています。実際のルート・ファイル・システムがマウントされると、initrd
RAM ディスクはアンマウントされ、そのメモリーが解放されます。一方、多くの組み込み
Linux システムでは initrd が最終ルート・ファイル・システムとなります。この記事では、Linux
2.6 の初期 RAM ディスクについて、Linux カーネルで初期 RAM ディスクを作成および使用する方法とあわせて説明します。
初期 RAM ディスクとは何か
初期 RAM ディスク (initrd) とは、実際のルート・ファイル・システムが使用できるようになる前にマウントされる初期ルート・ファイル・システムのことです。initrd
はカーネルにバインドされ、カーネル・ブート・プロシージャーの一部としてロードされます。initrd
がロードされると、カーネルはこれを、実際のファイル・システムを使用可能にするためのモジュールのロード、そして実際のルート・ファイル・システムの取得という
2 段階ブート・プロセスの一部としてマウントします。
initrd には、上記の内容を実行するためのディレクトリーと実行可能ファイル
(カーネル・モジュールをカーネルにインストールするための insmod ツールなど)
の最小限のセットが含まれています。
デスクトップまたはサーバー Linux システムでは、initrd は一時ファイル・システムとなります。その寿命は短く、実際のルート・ファイル・システムへの橋渡しとしてのみ機能します。一方、可変ストレージがない組み込みシステムでは、initrd
は固定ルート・ファイル・システムとなります。この記事では、両方のコンテキストを検討します。
initrd の構造
initrd イメージには、Linux システムの第2 段階のブートをサポートするために必要な実行可能ファイルとシステム・ファイルが含まれています。
実行している Linux のバージョンによって、初期 RAM ディスクの作成方法は異なります。Fedora Core 3 より前のバージョンでは、initrd はループ・デバイスを使用して作成されます。ループ・デバイスとは、ファイルをブロック・デバイスとしてマウントしてから、そのファイルが表すファイル・システムを解釈することができるデバイス・ドライバーのことです。ループ・デバイスはご使用のカーネルに表示されていない場合がありますが、Device Drivers > Block Devices > Loopback Device Support を選択して、カーネルの構成ツール (make menuconfig) によって有効にすることができます。ループ・デバイスは、以下のようにして調べることができます (ご使用の initrd ファイル名は異なる場合があります)。
リスト 1. initrd の検査 (FC3 より前の場合)
# mkdir temp ; cd temp
# cp /boot/initrd.img.gz .
# gunzip initrd.img.gz
# mount -t ext -o loop initrd.img /mnt/initrd
# ls -la /mnt/initrd
#
|
上記のコマンドによって、/mnt/initrd サブディレクトリーの initrd のコンテンツを調べることができます。initrd
イメージ・ファイルは圧縮ファイルなので、ファイル名が .gz という拡張子で終わっていない場合は
.gz を追加すれば解凍できます。
Fedora Core 3 以降からは、デフォルトの initrd イメージは圧縮済み cpio アーカイブ・ファイルとなっています。ループ・デバイスを使ってファイルを圧縮イメージとしてマウントする代わりに、cpio
アーカイブを使用できます。cpio アーカイブのコンテンツを調べるには、次のコマンドを使用します。
リスト 2. initrd の検査 (FC3 以降の場合)
# mkdir temp ; cd temp
# cp /boot/initrd-2.6.14.2.img initrd-2.6.14.2.img.gz
# gunzip initrd-2.6.14.2.img.gz
# cpio -i --make-directories < initrd-2.6.14.2.img
#
|
上記のコマンドを実行した結果が、リスト 3 に示した小さいルート・ファイル・システムです。./bin
ディレクトリーには、nash (シェルではないスクリプト・インタープリター)、カーネル・モジュールをロードする
insmod、そして lvm (論理ボリューム・マネージャー・ツール) をはじめ、小さいながらも必要な一連のアプリケーションがあります。
リスト 3. デフォルトの Linux initrd ディレクトリー構造
# ls -la
#
drwxr-xr-x 10 root root 4096 May 7 02:48 .
drwxr-x--- 15 root root 4096 May 7 00:54 ..
drwxr-xr-x 2 root root 4096 May 7 02:48 bin
drwxr-xr-x 2 root root 4096 May 7 02:48 dev
drwxr-xr-x 4 root root 4096 May 7 02:48 etc
-rwxr-xr-x 1 root root 812 May 7 02:48 init
-rw-r--r-- 1 root root 1723392 May 7 02:45 initrd-2.6.14.2.img
drwxr-xr-x 2 root root 4096 May 7 02:48 lib
drwxr-xr-x 2 root root 4096 May 7 02:48 loopfs
drwxr-xr-x 2 root root 4096 May 7 02:48 proc
lrwxrwxrwx 1 root root 3 May 7 02:48 sbin -> bin
drwxr-xr-x 2 root root 4096 May 7 02:48 sys
drwxr-xr-x 2 root root 4096 May 7 02:48 sysroot
#
|
リスト 3 で注目に値するのは、ルートにある init ファイルです。このファイルは、従来の
Linux ブート・プロセスと同様、initrd イメージが RAM ディスクに解凍されると呼び出されます。これについては、この記事で後述します。
initrd を作成するためのツール
 |
cpio コマンド
cpio ファイルを操作するには、cpio コマンドを使用します。cpio はまた、ヘッダーを持つファイルを単に連結したファイル形式でしかありません。cpio
ファイル形式では、ASCII とバイナリー・ファイルの両方を使用できます。移植性に重点を置くには、ASCII
ファイルを使用します。一方ファイル・サイズを小さくするには、バイナリー・ファイルを使用します。
|
|
ここで初めの話題に戻って、そもそも initrd イメージはどのように作成されるかをきちんと説明しましょう。従来の
Linux システムでは、initrd イメージは Linux のビルド・プロセス中に作成されます。実際のルート・ファイル・システムへの橋渡しに必要なライブラリーとモジュールを備えた
initrd を自動的に作成するには、多数のツールを使用できます。その 1 つが、mkinitrd
です。mkinitrd ユーティリティーは実際にはシェル・スクリプトであるため、どのようにしてその結果を実現しているかは、明確に分かります。また、YAIRD
(Yet Another Mkinitrd) というユーティリティーもあり、これは initrd 作成のあらゆる面をカスタマイズできます。
カスタム初期 RAM ディスクを手動でビルドする
Linux ベースの組み込みシステムの多くにはハード・ドライブがないため、initrd
は固定ルート・ファイル・システムとしても機能します。リスト 4 に、initrd
イメージの作成方法を示します。ここでは標準 Linux デスクトップを使っているため、組み込みターゲットがなくてもこの方法を適用できます。クロスコンパイルを除けば、組み込みターゲットの場合と同じコンセプトです
(initrd 作成に適用する場合)。
リスト 4. カスタム initrd を作成するためのユーティリティー (mkird)
#!/bin/bash
# Housekeeping...
rm -f /tmp/ramdisk.img
rm -f /tmp/ramdisk.img.gz
# Ramdisk Constants
RDSIZE=4000
BLKSIZE=1024
# Create an empty ramdisk image
dd if=/dev/zero of=/tmp/ramdisk.img bs=$BLKSIZE count=$RDSIZE
# Make it an ext2 mountable file system
/sbin/mke2fs -F -m 0 -b $BLKSIZE /tmp/ramdisk.img $RDSIZE
# Mount it so that we can populate
mount /tmp/ramdisk.img /mnt/initrd -t ext2 -o loop=/dev/loop0
# Populate the filesystem (subdirectories)
mkdir /mnt/initrd/bin
mkdir /mnt/initrd/sys
mkdir /mnt/initrd/dev
mkdir /mnt/initrd/proc
# Grab busybox and create the symbolic links
pushd /mnt/initrd/bin
cp /usr/local/src/busybox-1.1.1/busybox .
ln -s busybox ash
ln -s busybox mount
ln -s busybox echo
ln -s busybox ls
ln -s busybox cat
ln -s busybox ps
ln -s busybox dmesg
ln -s busybox sysctl
popd
# Grab the necessary dev files
cp -a /dev/console /mnt/initrd/dev
cp -a /dev/ramdisk /mnt/initrd/dev
cp -a /dev/ram0 /mnt/initrd/dev
cp -a /dev/null /mnt/initrd/dev
cp -a /dev/tty1 /mnt/initrd/dev
cp -a /dev/tty2 /mnt/initrd/dev
# Equate sbin with bin
pushd /mnt/initrd
ln -s bin sbin
popd
# Create the init file
cat >> /mnt/initrd/linuxrc << EOF
#!/bin/ash
echo
echo "Simple initrd is active"
echo
mount -t proc /proc /proc
mount -t sysfs none /sys
/bin/ash --login
EOF
chmod +x /mnt/initrd/linuxrc
# Finish up...
umount /mnt/initrd
gzip -9 /tmp/ramdisk.img
cp /tmp/ramdisk.img.gz /boot/ramdisk.img.gz
|
 |
initrd の Linux 配布
initrd に収まる Linux 配布になるように設計された注目すべきオープン・ソース・プロジェクトは、Minimax
です。サイズは 32MB で、BusyBox と uClibc を使用してこの超小型サイズを実現しています。その小さなサイズにも関わらず、便利なツールを豊富に揃えた
2.6 Linux カーネルとなっています。
|
|
initrd を作成するにはまず、空のファイルを作成するところから始めます。これには、ramdisk.img
ファイルに書き込む入力として、/dev/zero (ゼロのストリーム) を使います。その結果、ファイルのサイズは
4MB (4000個 の 1K ブロック) になります。次に、mke2fs コマンドで、この空のファイルを使って
ext2 (2 番目の拡張) ファイル・システムを作成します。この ext2 ファイル・システムを、ループ・デバイスを使って
/mnt/initrd にマウントします。マウント・ポイントに、initrd 用のデータを読み込むことが可能な
ext2 ファイル・システムを表すディレクトリーが作成されます。スクリプトの残りの大部分は、この機能を実行します。
次のステップは、ルート・ファイル・システムを構成するために必要なサブディレクトリー、/bin、/sys、/dev、そして
/proc の作成です。必要となるのはほんの少数ですが (例えば、ライブラリーは存在しません)、これらのサブディレクトリーにはかなり多くの機能が含まれます。
 |
ext2 ファイル・システムの代わりとなるもの
ext2 は一般的な Linux ファイル・システム形式ですが、他にも initrd イメージやその結果マウントされるファイル・システムのサイズを減らすことのできる形式があります。その例として、romfs
(ROM ファイル・システム)、cramfs (圧縮 ROM ファイル・システム)、squashfs
(高圧縮読取専用ファイル・システム) などがあります。データを一時的にファイル・システムに書き込むのであれば、ext2
で十分間に合います。ext2 ファイル・システム・ドライバーの拡張としては、オンライン圧縮をサポートする
e2compr が登場しています。
|
|
ルート・ファイル・システムを有用なものにするため、BusyBox を使いします。このユーティリティーは単一のイメージで、Linux
システムに含まれることの多い個別ユーティリティーが多数含まれています (awk、sed、insmod
など)。BusyBox の利点は、多くのユーティリティーを 1 つにパッケージ化し、それぞれの共通エレメントを共用することで、イメージのサイズを大幅に削減することです。組み込みシステムにとってはまさに理想的です。BusyBox
イメージをソース・ディレクトリーから、/bin ディレクトリーのルートにコピーしてください。これにより、BusyBox
ユーティリティーの場所を示す多数のシンボリック・リンクが作成されます。BusyBox
は、どのユーティリティーが呼び出されたかを認識し、その機能を実行します。/bin
ディレクトリーには、init スクリプトをサポートするための少数のリンクのセットが作成されます
(それぞれのコマンド・リンクは BusyBox の場所を示します)。
次のステップは、少数の特殊デバイス・ファイルを作成することです。ここでは、ファイル属性を維持するために、-a
オプション (アーカイブ) を使用して現在の /dev サブディレクトリーからファイルを直接コピーします。
最後から 2 番目のステップは、linuxrc ファイルを生成することです。カーネルは
RAM ディスクをマウントした後、実行する init ファイルを検索します。init
ファイルが見つからない場合、カーネルは linuxrc ファイルを起動スクリプトとして呼び出します。linuxrc
ファイルでは、基本的な環境のセットアップを行います。例えば、/proc ファイル・システムをマウントするなどです。ここでは
/proc の他、/sys ファイル・システムもマウントしてメッセージをコンソールに送っています。最後に、ルート・ファイル・システムの操作を可能にするため、ash
(Bourne シェル・クローン) を呼び出します。これにより、linuxrc ファイルが
chmod によって実行可能になります。
これで、ルート・ファイル・システムの完成です。ルート・ファイル・システムはアンマウントされてから、gzip
で圧縮されます。圧縮されたファイル (ramdisk.img.gz) は /boot サブディレクトリーにコピーされるため、GNU
GRUB によってロードできます。
初期 RAM ディクスをビルドするには、単に mkird を呼び出すだけです。これでイメージが自動的に作成され、/boot
にコピーされます。
カスタム初期 RAM ディスクをテストする
 |
Linux カーネルでの initrd サポート
Linux カーネルで初期 RAM ディスクをサポートするには、カーネルを CONFIG_BLK_DEV_RAM
および CONFIG_BLK_DEV_INITRD オプションでコンパイルする必要があります。
|
|
新しい initrd イメージは /boot に配置されました。次に行うステップは、これをデフォルト・カーネルでテストすることです。まず、Linux
システムを再起動してください。GRUB が表示されたら、C キーを押して GRUB
内でコマンド行ユーティリティーを使えるようにします。これで、GRUB と対話して、ロードする特定のカーネルと
initrd イメージを定義できます。kernel コマンドでカーネル・ファイルを定義し、initrd
コマンドで特定の initrd イメージ・ファイルを指定します。定義し終わったら、リスト
5 に示すように boot コマンドでカーネルをブートします。
リスト 5. GRUB を使ったカーネルと initrd の手動ブート
GNU GRUB version 0.95 (638K lower / 97216K upper memory)
[ Minimal BASH-like line editing is supported. For the first word, TAB
lists possible command completions. Anywhere else TAB lists the possible
completions of a device/filename. ESC at any time exits.]
grub> kernel /bzImage-2.6.1
[Linux-bzImage, setup=0x1400, size=0x29672e]
grub> initrd /ramdisk.img.gz
[Linux-initrd @ 0x5f2a000, 0xb5108 bytes]
grub> boot
Uncompressing Linux... OK, booting the kernel.
|
カーネルが起動すると、initrd イメージが使用可能かどうかのチェックが行われ
(後で詳細を説明)、イメージがルート・ファイル・システムとしてロードされ、マウントされます。リスト
6 に、この特定の Linux 起動の終わりを示します。ash シェルが起動すると、コマンドの入力が可能になります。この例では、ルート・ファイル・システムを探索し、仮想
proc ファイル・システムのエントリーを問い合わせています。また、ファイルの
touch を実行 (その結果、ファイルを作成) することによって、ファイル・システムへの書き込みが可能なことも示しています。ここで注意しなければならないのは、作成される最初のプロセスは
linuxrc (一般の init) であるという点です。
リスト 6. 単純な initrd による Linux カーネルのブート
...
md: Autodetecting RAID arrays
md: autorun
md: ... autorun DONE.
RAMDISK: Compressed image found at block 0
VFS: Mounted root (ext2 file system).
Freeing unused kernel memory: 208k freed
/ $ ls
bin etc linuxrc proc sys
dev lib lost+found sbin
/ $ cat /proc/1/cmdline
/bin/ash/linuxrc
/ $ cd bin
/bin $ ls
ash cat echo mount sysctl
busybox dmesg ls ps
/bin $ touch zfile
/bin $ ls
ash cat echo mount sysctl
busybox dmesg ls ps zfile
|
初期 RAM ディスクを使ってブートする
ここまでのところで、カスタム初期 RAM ディスクをビルドして使用する方法を見てきたので、このセクションではカーネルが
initrd をルート・ファイル・システムとして識別してマウントする方法を検討します。ブート・チェーンの主要な機能をいくつか紹介し、その実行内容について説明します。
GRUB などのブート・ローダーは、ロード対象のカーネルを識別し、そのカーネル・イメージと関連
initrd をメモリーにコピーします。この機能のほとんどは、Linux カーネル・ソース・ディレクトリーの
./init サブディレクトリーにあります。
カーネルと initrd イメージが解凍されてメモリーにコピーされると、カーネルが呼び出されます。さまざまな初期化が実行され、最終的には
init/main.c:init() (サブディレクトリー/ファイル:関数) に移動されます。この関数は、大量のサブシステム初期化を行います。ここで
init/do_mounts.c:prepare_namespace() が呼び出され、名前空間の作成 (dev
ファイル・システム、RAID、または md、デバイス、そして最終的には initrd
のマウント) に使用されます。initrd のロードは、init/do_mounts_initrd.c:initrd_load()
によって行われます。
initrd_load() 関数は init/do_mounts_rd.c:rd_load_image() を呼び出します。init/do_mounts_rd.c:rd_load_image()
は、init/do_mounts_rd.c:identify_ramdisk_image() を呼び出して、ロードする
RAM ディスク・イメージを決定します。init/do_mounts_rd.c:identify_ramdisk_image()
関数はイメージのマジック・ナンバーをチェックして、それが minux、etc2、romfs、cramfs、または
gzip のどの形式であるかを判断します。initrd_load_image に戻されると、init/do_mounts_rd:crd_load()
が呼び出されます。この関数は RAM ディスク用のスペースを割り当て、CRC (cyclic
redundancy check: 巡回冗長検査) を計算してから RAM ディスク・イメージを解凍してメモリーにロードします。この時点で、initrd
イメージが、マウントに適切なブロック・デバイス内に配置されます。
ブロック・デバイスをルートとしてマウントするには、まず init/do_mounts.c:mount_root()
を呼び出します。これによってルート・デバイスが作成され、次に init/do_mounts.c:mount_block_root()
が呼び出されます。ここから init/do_mounts.c:do_mount_root() が呼び出され、この関数によって
fs/namespace.c:sys_mount() が呼び出されて実際にルート・ファイル・システムがマウントされ、このシステムにディレクトリーが変更されます。ここで、リスト
6 に示されているメッセージ、VFS: Mounted root (ext2 file system) が表示されます。
最後に、init 関数に戻って init/main.c:run_init_process を呼び出します。これによって
execve が呼び出され、init プロセス (この例では、/linuxrc) が開始します。linuxrc
は実行可能ファイルまたはスクリプト (スクリプト・インタープリターが使用できる場合に限り)
のいずれかになります。
リスト 7 に、呼び出される関数の階層を示します。このリストには初期 RAM ディスクのコピーとマウントの際に呼び出される関数すべてが示されているわけではありませんが、全体的な流れを把握できるはずです。
リスト 7. initrd のロードとマウントにおける主要な関数の階層
init/main.c:init
init/do_mounts.c:prepare_namespace
init/do_mounts_initrd.c:initrd_load
init/do_mounts_rd.c:rd_load_image
init/do_mounts_rd.c:identify_ramdisk_image
init/do_mounts_rd.c:crd_load
lib/inflate.c:gunzip
init/do_mounts.c:mount_root
init/do_mounts.c:mount_block_root
init/do_mounts.c:do_mount_root
fs/namespace.c:sys_mount
init/main.c:run_init_process
execve
|
ディスクレス・ブート
組み込みブート・シナリオと同様に、カーネルと RAM ディスク・ルート・ファイル・システムのブートにはローカル・ディスク
(フロッピーや CD-ROM) は必要ありません。DHCP (Dynamic Host Configuration
Protocol) を使えば、IP アドレスやサブネット・マスクなどのネットワーク・パラメーターを識別できます。次に
TFTP (Trivial File Transfer Protocol) を使って、カーネル・イメージと初期
RAM ディスク・イメージをローカル・デバイスに転送できます。Linux カーネルを転送したら、ローカル・イメージ・ブートと同様にこれをブートし、initrd
をマウントすることができます。
initrd をパッケージ化する
組み込みシステムをビルドする際に、initrd イメージのサイズを最小限にするには、いくつかの秘訣があります。まずは、この記事で紹介した
BusyBox を使用することです。BusyBox は数メガバイトのユーティリティーを数百キロバイトにパッケージ化します。
この例では、BusyBox イメージが静的にリンクされているため、ライブラリーは不要です。ただし、標準
C ライブラリー (カスタム・バイナリー用) が必要な場合は、膨大な glibc の他にも選択肢があります。その一つは
uClibc で、これは、容量が限られたシステムを対象とした標準 C ライブラリーの最小化バージョンです。また、dietlib
も容量が限られた環境に理想的なライブラリーです。これらのライブラリーを使った組み込みシステムでは、バイナリーを再コンパイルしなればならなくなることを忘れないでください。つまり、追加の作業が必要となります
(ただし、その価値はあります)。
まとめ
初期 RAM ディスクは当初、一時ルート・ファイル・システムによって、カーネルの最終ルート・ファイル・システムへの移行をサポートするために作成されましたが、この
initrd は、組み込み Linux システムの RAM ディスクにマウントする非永続ファイル・システムとしても役立ちます。
参考文献 学ぶために
製品や技術を入手するために
-
cpio ファイル形式 (現在、Fedora Core initrd イメージ形式としてサポート) には長年の歴史があり、幅広い種類の
UNIX で動作します。
-
ash シェルは Bourne シェル・クローン (ほぼ準拠) で、小さいながらもその役目を果たします。容量が限られた
Linux 組み込みシステムでスクリプト・インタープリターとして使用するには最適です。
-
BusyBox は、次回の組み込み Linux プロジェクトのメモリー要件を抑えるのに最適な方法です。
- initrd イベントのサイズをさらに小さくするには、glibc に代わる C ライブラリー、uClibc や dietlibなどを使用することを検討してください。C++ を使用する場合は、アルファ・バージョンの
uClibc++ ライブラリーをお試しください。
-
Minimax は、initrd イメージに完全に収まる Linux 配布です。
-
Order the SEK for Linux を注文してください。この 2 枚組 DVD セットには、Linux 対応の DB2®、Lotus®、Rational®、Tivoli®、そして
WebSphere® の最新 IBM トライアル・ソフトウェアが収録されています。
- developerWorks から直接ダウンロードできる IBM トライアル・ソフトウェアを使用して、Linux で次の開発プロジェクトを構築してください。
議論するために
著者について  | 
|  | M. Tim Jonesは、埋め込みソフトウェアのエンジニアであり、GNU/Linux Application Programming, AI Application Programming と BSD Sockets Programming from a Multilanguage Perspective の著者でもあります。エンジニアとして経歴は幅広く、静止衛星用のカーネル開発から埋め込みシステム・アーキテクチャー、そしてネットワーク・プロトコル開発まで経験しています。現在はEmulex Corp.のシニア主席エンジニアです。 |
記事の評価
|