Initrd

初期RAMディスクはLinuxカーネルのブート時に一時的なルートファイルシステムをメモリに読み込むための方式。 真のルートファイルシステムをマウントできるようになる前にファイルシステムを必要とする場面で使用される。initrd とinitramfsの2種類の方式があるが、文脈によってはこれらを総称してinitrdと呼んでいる場合もある。 本記事でもinitrdとinitramfsの両方を記述する。

1. 原理
-----

Linuxディストリビューションの多くは、なるべく広範囲なハードウェアでブートできるよう、単一の汎用的カーネルイメージで出荷されている。この汎用カーネルイメージのデバイスドライバ群はローダブル・カーネル・モジュールになっており、メモリの限られたコンピュータやフロッピーディスクなどの低容量媒体からもブートができるようカーネルイメージを巨大化させない工夫をしている。

このような方式では、ルートファイルシステムをブート時にマウントするには、事前に必要なモジュールを検出してロードしなければならないという問題が生じる。

さらに問題を複雑にするのは、ルートファイルシステムがソフトウェアRAIDボリュームだったり、LVMだったり、NFSだったり、暗号化されたパーティションだったりする点である。これらはマウントに当たって特別な処理を必要とする。

もう1つ問題を複雑化させることとして、カーネルがハイバネーションをサポートしていることがある。ハイバネーションとは、システムを停止させて、その時点の全システムイメージをスワップパーティションや普通のファイルにダンプし、電源を切る機能である。次回立ち上げたとき、そのイメージをメモリにロードするには、ディスク上のイメージにアクセスできなければならない。

これらの特殊ケースに対応してカーネルにコードを加えるのを防ぐため、立ち上げの初期段階では一時的なルートファイルシステムを使う。これを初期ユーザ空間などと呼ぶ。このルートファイルシステムには真のルートファイルシステムのマウントに必要となる、ハードウェア検出、モジュールローディング、デバイス発見などのユーザー空間ヘルパーが存在する。

2. 実装
-----

initrd のファイルシステムイメージは、Linuxのブートローダやファームウェアがアクセスできる場所に格納しておく必要がある。これには、次のようなものがある。

ルートファイルシステム自身
ローカルディスク上の ext2 か FAT でフォーマットされた小さなパーティション
Live CD の場合は、CD上のファイルシステム
TFTPサーバブートローダはカーネルとinitrdイメージをメモリ上にロードし、カーネルを起動する際に initrd のメモリアドレスを渡す。ブートの最終段階で、カーネルはinitrdイメージの先頭数ブロックを読み込み、そのフォーマットを判断する。

そのイメージがファイルシステムイメージの場合、特殊なブロックデバイス  として利用可能にし、ルートファイルシステムとしてマウントする。このファイルシステム用のドライバはカーネル内に静的にコンパイルしておく必要がある。多くのディストリビューションではデフォルトで圧縮されたext2ファイルシステムをinitrdイメージに採用している。他には、メモリの限られたシステムでもブートできるようcramfsを使うものもある。cramfsは伸長の際に追加のメモリを必要としない。 初期化用ルートファイルシステムが利用可能になると、カーネルは最初のプロセスとして /linuxrc を実行する。そのプロセスが終了  するとカーネルは真のルートファイルシステムのマウントが完了したと判断し、"/sbin/init" を実行して通常のユーザー空間の立ち上げ処理を開始する。
そのイメージがgzipで圧縮されたcpioアーカイブの場合、中間段階としてカーネルがそれを展開して initramfs とし、それを初期化用ルートファイルシステムとする。ext2などのファイルシステムのドライバをカーネルに組み込んでおく必要がなくなるという利点がある。 initramfs 上で、カーネルは最初のプロセスとして /init を実行する。/init は終了  しない。

2.1. マウント準備
-----------

一部のLinuxディストリビューションでは、特定のコンピュータでのブートに必要なものだけを格納したカスタマイズしたinitrdイメージを生成する。その場合、ルートファイルシステムの場所や種類を実行時に判断するのではなく、initrdイメージ内に決めうちで書き込んでおくことが多い。

他のディストリビューションはより汎用的なinitrdイメージを生成する。その場合、ルートファイルシステムのデバイス名のみを使い、他の必要な情報はブート時に発見しなければならない。したがって、ルートファイルシステムをマウントするまでに以下のようなタスクが実行される。

ブート処理が依存している任意のハードウェアドライバをロードしなければならない。通常、一般的なストレージ機器用カーネルモジュールをまとめてinitrdに格納しておき、ホットプラグエージェントを起動して、検出したハードウェアにマッチするモジュールを取出す。
ブートスプラッシュを表示するシステムでは、画面表示関連ハードウェアを初期化し、ユーザー空間のヘルパーを使ってブート処理と同期しつつアニメーションを描画させる。
ルートファイルシステムがNFSの場合、以下を行う。
主要なネットワークインタフェースを起動させる。
DHCPクライアントを呼び出し、必要な情報を得る。
その情報からNFS共有の名前とNFSサーバのアドレスを取出す。
NFS共有をマウントする。
ルートファイルシステムがソフトウェアRAIDデバイスの場合、RAIDボリュームがどのデバイスにまたがっているかを知る手段がない。通常はMDユーティリティを呼び出し、全ブロックデバイスをスキャンし、必要なデバイスをオンラインにする。
ルートファイルシステムが論理ボリュームの場合、LVMユーティリティを呼び出してスキャンし、ルートファイルシステムを格納しているボリュームグループを活性化させる。
ルートファイルシステムが暗号化されたブロックデバイスにある場合、
ヘルパースクリプトを呼び出し、ユーザーにパスフレーズを入力させるかハードウェアトークンを挿入させる。
デバイスマッパーにより復号対象を生成する。
ルートファイルシステムをマウントした状態では安全に実施できない保守タスクがあれば、ここで実行する。
ルートファイルシステムを読み込み専用でマウントする。
動作し続ける必要のあるプロセスを新たにマウントしたルートファイルシステムに移行させる。ルートファイルシステムを普通にルートにマウントすると、初期化用ルートファイルシステム上のスクリプトなどを実行していたプロセスがうまくクリーンアップして終了できないため、次のような配慮が必要となる。

initrd では、真のルートファイルシステムは一時的なマウントポイントにマウントし、このためだけに導入された [1] を使って両者を入れ替える。こうすると初期化用ルートファイルシステムは新たなマウントポイントに残るので、後でこれをアンマウントし initrd に使っていたメモリを解放することができる。
initramfs では、初期化用ルートファイルシステムを pivot_root で移動させることができない。そのため、[2]により単にその中身を空にし、真のルートファイルシステムを上書きするようにマウントする。初期化用ルートファイルシステムには /linuxrc や /init といったシェルスクリプトがあるため、最小限のシェルも含まれているし、他にも基本的なユーティリティ群も格納されている。容量を節約するため、それらのシェルやユーティリティやライブラリ群は容量最適化オプション付きでコンパイルされ、klibcのような標準Cライブラリの最小版とリンクされている。

3. 脚注・出典
--------

4. 外部リンク
--------

[3] initrd生成ツールキットの詳細な比較
[4] on early userspace support