VMware上のUbuntuで最新カーネルをビルドする

TOMOYO Linuxの2度目のLKML投稿を間近に控え、手元に環境を用意しておくことにした。VMware仮想マシンとして、カーネルコンパイル環境を用意する。備忘録もかねてここに記録しておくことにする。

最新のカーネルでなく、Ubuntu用に配布されているカーネルのビルドであれば下記が参考になる。

準備

最初のつまずきは、仮想マシンの容量だった。デスクトップ環境自体を使うことがメインではないので、4GBで仮想マシンを定義したが、gitでLinuxのツリーのダウンロードまではできたが、ダウンロードしたカーネルコンパイル中にout of spaceになってしまった。その後小刻みに増やしてみたが、結論としては、8GB程度(VMwareのデフォルト)用意することで落ち着いた。後から知ったのだが、Ubuntuでは2007年8月4日から導入済みの仮想マシンデータも配布していた。こちらは最大容量20GB、領域は利用時に自動拡張となっており、インストールの手間が省けるし、OpenOffice等は含まれていないので、今回のような開発向き作業には適しているかもしれない。親切なことにVMware toolsも含まれている(涙)。但し、仮想マシンのファイルサイズは利用時に自動拡張するようになっているので(そうでなければ仮想マシンファイルが20GBになるから当然だ)、少しでもパフォーマンスを良くしたければ最初から固定領域確保が有効だろう。

仮想マシンのネットワークの設定は、NATにした。Ubuntu自体のインストールは、デフォルトのまま。

仮想マシンのデスクトップやコンソールで作業するのは窮屈?なので、何はともあれ、sshで外から入れるようにしておく。ついでにsudo passwd rootで、rootパスワードを設定しておく。

  1. sudo apt-get update
  2. sudo apt-get install ssh(これでopenssh-serverとsshクライアントの両方が導入される)
  3. sudo passwd root
  4. sudo apt-get dist-upgrade(かなり時間がかかる)

パッケージの導入

Ubuntuのパッケージは「至れり尽くせり」という感じだが、もともとカーネルをカスタマイズするような使い方を想定したものではないから準備が必要だ。

  • build-essential(これがなくては/usr/includeすらない)
  • kernel-package
  • libncurses5-dev(make menuconfigを行うために必要。本来kernel-packageに入っていると良いような気がする)
  • subversion, subversion-tools(TOMOYOのレポジトリの参照用)
  • quilt(もともとはAndrew Mortonが作成したパッチ管理用ツール。自分で使うことはないだろうけれども一応。依存関係でgawkとdiffstatが導入された)

もし、rootでコンパイルしたくなければfakerootもあると良い。

最新カーネルの入手

gitが使える環境ならgitを使うのが良い。

% sudo apt-get install git git-core(gitだけだとgit-colneなど入らないようだ)

gitでLinuxのツリーを複写した。

haradats@tomoyo:~$ cd /usr/src
haradats@tomoyo:/usr/src$ sudo git-clone git://git.kernel.org/pub/scm/linux/kernel/git/tor
valds/linux-2.6.git
Password:
remote: Generating pack...
remote: Done counting 548872 objects.
remote: Deltifying 548872 objects...
remote:  100% (548872/548872) done
Indexing 548872 objects.
remote: Total 548872 (delta 445805), reused 548479 (delta 445454)
 100% (548872/548872) done
Resolving 445805 deltas.
 100% (445805/445805) done
Checking files out...
 100% (22466/22466) done
haradats@tomoyo:/usr/src$

会社の中からのアクセス等で、gitが使えない場合はwww.kernel.orgから安定版のソースを選び、をwgetしよう。

% sudo apt-get install wget
% cd /usr/src
% sudo -s
% wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.22.5.tar.bz2
% tar xfj linux-2.6.22.5.tar.bz2

Configを決める

ポイントとしては、

だけだが、さらでmake menuconfigをしたところ、CONFIG_DEBUG_INFOがy(有効)になっていた。この日記を読んだ方から、イメージのサイズがばかでかくなると教えていただいたので無効にしたが、考えてみると

% sudo cp arch/i386/defconfig .config
% sudo make menuconfig

が筋だろう。TOMOYO LinuxのLXRで調べてみたところ、CONFIG_DEBUG_INFOのデフォルト設定の値は、arch毎にばらばらだ。i386を含めてほとんどは無効になっているが、alpha等一部では有効になっている。make menuconfigでは、「kernel Hacking ---> Kernel debugging」の下に「Compile the kernel with debug info」という項目として(結構深いところに)存在している。今回は、Kernel debugging自体を無効にした。

make-kpkgでdebパッケージを作成する場合、CONFIG_DEBUG_INFOの有無でどのくらい大きさが変わるか実験してみた。

  • CONFIG_DEBUG_INFOなし 19741080
  • CONFIG_DEBUG_INFO=y 199498326

