ソースコード・リテラシーのススメ

第16回トラブルの状況を読む

過去数回に渡って最近のLinux起動の仕組みを解説し、その際に実行されるスクリプトや参照される設定ファイルなどを眺めてきました。実のところ、このあたりのシステムの基盤部分に関する設定は、ヘタにいじるとシステムが正しく起動しなくなることもあるため、一般ユーザはおろかシステム管理者でも通常は気にする必要のない部分だったりします。

しかしながら、筆者のようにディストリビューションの開発にたずさわっていると、このような基盤部分のトラブルにもしばしば直面します。

基盤部分のトラブルは、ディストリビューションの設計方針などとも関係するため、Google等で調べても直接解決することは少なく、付属ドキュメントや設定ファイル、ソースコードなどを総合的に検討する必要があります。

今回は、トラブル時の調査や分析の一例として、Plamo-4.5にext4ファイルシステムを組み込む際に遭遇したトラブルを用いて、それらトラブルの原因をどのように調べ、解決したかの例を紹介してみようと思います。

e2fsprogs-1.41 の導入

筆者がとりまとめ役をしているPlamo Linuxでは、ルートパーティションのファイルシステム(fs)として ext2/ext3/reiser の3種を使えるようにしていましたが、最近ではreiser fsの将来性が怪しくなると共に、ext4 fsも実用レベルになってきたようなので、ext4 fsに対応するための作業を始めました。

まず、ext4 fsを作成するためのツールであるe2fsprogsの最新版である1.41をビルドし、インストーラに組み込みました。また、インストール用のスクリプトでもext4をファイルシステムとして選択できるように修正しました。

この状態でテストしてみると、mkfs.ext4コマンドは正しく実行されるものの、パッケージをインストールしている途中で ⁠OOM killer⁠ が発生して、異常終了してしまいます。

図1 OOM killerが発生!
図1 OOM killerが発生!

当初は「使っているカーネルにext4の機能を組み込み忘れたのが敗因だろう」と考えて、カーネルを最新版に更新してext4の機能を組み込むことにしました。Plamo-4.22で使っていたカーネルは2.6.24系でしたが、最近では2.6.26系が公開されているので、その最新バージョンである 2.6.26.1 を採用し、make menuconfig のファイルシステムの設定で Ext4dev/ext4 を有効にしたカーネルを作成、パッケージ化すると共に、インストーラのカーネルも更新しました。

再度テストしたところ、やはりパッケージをインストールする段階でOOM Killerが発生します。⁠これはおかしい」と、インストーラの各段階ごとにファイルシステムの状況やプロセス、メモリの使用状況などを確認しながら進めたところ、ext4 形式で作成したルートパーティションがマウントできていないようです。

インストーラのシェルを使って対話的に操作してもやはりエラーになってマウントできません。

# mkfs.ext4 /dev/sda1
mke2fs 1.41.0 (10-Jul-2008)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
...
Thie filesystem will be automatically checked every 37 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.

# mount /dev/sda1 /mnt
mount: wrong fs type, bad option, bad superblock on /dev/sda1,
       missing codepage or other error
       In some cases useful info is found in syslog - try
       dmesg | tail or so

エラーメッセージにあるようにdmesgの内容を調べてみたところ、⁠unsupported optional features⁠なるエラーが報告されています。

# dmesg | tail
....
Unikey successfully installed.
Ext3-fs: sda1: couldn't mount because of unsupported optional features (240).

「あれれ、なぜExt3-fsのエラーなんだろう?」と思って、カーネルがサポートしているファイルシステムの一覧を確認するために/proc/filesystemsを調べました。

# cat /proc/filesystems
nodev   sysfs
nodev   rootfs
...
nodev   devpts
        reiserfs
        ext3
        ext4dev
        ext2
nodev   ramfs
...

この結果を見ると、カーネルがサポートしているファイルシステムはext4devであってext4ではないようです。確かにe2fsprog-1.41.0にはmkfs.ext4mkfs.ext4devの2種のコマンドがあります。⁠ext4とext4devって異なるファイルシステムという扱いなのかな?」と首をかしげつつ、こういった場合はmenuconfigのヘルプメッセージが参考になるだろうと、make menuconfigを実行して、⁠Ext4dev/ext4 extended fs support development⁠のHelpメッセージを読んでみました。

図2 menuconfigのext4devに関するヘルプメッセージ
図2 menuconfigのext4devに関するヘルプメッセージ

このヘルプメッセージを見る限り、ext4 fsは現在も開発が進行中の機能で、開発が完了するまではext4devという名称にしてあるようです。

それでは、mkfs.ext4とmkfs.ext4devの違いはどこにあるのでしょう? e2fsprogsと共にインストールされる、これらのコマンドの設定ファイル/etc/mke2fs.confを調べてみました。

# cat /etc/mke2fs.conf
[defaults]
        base_features = sparse_super,filetype,resize_inode,ext_attr
        blocksize = 4096
        inode_size = 256
        inode_ratio = 16384

[fs_types]
        ext3 = {
                features = has_journal
        }
        ext4 = {
                features = has_journal,extents,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize
                inode_size = 256
        }
        ext4dev = {
                features = has_journal,extents,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize
                inode_size = 256
                options = test_fs=1
        }
        small = {
                blocksize = 1024
                inode_size = 128
                inode_ratio = 4096
        }
 ...

この設定ファイルは、それぞれの形式でファイルシステムを作成する際に利用するオプション類を指定しています。このファイルを見る限り、ext4とext4devの違いは、test_fs=1というオプションを指定するかどうかだけのようです。このオプションを指定すると何が変わるのだろう、mke2fsのmanページ を調べてみました。

