Initrd

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

原理

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

このような方式では、ルートファイルシステムをブート時にマウントするには、事前に(ルートファイルシステム上にある)必要なモジュールを検出してロードしなければならないという問題が生じる(あるいは、ルートファイルシステムそのものがどこにあってどういう種類かを事前に知る必要がある)[1]

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

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

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

実装

mkinitcpio, Arch Linux および関連ディストリビューションで initramfs を生成するソフトウェア

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

  • ルートファイルシステム自身
  • ローカルディスク上の ext2FAT でフォーマットされた小さなパーティション(ブートパーティション)
  • Live CD の場合は、CD上のファイルシステム
  • TFTPサーバ(イーサネットからブートする場合)

ブートローダはカーネルとinitrdイメージをメモリ上にロードし、カーネルを起動する際に initrd のメモリアドレスを渡す。ブートの最終段階で、カーネルはinitrdイメージの先頭数ブロックを読み込み、そのフォーマットを判断する。

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

マウント準備

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

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

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

ルートファイルシステムを普通にルート(/)にマウントすると、初期化用ルートファイルシステム上のスクリプトなどを実行していたプロセスがうまくクリーンアップして終了できないため、次のような配慮が必要となる。

  • initrd では、真のルートファイルシステムは一時的なマウントポイントにマウントし、このためだけに導入された pivot_root(8) を使って両者を入れ替える。こうすると初期化用ルートファイルシステムは新たなマウントポイント(/initrd など)に残るので、後でこれをアンマウントし initrd に使っていたメモリを解放することができる。
  • initramfs では、初期化用ルートファイルシステムを pivot_root で移動させることができない[5]。そのため、swich_root(8)コマンドにより単にその中身を空にし、真のルートファイルシステムを上書きするようにマウントする。

初期化用ルートファイルシステムには /linuxrc/init といったシェルスクリプトがあるため、最小限のシェル(通常、/bin/ash)も含まれているし、他にも基本的なユーティリティ群(BusyBoxツールキットにあるようなもの)も格納されている。容量を節約するため、それらのシェルやユーティリティやライブラリ群は容量最適化オプション(gcc の "-Os" フラグなど)付きでコンパイルされ、klibcのような(このために開発された)標準Cライブラリの最小版とリンクされている[6]

脚注・出典

  1. ^ a b Almesberger, Werner (2000), “Booting linux: the history and the future”, Proceedings of the Ottawa Linux Symposium, http://www.linuxsymposium.org/2000/booting.php 
  2. ^ a b Landley, Rob (15 March 2005), Introducing initramfs, a new model for initial RAM disks, linuxdevices.com, オリジナルの2013-01-04時点におけるアーカイブ。, https://archive.is/xoNFj 
  3. ^ a b Almesberger, Werner; Lermen, Hans (2000), http://www.kernel.org/doc/Documentation/initrd.txt 
  4. ^ Landley, Rob (2005-10-17), ramfs, rootfs, and initramfs docs, take 2, Linux kernel source tree, http://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt 
  5. ^ Fish, Richard (2005-07-06), pivot_root from initramfs causes circular reference in mount tree, Linux Kernel Bug Tracker, http://bugzilla.kernel.org/show_bug.cgi?id=4857 2009年2月28日閲覧。 
  6. ^ Garzik, Jeff (2002-11-02), initramfs merge, part 1 of N, Linux kernel mailing list, http://lkml.org/lkml/2002/11/2/17 

外部リンク