実際にはdebだけでなく個々のオブジェクトのサイズも大きくなるので、ここに書かれているように必要がなければ無効にすべきだろう。なお、CONFIG_SECURITY_SELINUXについては、CONFIG_DEBUG_INFOとは異なり、arch毎のデフォルトはなく、arch/i386/defconfigにも含まれていなかったから、make menuconfigで無効にする必要もない。

ビルド

ここまできたらあとは簡単だ。

% sudo make-kpkg --initrd --append_to_version .tomoyo kernel_image

コンパイル環境を作った後では、TOMOYO Linuxのパッチを当てるので、2.6.22.3.tomoyoという名前にすることにした。".tomoyo"を"tomoyo"にすると、2.6.22.3tomoyoになってしまうので要注意?だ。ノートPC+VMwareなので、ビルドにはかなり時間がかかる。

問題発生

ビルドが成功したら、1つ上のディレクトリにdebファイルができているが、それをdpkg -iで導入して再起動をする前に、/boot/grub/menu.lstを編集しておくべきだ、ということに気がついたのは作成したカーネルがフリーズしたおかげだ(笑)。

導入したカーネルをパッケージとしてインストールした場合、そのカーネルがデフォルトとして登録される。timeoutパラメータはデフォルトでは3(秒)なので、導入したカーネルが動かない場合は大変困ったことになる。なので、今後の作業に備えてtimeoutの値は15秒程度に増やしておき、かつdefaultは0(導入した新しいカーネル)でなく、古い(動作する安全な)カーネルを指すようにしておくと良い。また、他はわからないが、Ubuntuではsplashとquietが勝手に追加されるので、起動に失敗した場合何も見えないから、新たに追加したエントリーについてはそれらを削除したほうが良い。

「フリーズ」の症状は、Ubuntuのおなじみの起動画面が表示されて、プログレスバーの最初の目盛りが表示されたところでだんまりになり、そのまま10分くらい放っておくと、「BusyBox v1.1.3」としてBusyBoxのシェルが表示される。プロンプトは、「(initramfs)」となっている。lsを実行したり、BusyBoxのヘルプを見るだけならこれでも良いが、残念ながらこれではやりたいことができない。「フリーズ」の原因は二つで、ひとつはごく初歩的な、もうひとつはえらく複雑な話だった。

  1. VMwareではHDをSCSIとして見せるので、configには該当するオプションを指定しなければいけないがしていなかった(笑)
  2. 少なくともVMwareの5.4以前のバージョンでは、Linuxカーネル2.6.21以降のSCSIの変更に追随しておらず、その結果、configで必要なオプションを追加していたとしてもHD(root fs)を認識できず死んでしまうらしい*1

後者についてこんな情報が見つかった。

事態は複雑かつややこしい。ひと言で言うと「VMware側のバグ」ということのようだが、どうやら6.0でもまだ対応されていないらしい。3番目のリンクに含まれているパッチは、2番目のVMware掲示板の上のほうに含まれているものと同じで、drivers/message/fusion/mptbase.cに対するもので、試してみたら無事起動できた。

--- linux/drivers/message/fusion/mptbase.c.orig	2007-03-20 13:47:28.000000000 -0700
+++ linux/drivers/message/fusion/mptbase.c	2007-03-23 17:45:51.000000000 -0700
@@ -2564,6 +2564,16 @@
 	pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
 	pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
 	pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
+	/*
+	 * VMware emulation is broken, its PortFact's MaxDevices reports value
+	 * programmed by IOC Init, so if you program IOC Init to 256 (which is 0,
+	 * as that field is only 8 bit), it reports back 0 in port facts, instead
+	 * of 256...  And unfortunately using 256 triggers another bug in the
+	 * code (parallel SCSI can have only 16 devices).
+	 */
+	if (pfacts->MaxDevices == 0) {
+	   pfacts->MaxDevices = 16;
+	}
 	pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
 	pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
 	pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);

(但し、このスレッドには「これより良い」という違うパッチも投稿されている)

動作を確認した環境は、

  • Ubuntu 7.04Desktop(このページの上にリンクがある仮想マシンデータ)
  • 2.6.22.5カーネル
  • configは、さらからmake menuconfigして、SELinuxとKnernel Hackingを無効にしたもの

本来VMware側の問題なのにカーネル側で暫定*2対処するのは好ましくないかもしれないが、「とにかくVMwareで2.6.21以降のカーネルコンパイルしたい」という方は、下記パッチを当てると良い。

*1:これが本当ならもっと世界中にたくさん困っている人があるはずだが、どうも検索してもそれほど情報が見つからない。何故だ?

*2:このパッチはLinux自体に取り込まれることはないからずっと暫定のままとなる