8月版 ブート時間の短縮にかけるカーネルアスリートたち
小崎資広
2008/9/1
OLS(Ottawa Linux Symposium)が終わって気分も一新、Linuxカーネルメーリングリスト(LKML)でのパッチの投稿ペースがまた上がってきています。
先日、某所で議論したところ、2008年のOLSのハイライトは
- 基調講演でTOMOYO LinuxがTOMOYA Linuxと呼ばれていた
- Tシャツの平均サイズが10年間でMからXLに成長。みんな大きくなったね
だとか。
関連記事: | |
オタワで聞いた“Thanks to Japanese Community”の声(@IT Security&Trust) http://www.atmarkit.co.jp/fsecurity/special/127ottawa/ottawa01.html |
それでは、2008年8月のLKMLでどんなことが起きたのか見てみましょう。
ブート高速化フレームワークの開発始まる
OSのブート処理の1つに、デバイスを初期化する処理があります。これによりさまざまなデバイスが使用可能になり、ディスクやネットワークといったリソースが使えるようになるわけです。
従来、Linuxの起動処理において、デバイスドライバの初期化は1つ1つシーケンシャルに処理されていました。このため複数のCPUを活用することができず、また初期化に時間がかかるドライバがあると全体の起動時間までが延びてしまうという問題がありました。また、例えばUSBコントローラはハードウェア的な制限のため、ポート数に比例して所要時間が延びてしまうという問題があり、そのようなデバイスの場合、ドライバを個別に最適化させる努力だけでは初期化時間の短縮は難しいという状況でした。
これに対し、Irqbalance、PowerTOPなどの開発で有名なArjan van de Venが、ブート時間を高速化させるパッチシリーズの開発に着手し、「fastbootパッチ」シリーズとして、精力的にパッチを投稿しています。
基本的なアイデアはシンプルです。Linuxのデバイスドライバはそれぞれ、モジュール初期化関数と呼ばれる関数を持っています。ドライバが定められた作法に従って記述するだけで、その初期化関数が、カーネルが持つ初期化関数テーブルに登録されます。そしてカーネルは、起動時にその初期化関数を順次呼び出すという処理を行っています。
そこでこの部分に「非同期初期化関数用」のテーブルを新設し、ドライバを1行ほど変更し、そちらのテーブルにもモジュール初期化関数を登録できるようにします。そしてカーネルは、ブート時にこちらの非同期初期化関数を呼び出します。Work Queue(注1)を使って呼び出した処理の完了を待たずに以降の処理を次々と呼び出し、それらは非同期的に実行されます。
このような仕組みを取ることにより、もし初期化に時間がかかるデバイスがあったとしても、ほかのデバイスの処理には影響が及びません。結果として、ブート時間が大幅に短縮します。Arjanによれば、USBコントローラとACPIのいくつかの初期化を非同期動作させるだけで、カーネルの初期化時間は1.9秒から1.5秒へと、0.4秒短縮できたそうです。
もちろん、中にはRAIDドライバのように、別のドライバに依存しているドライバもあります。このように、従来の処理順序に暗黙のうちに依存してきたドライバには修正が必要になるため、すぐさま全ドライバを非同期処理に変更することはできません。
しかしながら、そのような暗黙の依存関係さえなければ、ドライバ自体の変更内容は、module_init()という行をmodule_init_async()に変更するだけという、極めてシンプルなものです。今後、それほど時間がかからずにドライバ側の対応が進むのではないかと期待されています。
注1:Linuxが持っている汎用的な非同期処理の仕組み |
ファイルディスクリプタリークを防げ!
glibcのメンテナであるUlrich Drepperによる「close-exec拡張パッチ」が、2.6.7-rc1においてマージされました。
Ulrichはこのパッチは、「従来の手法が持っていたセキュリティリスクを解決するパッチだ」と主張しています。それでは、従来の方法の欠点とは何だったのでしょうか。
Ulrichによると、そもそも、open()システムコールとfcntl(FD_CLOEXEC)とが、2つの手順に分離されていることが問題だといいます。もし「open」と「fcntl」という2つの処理のすき間で、別スレッド、またはシグナルハンドラからforkが呼ばれると、ファイルディスクリプタが閉じられずにリークしてしまいます。もし、execしたプログラムに脆弱(ぜいじゃく)性が含まれていた場合、親プロセスがオープンしていたファイルまでもが危険にさらされることになります。
ここで、fork()が「signal-safe」なシステムコール(シグナルハンドラから呼ばれ得るという意味です)であることが、話をさらにややこしくしています。
シグナルハンドラでは、pthred_mutex_lock()などのロック関数が使えないので、セキュアなコードを書くのは一般的に非常に困難です。仕方がないので、open-fcntl間にシグナルが割り込まないよう、openのたびにシグナルマスクを操作するという手法が取られてきましたが、これは、サーバ分野において受け入れ難い性能低下を引き起こしていました。
では、forkした側がexecする前に全ファイルディスクリプタをcloseすればいいかというと、そうもいきません(注2)。ブラウザやWebサーバのように、アプリケーションがプラグイン型のアーキテクチャになっている場合、forkを呼び出すのはプラグインかもしれません。そのような場合、全プラグインに対して統制を取るのはなかなか難しいという問題がありました。
そのため、openシステムコールに「O_CLOEXECフラグ」を追加し、このフラグを指定すると、オープンと同時にclose-execをONにできるようにするという解決方法が選択されました。
またLinuxにおいては、open以外にも新規ファイルディスクリプタを作成して返却するシステムコールは大量にあります。そのすべてにおいて、フラグ引数に「XX_CLOEXECフラグ」を追加する、またはフラグ引数を追加した新システムコールを新設するという修正が行われました。
ついでにというわけでもないのでしょうが、今回追加されたフラグ引数はすべて、XX_CLOEXECだけではなくXX_NONBLOCKフラグも取れるようになっており、利便性が少しだけ向上しています(close-execと違って、2手順に分かれていてもそんなに問題のない機能ですから、ポータビリティが落ちるのを覚悟で使う価値があるかはちょっと疑問ですが……)。
この機能、どれだけのアプリケーションが使うのか若干疑問な部分もありますが、glibcが対応を表明しているため、意外とすぐに普及するかもしれません。
|
注2:これは以下のようなコードで行います。 int open_max = sysconf (_SC_OPEN_MAX); for (int i = 3; i < open_max; i++) close(i); 注3:つまり、socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC, ...)のような形で使えということです。最初はフラグ引数を追加した新システムコールを新設する方向で提案されていたのですが、Alan Coxがむやみにシステムコールを増やすなといい出してこの形に。どう見ても汚いと思うんだけど……。 |
7月版へ |
1/2 |
|
||||
|
連載 Linux Kernel Watch |
Linux Squareフォーラム Linuxカーネル関連記事 |
連載:Linux Kernel Watch(連載中) Linuxカーネル開発の現場ではさまざまな提案や議論が交わされています。その中からいくつかのトピックをピックアップしてお伝えします |
|
連載:Linuxファイルシステム技術解説 ファイルシステムにはそれぞれ特性がある。本連載では、基礎技術から各ファイルシステムの特徴、パフォーマンスを検証する |
|
特集:全貌を現したLinuxカーネル2.6[第1章] エンタープライズ向けに刷新されたカーネル・コア ついに全貌が明らかになったカーネル2.6。6月に正式リリースされる予定の次期安定版カーネルの改良点や新機能を詳しく解説する |
|
特集:/procによるLinuxチューニング[前編] /procで理解するOSの状態 Linuxの状態確認や挙動の変更で重要なのが/procファイルシステムである。/procの概念や/procを利用したOSの状態確認方法を解説する |
|
特集:仮想OS「User
Mode Linux」活用法 Linux上で仮想的なLinuxを動かすUMLの仕組みからインストール/管理方法やIPv6などに対応させるカーネル構築までを徹底解説 |
|
Linuxのカーネルメンテナは柔軟なシステム カーネルメンテナが語るコミュニティとIA-64 Linux IA-64 LinuxのカーネルメンテナであるBjorn Helgaas氏。同氏にLinuxカーネルの開発体制などについて伺った |
|
|
- 【 pidof 】コマンド――コマンド名からプロセスIDを探す (2017/7/27)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、コマンド名からプロセスIDを探す「pidof」コマンドです。 - Linuxの「ジョブコントロール」をマスターしよう (2017/7/21)
今回は、コマンドライン環境でのジョブコントロールを試してみましょう。X環境を持たないサーバ管理やリモート接続時に役立つ操作です - 【 pidstat 】コマンド――プロセスのリソース使用量を表示する (2017/7/21)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、プロセスごとのCPUの使用率やI/Oデバイスの使用状況を表示する「pidstat」コマンドです。 - 【 iostat 】コマンド――I/Oデバイスの使用状況を表示する (2017/7/20)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、I/Oデバイスの使用状況を表示する「iostat」コマンドです。
|
|