レベル: 初級 Lei Jiang, Software Engineer, IBM
2009年 03月 11日 皆さんは Linux® 管理者として、外部ストレージのボリュームを追加した後や、新しい Linux オペレーティング・システムをインストールした後でさえ、サーバーをリブートしようとすると「cannot mount rootfs」や「kernel panic」などの rootfs に関するエラーが起きた経験があるのではないでしょうか。この記事では、x86 プラットフォームでの Linux のブート・プロセスの概要と、こうしたエラーが起こる原因、そしてこのエラーを回避あるいは修復するための 4 つのヒントを説明します。
問題の概要
ルート・ファイルシステム (この記事のエラー・メッセージの中では rootfs と呼びます) は Linux の最も基本的なコンポーネントです。ルート・ファイルシステムには完全な Linux システムをサポートするために必要なもの (アプリケーション、構成、デバイス、データ、等々) がすべて含まれています。ルート・ファイルシステムがないと Linux システムを実行することはできません。
皆さんの中には、システムをリブートした後、「cannot mount rootfs」(そしてそれに続く Linux ホストからの「kernel panic」) というエラーに遭遇したことのある人がいるのではないでしょうか。このエラーは、外部ストレージに何らかのストレージ・ボリュームを追加した場合によく起こります。また、ファイルのコピーを終了した後でインストールを完了するためにリブートする場合にも起こることがあります。
このエラーが発生すると、システムは再起動することができません。この問題のトラブルシューティングと修復には時間がかかる場合があります。ここで紹介する一連のヒントは、この問題の解決と時間の節約に役立つはずです。
もう 1 つ、エラーの原因として、Linux カーネルがルート・ファイルシステムをマウントしようとしてターゲット・デバイスを見つけられない状態が考えられます。つまり、あるはずの場所にルート・ファイルシステムが見つからないのです。これは例えば、Linux のルート・ファイルシステムをディスク /dev/sda にインストールしたものの、システムはリブート中にそのディスクをマウントできないという状態です。この原因としては次の 2 つが考えられます。
- システムのリブート中にディスク /dev/sda が見つからない。
これは Linux ホストがルート・ファイルシステム用の重要なドライバーをロードしなかったために起きているのかもしれません。しかしそれは滅多にないことです。Linux のインストール・プログラムは Linux システムがブート中にデバイス・ドライバーを容易にロードできるように、必要なすべてのドライバーを initrd イメージの中にビルドするからです。ただしドライバーを手動でインストールした場合には、このエラーが起こる可能性があります。
- /dev/sda ディスクは見つかるものの、そのディスクはルート・ファイルシステムではなく、リブート後にルート・ファイルシステムが /dev/sdb に変更されている。
これが最もよくある例です。
ではシステムのリブート後に、どのようにして /dev/sda が /dev/sdb にリネームされてしまうのでしょう。Linux では /dev/sd* は SCSI デバイスを意味します。Linux はこれらのデバイスに対して sda から sdz の順に名前を付けます (その後は sdaa から sdzz の順で名前を付ける等々です)。最初の SCSI デバイスの名前は /dev/sdaであり、2 番目の名前は /dev/sdb であり、等々です。
あるアダプターの中にあるデバイスをドライバーと共にインストールする場合、そのドライバーがルート・ファイルシステムのデバイス・アダプターのドライバー (元々の場所は /dev/sda) よりも前にロードされると、ルート・ファイルシステムのデバイス名は 1 文字後の /dev/sdb になり、最初に検出されるデバイスではなくなります。従ってルート・ファイルシステムが行の先頭にはないため Linux システムはルート・ファイルシステムをマウントすることができません。
これは何が起きているかを簡単に説明しただけですが、もう少し詳しく説明するために、Linux のブート・プロセスの概要を説明しましょう。(「根本的な」原因を理解している読者は次のセクションを飛ばして直接「4 つのヒント」に進んでください。)
Linux のブート・プロセスの動作
 |