# export LANG=C ; man mke2fs
MKE2FS(8)                                               MKE2FS(8)

NAME
       mke2fs - create an ext2/ext3 filesystem
...
                  test_fs
                         Set  a  flag in the filesystem superblock indicating that it
                         may be mounted using experimental kernel code, such  as  the
                         ext4dev filesystem.

manページを見ると、test_fsというオプションは-Eで指定する拡張オプションの1つで、ファイルシステムのスーバーブロックに開発中のコードを使うことを示すフラグを立てる指定のようです。

「なるほど」と思って、mkfs.ext4devコマンドで再度ファイルシステムを作成し、Ext4dev/ext4機能を組み込みにしたカーネルでマウントできるか試してみました。

# mount /dev/sda2 /mnt -t ext4dev
EXT4-fs: sda2: Filesystem with huge files cannot be mounted read-write without CONFIG_LSF.
mount: wrong fs type, bad option, bad superblock on /dev/sda2,
       missing codepage or helper program, or other error
       In some cases useful info is found in syslog - try
       dmesg | tail or so

うーん、まだダメのようです。dmesgを調べても、⁠EXT4-fs: sda2:...⁠という同じメッセージが出力されているだけです。

カーネルの設定オプションの調査

CONFIG_LSFというのはカーネルをコンパイルする際のオプション指定のようなので、カーネルのビルドオプション設定ファイルである/usr/src/linux/.configを調べました。下記でgrepに与えている-C 3オプションは、該当する行の前後3行を合わせて表示するという指定です。

# grep -C 3 CONFIG_LSF /usr/src/linux/.config
CONFIG_BLOCK=y
CONFIG_LBD=y
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
CONFIG_BLK_DEV_BSG=y

なるほど、確かにCONFIG_LSFという設定はコメントアウトされて有効になっていません。このオプションはどこで指定するのだろう…、とmenuconfigの画面をあちこち探し回って、ようやく、Enable the block layer -> Support for Large Single Filesというオプションを発見しました。解説によると、2Tバイトを越えるような巨大なファイルを扱いたい時に指定するオプションだそうです。そんな巨大なファイルを扱う必要はないだろうと考えて、Plamo-4.5用のカーネル設定ではオフにしていた機能ですが、ext4 fsのヘルプメッセージにあったように、ext4 fsは16Tバイトを越えるようなファイルを扱えるように設計されているため、この機能を必要とするのでしょう。

改めてmake menuconfigでこのオプションを有効にした上でカーネルを再構築したところ、ようやくext4devファイルシステムが使えるようになりました。

# mount /dev/sda2 /mnt -t ext4dev
# dmesg | tail
...
EXT4 FS on sda2, internal journal
EXT4-fs: mounted filesystem with ordered data mode.
EXT4-fs: file extents enabled
EXT4-fs: mballoc enabled

なお、インストーラでOOM killerが発生していたのは、インストール用のパーティションがマウントできなかったため、 ramdisk上のmntディレクトリ以下にパッケージが展開されてしまい、ramdiskがメモリを使い果たしたせいでした。最新のカーネルといえども、利用可能なメモリがどんどん少なくなっていくという異常な状況は如何ともしがたかったようです。

grubの更新

上記の作業でext4 fsがルートファイルシステムの一種として利用可能になったものの、実際にext4 fsをルートファイルシステムに指定してインストールテストを行うと、インストールは無事終了するものの、再起動しようとするとgrubが正しく起動しません。

当初は「grubのインストールをミスったのかな?」と思って、インストーラのgrubからHDD上のカーネルを読み込ませようとしましたが、インストーラのgrubもファイルシステムの種類こそ ext2fs だと認識するものの、⁠Bad file or directory type⁠ 言ってファイルシステムの中身を読んでくれません。

図3 grubのエラーメッセージ
図3 grubのエラーメッセージ

一方、インストーラのシェルを操作して、手動でこのパーティションをマウントすることは可能です。

「どうもgrubがext4に対応していないみたいだ」と考えて、Googleでext4とgrubをキーワードに検索してみると、grub legacy(grub-0.97) はext4 fsで追加されたextents機能に対応していないこと、対応するためのパッチがすでにgrub開発者のメーリングリスト(bug-grub@gnu.org)に投稿されていることなどがわかりました。

パッチがあれば話は簡単、とブラウザからカット&ペーストしてパッチファイルを作り、ext4 fsに対応するためのパッチを適用しようとしましたが、画面を見易くするために長い行はブラウザが自動的に改行コードを挿入してくれるのか、カット&ペーストのままではあちこちでパッチファイルの不整合が生じています。

それでは、とソースコードをダウンロードして使おうとしても&等のHTMLのスペシャルキャラクタが邪魔をしてやはり正しく適用されません。

結局、パッチファイルを手で整形した上で、適用しそこねた部分は手動で修正し、再度差分を取り直すことで、何とか ext4 対応の grub をパッケージ化できました。作成した新しいgrubパッケージを使えば、TABキーを叩くとext4 fs上のファイル名もきちんと補完してくれました。

このgrubパッケージをPlamo-4.5のツリーに移して、ようやくext4 fsをルートファイルシステムとして使えるようになりました。

今回の例ではインストーラでの動作チェックやマウント状況の確認、grubでの動作チェックなど、段階を踏んで進めることができたため、それぞれの段階で発生した問題を比較的容易に解決できましたが、このトラブルが「ext4 fs 上にインストールすると起動しない」といった形で重合して発生した場合、要因の切り分けや原因の特定にはもっと時間がかかったことでしょう。トラブル解決の際には少々遠回りに見えても、ひとつひとつ条件を確認した上で進む方が、結局はより速く目的地に到着することがよくあります。

おすすめ記事

記事・ニュース一覧