ブート・ローダー
LILO (Linux Loader) は Linux 用の汎用のブート・ローダーであり、特定のファイルシステムに依存せず、フロッピー・ディスクやハード・ディスクからオペレーティング・システムをブートすることができます。ブート時には最大 16 種類の異なるイメージから選択することができると同時に、カーネルごとに別々に各種パラメーター (ルート・デバイスなど) を設定することができます。LILO は MBR (マスター・ブート・レコード) に配置することも、あるパーティションのブート・セクターに配置することもできます。後者の場合には、MBR に何らかの起動プログラムを配置しておかないと LILO をロードすることはできません。
もう 1 つのブート・ローダーは GRUB (GNU GRUB) です。GRUB はマルチブート仕様のリファレンス実装です。マルチブート仕様ではコンピューター上にいくつかの異なるオペレーティング・システムを同時に持つことができ、どれを実行するのかをユーザーが選択することができます。GRUB は動的に構成可能であり、構成のロードは起動時に行われるため、ブート時に、例えば異なるカーネルを選択したり初期 RAM ディスクを選択したりすることができます。GRUB は非常に移植性が高く、実行ファイルのフォーマットを複数サポートし、またジオメトリー変換に依存しません。GRUB はオペレーティング・システムのイメージをネットワークからダウンロードすることができるため、ディスクレス・システムを実現することができます。GRUB はオペレーティング・システムのイメージを自動解凍し、そのイメージからブートします。また GRUB は他のブート・ローダーとは異なり、GRUB プロンプトから直接ユーザーとやり取りすることができます。
|
|
Linux のブート・プロセスは大まかに以下のステップで行われます。
- コンピューターは起動すると、最初に基本テストである POST (Power On Self Test) を実行します。プロセッサー、メモリー、グラフィック・カード、キーボードなど、いくつかのデバイスがテストされます。またブート・メディア (ハード・ディスク、フロッピー・ユニット、CD-ROM) もテストされます。POST が終わると、ROM の中にあるローダーがブート・セクターをロードし、次にブート・セクターはアクティブなパーティションからオペレーティング・システムをロードします。サーバーの BIOS を編集するとメディアをブートする順序を変更することができます。
- ブート・セクターは常に同じ場所、つまりブート・デバイスのトラック 0、シリンダー 0、ヘッド 0 にあります。このセクターには
ローダーと呼ばれるプログラム (Linux の場合には通常 LILO または GRUB) が含まれており、このローダーが実際にオペレーティング・システムをブートします。ローダーは MBR にインストールされるか、あるいはアクティブなプライマリー・パーティションの最初のセクターにインストールされます。
- サーバーに複数のオペレーティング・システムがインストールされている場合には、どれを使用するのかをブート・ローダーのメニューから選択する必要があります。また複数のカーネルがインストールされている場合も、どのカーネルをロードするのかをブート・ローダーのメニューから選択することができます。
- 次に、ブート・ローダーはカーネルを解凍してロードします。カーネルは最初にカーネル・モジュールをロードしたら、ハードウェア (フロッピー・ドライブ、ハード・ディスク、ネットワーク・アダプターなど) を検出し、ハードウェアの構成を検証し、そしてデバイス・ドライバーをスキャンしてロードします。
- この段階でカーネルはルート・ファイルシステムとシステム・ファイルをマウントします。システム・ファイルの場所は再コンパイル中に、または他のプログラムによって構成することができます。もしマウントが失敗すると「
kernel panic」が発生し、システムがフリーズします。これが先ほど説明したタイプのマウント失敗です。
- 次に、カーネルはシステムの初期化プロセスである
init を開始し、これが最初のプロセスとなります。そしてカーネルはシステムの残りの部分を開始します。init プロセスは Linux の最初のプロセスであり、他のすべてのプロセスの親でもあります。どのような Linux/UNIX® システムでも、最初に実行されるプロセスは init プロセスであり、このプロセスの PID は必ず 1 です。
- 次に
init は /etc/inittab ファイルを調べ、どのプロセスを起動する必要があるのかを判断します。このファイルは init に対して、ランレベルに関する情報と、どのプロセスを各ランレベルに対して起動するのかに関する情報を提供します。init はこのファイルの中でさらに、sysinit (システム初期化) アクションが指定されている最初の行を調べ、その行に指定されたコマンド・ファイル (例えば Red Hat Linux の /etc/rc.d/rc.sysinit など) を実行します。init は /etc/rc.d/rc.sysinit の中のスクリプトを実行した後、最初のランレベルに関連付けられたプロセスの起動を開始します。ランレベルで指定された最初のスクリプトの実行が終わると、Linux はユーザーからのログインを許可します。
ここで説明する各ソリューションでは、上記のステップ 5 を処理します。
4 つのヒント
ほとんどの場合、「cannot mount rootfs」エラーはデバイスの順序が原因で起こるため、デバイスの順序を変更するか、ドライバーのロード順序を変更することで、この問題を解決することができます。
この 2 つの解決手段を実現するための方法として、以下の 4 つがあります (以下の各方法では、Linux のルート・ディスクのデバイス名に必ず /dev/sda を使えるように、このディスクがカーネルやシステムの最初に現れるように考慮されています)。
- サーバーの BIOS で PCI デバイスのブート順序を変更する。
- ルート・ファイルシステムのディスクをアダプターの最初のスロットに接続する。
- initrd イメージを編集し、ルート・ファイルシステムのアダプターのドライバーが他のどのストレージ・アダプターのドライバーよりも先にロードされるようにする。
- ルート・ファイルシステムのマウント用に、デバイス名の代わりにラベルや UUID、またはわかりやすい名前を使う。
1. サーバーの BIOS で PCI デバイスのブート順序を変更する
IBM System x® シリーズまたは IBM BladeCenter® HS シリーズを使用している場合には、手順は以下のとおりです。
- サーバーからセルフテストの情報が表示され、続いて「Press F1 to enter BIOS」と表示されたら F1 を押します。
- Start Options を選択し、Enter を押します (図 1)。
図 1. 構成/セットアップ・ユーティリティー
- PCI Device Boot Priority をルート・ファイルシステムのディスクが使用しているアダプターに変更します (下記の図 2)。下記図は Linux がローカルの Planar SAS ディスクにインストールされている場合です。
図 2. 起動オプション
あるいは、関連する PCI スロットを選択し、Daughter Card Slot 1 が最も小さい値のデバイス ID としてシステムに最初に現れるようにする方法もあります (図 3)。
図 3. 別の起動オプション
この場合はローカルの Planar SAS の方が大きい値のデバイス ID を持つことになります。デバイス名が /dev/sda の Planar SAS ディスクに Linux をインストールしてある場合に、新しいディスク・デバイスを Daughter Card Slot 1 に追加すると、この新しいディスクが /dev/sda というデバイス名を使うことになり、ルート・ファイルシステムのディスクは /dev/sdb に変わります。そのため「cannot mount rootfs」エラーが起こります。
2. ルート・ファイルシステムのディスクをアダプターの最初のスロットに接続する
ルート・ファイルシステムのディスクのアダプターに 2 つを超えるデバイスを接続できる場合、あるいは 2 つを超えるディスク・アダプターがある場合には、最も小さい値のデバイス ID を持つスロット (最初のアダプターの最初のスロットなど) に必ずルート・ファイルシステムのディスクが配置されるようにします。ルート・ファイルシステムのディスクよりも小さい値の ID を持つディスクが新たに追加されている場合には、そのディスクよりも前のスロットにルート・ファイルシステムのディスクを配置する必要があります。こうすることによって、ルート・ファイルシステムのディスクが Linux システムの最初に現れるようになります。
3. initrd イメージを編集し、ストレージ・アダプターの順序を変更する
initrd イメージは実際には RAM ディスクであり、そこには基本構成ファイルやバイナリー、ライブラリー、ドライバーなどで構成される簡単なファイルシステムが含まれています。この簡単なファイルシステムの中に、ブート時にメモリーにロードされるルート・ファイルシステムがあり、またシステムのデバイス・ドライバーをロードするための初期スクリプトがあります。システムはすべてのデバイス・ドライバーのロードを終えると、実際に使用するルート・ファイルシステムをマウントしなおします。しかし、システムがこの構成でデバイス名を使って initrd のルート・ファイルシステムを実際に使用するルート・ファイルシステムのディスクに切り換えようとすると、必ず「cannot mount rootfs」エラーが起こります。このエラーが起こらないようにするには、initrd イメージの中にあるドライバー・ロード用スクリプトの中でデバイス・ドライバーのロード順を変更し、ルート・ファイルシステムのディスクが適切なデバイス名で表示されるようにしてから、システムが実際に使用するルート・ファイルシステムをシステムにマウントしなおす必要があります。これは以下の手順で行います。
- (ルート・ファイルシステムにはアクセスできないので) Linux レスキュー CD を使ってレスキュー・モードでシステムをブートします。
- ルート・ファイルシステムを
sysroot のような一時ディレクトリーにマウントします (一部の Linux レスキュー CD はこれを自動的に行います)。例えばシステムをレスキュー・モードでブートし、ルート・ファイルシステムがパーティション 3 を使っている場合には、ルート・ファイルシステムのディスクは /dev/sdc と認識されます。
[root@linuxhost ~]#mount /dev/sdc3 sysroot
|
- レスキュー・システムのルートを sysroot に変更し、問題のサーバー・システムのルート・ファイルシステムにアクセスできるようにします。
[root@linuxhost ~]#chroot sysroot
|
- initrd イメージを抽出します。
- バージョン 3 およびそれより前のバージョンの Red Hat Enterprise Linux と、バージョン 9 およびそれより前のバージョンの SUSE Linux Enterprise Server の場合には次のようにします。
[root@linuxhost ~]#cp /boot/initrd-x.x.x-x.ELsmp.img ./initrd.gz
[root@linuxhost ~]#mkdir temp
[root@linuxhost ~]#gunzip ./initrd.gz
[root@linuxhost ~]#mount -o loop -t ext2 initrd temp
|
これによって initrd イメージが initrd ファイルに抽出されるので、このファイルを ext2 ファイルシステムを使って temp というマウント・ポイントにマウントします。マウントできる、すべてのファイルが initrd イメージの中にパッケージされていることがわかります。
- バージョン 4 およびそれ以降のバージョンの Red Hat Enterprise Linux と、バージョン 10 およびそれ以降のバージョンの SUSE Linux Enterprise Server の場合には次のようにします。
[root@linuxhost ~]#cp /boot/initrd-*.img ./initrd.gz
[root@linuxhost ~]#mkdir temp
[root@linuxhost ~]#cd temp
[root@linuxhost ~]#gzip -dc ../initrd.gz | cpio -id
|
こうした新しい Linux ディストリビューションの場合と同じように、initrd イメージを cpio で圧縮することもできます。これらのコマンドによって、ファイルシステム全体がディレクトリー構造と共に temp ディレクトリー配下に抽出されます。すると、initrd イメージの中にあるすべてのファイルが temp ディレクトリー配下にあることを確認できるはずです。
- これで、Red Hat Enterprise Linux と SUSE Linux Enterprise Server バージョン 10 用の init ファイル、あるいはバージョン 9 およびそれより前のバージョンの SUSE Linux Enterprise Server 用の linuxrc ファイルが temp ディレクトリー配下にあることがわかります。このファイルは単純な Linux シェル・スクリプトであり、デバイス・ドライバーをシステム・メモリーにロードするためのすべてのコマンドを含んでいます。このファイルはテキスト・エディターまたはその他のエディターを使って編集することができます。
- init ファイルまたは linuxrc ファイルを編集し、同じカテゴリー内にある他のどのストレージ・アダプターよりも前にルート・ファイルシステムのディスク・アダプターが現れるようにします。ほとんどの場合、ルート・ファイルシステムのディスクは接頭辞が sd の SCSI デバイスなので、他のすべてのストレージ・アダプター (FC ドライバーや SAS HBA ドライバーなど) を、ルート・ファイルシステムのディスクが依存するドライバーの後に配置する必要があります。
- 例えばルート・ファイルシステムの物理ディスクが SAS アダプターに接続されている場合には、init ファイルには以下のようなフィールドがあるかもしれません。
.......
echo "Loading mptbase.ko module"
insmod /lib/mptbase.ko
echo "Loading mptscsi.ko module"
insmod /lib/mptscsi.ko
echo "Loading mptspi.ko module"
insmod /lib/mptspi.ko
echo "Loading mptsas.ko module"
insmod /lib/mptsas.ko
echo "Loading mptscsih.ko module"
insmod /lib/mptscsih.ko
echo "Loading qla2xxx.ko module"
insmod /lib/qla2xxx.ko
.......
|
この場合には、他のすべての SCSI アダプター・ドライバー (例えば Qlogic の HBA ドライバー qla2xxx.ko など) を SAS アダプター・ドライバー mptsas.ko の後に配置します。
- SUSE Linux Enterprise Server バージョン 10 を使用している場合には以下のようになります。
modprobe scsi_mod $params
modprobe sd_mod $params
params=
for p in $(cat /proc/cmdline) ; do
case $p in
aacraid.*)
params="$params ${p#aacraid.}"
;;
esac
done
echo "Loading aacraid"
modprobe aacraid $params
modprobe scsi_transport_fc $params
modprobe firmware_class $params
params=
for p in $(cat /proc/cmdline) ; do
case $p in
qla2xxx.*)
params="$params ${p#qla2xxx.}"
;;
esac
done
echo "Loading qla2xxx"
modprobe qla2xxx $params
|
- バージョンをよく確認し、必要なドライバーが必ずすべてロードされるようにします (例えば SAS の場合、mptbase.ko、mptscsi.ko、mptspi.ko、mptsas.ko、mptscsih.ko を一緒にロードする必要があります。そのため mptscsih.ko の前に qla2xxx.ko をロードすることはできません)。また、タイプミスがないかどうかもチェックする必要があります。
- この段階で initrd ファイルシステムを再度イメージに圧縮し、/boot ディレクトリー配下にある元のイメージと置き換える必要があります。
- バージョン 3 およびそれより前のバージョンの Red Hat Enterprise Linux と、バージョン 9 およびそれより前のバージョンの SUSE Linux Enterprise Server の場合には次のようにします。
[root@linuxhost ~]#umount temp
[root@linuxhost ~]#gzip initrd
[root@linuxhost ~]#cp initrd.gz /boot/initrd-2.x.x-x.img
|
- バージョン 4 およびそれ以降のバージョンの Red Hat Enterprise Linux と、バージョン 10 およびそれ以降のバージョンの SUSE Linux Enterprise Server の場合には次のようにします。
[root@linuxhost ~]#find ./ | cpio -H newc -o > ../initrd
[root@linuxhost ~]#gzip initrd
[root@linuxhost ~]#cp initrd.gz /boot/initrd-2.6.x-x.img
|
- おめでとうございます。これで問題を修復することができました。リブートして結果を確認します。
4. ラベル、UUID、またはわかりやすい名前を使う
 |
UUID
UUID は Universally Unique Identifier を意味します。UUID はソフトウェアを作成する際に使われる識別子の標準であり、Open Software Foundation による DCE (Distributed Computing Environment) の一環として標準化されました。UUID は中央で大がかりな調整を行わなくても分散システムが情報を一意に識別できるように設計されています。UUID によってラベル付けされた情報は 1 つのデータベースの中にまとめることができ、名前の競合を解決する必要がありません。UUID 標準が使われている重要な例として、Linux の ext2/ext3 ファイルシステム、LUKS 暗号化パーティション、GNOME、KDE、Mac OS X、Microsoft® の Globally Unique Identifiers などがあります。
|
|
一部のタイプの Linux ファイルシステム (例えば ext2、ext3、reiserfs、swap、XFS など) では、デバイス名の代わりにラベルを使ってファイルシステムをマウントすることができ、UUID をサポートする Linux システムであればデバイス名の代わりに UUID を使うこともできます。またデバイス・ドライバーがサポートしている場合には、わかりやすい名前を使うこともできます。
これらの方法を利用するためには、そうした機能を Linux システムがサポートしている必要があります (例えば Red Hat Enterprise Linux V4 およびそれ以降のバージョンや、SUSE Linux Enterprise Server V9 およびそれ以降のバージョンではサポートしています)。こうした機能では、ラベルや UUID、わかりやすい名前などによって特定のデバイスが永続的に結びつけられるため、それらにどのようなデバイス ID やデバイス名が付けられたとしても、システムは必ずルート・ファイルシステムのディスクを見つけることができます。
ラベルを使う
- ルート・ファイルシステムやスワップ・ファイルシステム、あるいは他のファイルシステムなどのファイルシステムを作成する際に、ラベルを作成します。
[root@linuxhost ~]#mkfs.ext3 -L ROOT /dev/sda1
[root@linuxhost ~]#mkfs.reiserfs -l OSROOT /dev/sdb2
[root@linuxhost ~]#mkfs.xfs -L XFSROOT /dev/sde3
[root@linuxhost ~]#mkswap -L SWAP0 /dev/sdb5
|
- ファイルシステムが作成できたら、そのファイルシステムにラベルを追加します。
[root@linuxhost ~]#e2label /dev/sda1 PRIMARY_ROOT
[root@linuxhost ~]#reiserfstune -l OSROOT /dev/sdb2
[root@linuxhost ~]#xfs_admin -L DATA1 /dev/sdf4
|
- システムの中でラベルを使います。
- システムがファイルシステムをマウントする際にデバイス名の代わりにラベルを使うように、Linux システムの /etc/fstab を編集します。下記は /etc/fstab の内容を示した簡単な例です。
LABEL=ROOT / ext3 defaults 1 1
LABEL=BOOT /boot ext3 defaults 1 2
LABEL=SWAP swap swap defaults 0 0
LABEL=HOME /home ext3 nosuid,auto 1 2
|
- Linux ブート・ローダーの grub.conf を編集します。
title Linux
root (hd0,0)
kernel (hd0,0)/vmlinuz ro root=LABEL=ROOT rhgb quiet
initrd (hd0,0)/initrd-2.x.x-xx.img
|
UUID を使う
- ルート・デバイスの UUID を取得します。ここでは仮に、下記の例のようにルート・ファイルシステムがディスク・デバイス /dev/sda の中にあるとしましょう。
[root@linuxhost ~]#scsi_id -g -s -u /block/sda
|
- ステップ 1 で取得したデバイス UUID を持つルート・ファイルシステムのデバイス ID を下記のコマンドを使ってチェックします。
[root@linuxhost ~]#ls /dev/disk/by-id/<your device UUID>
|
- 下記の例のように /etc/fstab を編集し、システムで UUID を使用します。
/dev/disk/by-id/scsi-<your uuid>-part2 / ext3 defaults 1 1
|
わかりやすい名前を使う
マルチパス・ストレージに DMMP (Device Mapper Multi-Path) ツールを使う場合には、わかりやすい名前をルート・ファイルシステムに使用すると、リブート後に DMMP によってデバイス番号が付け替えられることがなくなります。
- ルート・デバイスの UUID を取得します。ここでは仮に、ルート・ファイルシステムがディスク・デバイス /dev/sda にあるとしましょう。
[root@linuxhost ~]#scsi_id -g -s -u /block/sda
|
- etc/multipath.conf を編集し、わかりやすい名前をルート・ファイルシステムのデバイスに付けます。例えば次のようにします。
multipaths {
multipath {
wwid <your disk UUID get from above command>
alias OSROOT
}
}
|
- システムをリブートするか、または DMMP をリロードすると、ルート・ファイルシステムのデバイス名が /dev/mapper/OSROOT のようになっているはずです (このディスクのパーティション 3 をルート・ファイルシステムが使用している場合には、デバイス名は /dev/mapper/OSROOT-part3 または /dev/mapper/OSROOTp3 のようになります)。
- /etc/fstab を編集し、このルート・ファイルシステムのデバイスに対して、このわかりやすい名前を使うようにします。
/dev/mapper/OSROOT-part3 / ext3 defaults 1 1
|
- /etc/grub.conf を編集し、この名前がシステムのブート時に使われるようにします。
title Linux
root (hd0,0)
kernel (hd0,0)/vmlinuz ro root=/dev/mapper/OSROOT-part3 rhgb quiet
initrd (hd0,0)/initrd-2.x.x-xx.img
|
- これで完成です。リブートすると、この名前が機能しているかどうかを確認することができます。
まとめ
この記事では、Linux システムの「cannot mount rootfs」エラーを回避あるいは修復するようにシステムを設定する方法と、Linux システムのブート・プロセスの背景について説明しました。
参考文献 学ぶために
製品や技術を入手するために
- developerWorks から直接ダウンロードできる IBM ソフトウェアの試用版を利用して皆さんの次期 Linux 開発プロジェクトを構築してください。
議論するために
著者について  | 
|  | Lei Jiang は Open Systems Interoperability Validation Lab ストレージ・テスト・チームの一員として IBM China Systems and Technology Lab in Shanghai で働いています。彼は SAN によるストレージに関するさまざまなサポートとテストに 3 年間の経験があり、現在はストレージ技術や、オープンシステムによる SAN と高可用性ソリューションに関する業務に従事しています。 |
記事の評価
|