2.開発プロセスの仕組み
1990年代の初めにおけるLinuxカーネルの開発は、ユーザーや開発者の数も比較的少なく、かなり自由な形で行われていました。しかし数100万人のユーザー基盤と1年間に2,000人もの開発者が関係するようになり、カーネルの開発が円滑に進められるよう、多くのプロセスを発達させることが必要でした。このプロセスの中で効率よく開発をするためには、このプロセスの仕組みについて確実に理解することが必要です。
2.1: 全体像
カーネルは、ほぼ2~3ヵ月に一回の割合で主要なリリースが行われます。最近のリリース履歴は以下のようなものです。
2.6.26:2008年7月13日
2.6.25:2008年4月16日
2.6.24:2008年1月24日
2.6.23:2007年10月9日
2.6.22:2007年7月8日
2.6.21:2007年4月25日
2.6.20:2007年2月7日
2.6.xのリリースは新機能の追加や内部APIの変更等が行われたカーネルの主要リリースです。標準的な2.6リリースには、10,000件を超える変更セットによる、数10万行のコード変更が含まれます。このように、2.6はLinuxカーネル開発の最新版です。またカーネルは連続的に主要な変更をマージしていくローリング開発モデルを使用しています。
各リリースにおけるパッチのマージに関しては、比較的単純な規律に従うようになっています。各開発サイクルの開始時に、「マージ・ウィンドウ」が開きます。この時点で、十分に安定していると見なされ開発コミュニティの承認が得られたコードがメインライン・カーネルにマージされます。この時、1日あたり1000件近い変更(「パッチ」または「変更セット」)の割合で、新しい開発サイクルの大部分の変更(および主要な変更のすべて)がマージされます。
(余談ですが、このマージ・ウィンドウ中にマージされる変更は、いずれも突然何も見えない状態から出てくるのではなく、すべて十分に前もってその収集、テスト、計画が行われていることが重要な点です。このプロセスがどのように行われるのかについては、この後で詳しく説明します。)
このマージ・ウィンドウは2週間続きます。この期間の満了時、Linus Torvaldsがウィンドウの閉鎖(クローズ)を宣言し、最初の「rc」カーネルをリリースします。たとえば最終的に2.6.26となるカーネルの場合、マージ・ウィンドウの終了時に発生するリリースは2.6.26-rc1と呼ばれます。この -rc1 リリースは、新機能をマージする期間が過ぎ、次のカーネルの安定化の時間が開始されたことのシグナルとなります。
次の6~10週間は、問題を修正するためのパッチのみをメインラインへと提出することが必要です。たまに、より重大な変更が許可される場合もありますが、そのようなケースは稀です。マージ・ウィンドウ以外のタイミングで新機能をマージしようとする開発者に対しては一般に友好的でない対応が行われます。一般的なルールとして、希望する機能がマージ・ウィンドウ中にマージできなかった場合、次の開発サイクルまで待つのが最善の方法です。(時折発生する例外として、従来は未対応だったハードウェアのドライバの追加があります。そのドライバがツリー内のコードにまったく関係しない場合、それによりリグレッション(退行)が発生するおそれはなく、いつでも安全に追加することができます。)
修正はメインラインで置き換えられるため、パッチの割合は時の経過とともに低下します。Linusは新しい -rc カーネルを約1週間に1回リリースします。カーネルが十分に安定したと考えられるのは通常 -rc6 から -rc9 の間で、その後最終的な 2.6.x のリリースが行われます。この時点で、全体プロセスが再び開始されます。
1例として、バージョン 2.6.25 の場合の開発サイクルの進捗を以下に示します(日付はすべて2008年です)。
1月24日:2.6.24 の安定リリース
2月10日:2.6.25-rc1、マージ・ウィンドウの終了
2月15日:2.6.25-rc2
2月24日:2.6.25-rc3
3月4日:2.6.25-rc4
3月9日:2.6.25-rc5
3月16日:2.6.25-rc6
3月25日:2.6.25-rc7
4月1日:2.6.25-rc8
4月11日:2.6.25-rc9
4月16日:2.6.25 の安定リリース
ひとつの開発サイクルを終了して安定リリースを作成するタイミングをどのように決定しているのでしょうか?最も重要な測定基準(メトリック)は、過去のリリースにおけるリグレッション・リストです。バグがないことは良いことですが、過去に正常に機能したものでもシステムを壊すものは特に深刻です。この理由から、リグレッションを起こすパッチは好ましくないものと見なされ、安定化期間中に元の状態に戻される可能性が高くなります。
開発者の目標は、安定リリースの前に既知のリグレッションをすべて修正することです。しかし、このような規模のプロジェクトにはあまりにも多くの変数があるため、そのような完璧な目標は現実には達成困難です。これ以上最終リリースを遅らせることは単に問題を更に悪化させるだけ、という時が来ます。すなわち、次回のマージ・ウィンドウに予定される変更の件数が大きく積み上がり、そのため次のサイクルでリグレッションが更に増加することになるという状態です。そのため、ほとんどの2.6.x カーネルは(深刻なものではないと望まれる)既知のリグレッションを少しだけ残した状態でリリースされます。
安定リリースが行われると、そのリリースの進行中の保守は「安定化チーム」(現在はGreg Kroah-Hartman とChris Wrightが担当)に任されます。安定化チームは必要に応じ、安定リリースに対する更新リリースを「2.6.x.y」という番号方式でリリースします。更新リリースとして考慮されるためには、そのパッチが(1) 重大なバグを修正するもので、(2) 既に次回リリースの開発カーネルのメインラインにマージ済みのものであることが必要です。ここで先程の2.6.25 の例を続けると、その履歴は(本文書の執筆時点で)以下のようになっています。
5月1日:2.6.25.1
5月6日:2.6.25.2
5月9日:2.6.25.3
5月15日:2.6.25.4
6月7日:2.6.25.5
6月9日:2.6.25.6
6月16日:2.6.25.7
6月21日:2.6.25.8
6月24日:2.6.25.9
これらのカーネルの安定リリースの更新は約6ヶ月間行われ、その後の保守はすべてその特定のカーネルを出荷したディストリビュータの責任となります。
2.2: パッチのライフサイクル
各パッチは、開発者のキーボードから直接メインライン・カーネルにマージされるわけではありません。その間には(いくぶん非公式な形の)多少複雑なプロセスがあり、これは各パッチの品質レビューを確実に行うよう、またそのパッチによる変更を望ましい形でメインラインにマージするようにするためです。このプロセスは軽微な修正の場合は迅速な処理が可能ですが、賛否両論のある大きな変更については何年もかかる場合があります。多くの開発者が思い通りにならず挫折するのは、このプロセスに対する理解不足や、このプロセスを迂回しようとする行動が原因です。
そのような失敗を少なくするため、本書ではパッチをカーネルにマージするための方法について解説しています。以下に示すのは、このプロセスをやや理想的な形で解説した手引きです。より詳細な取り扱いについては後のセクションで解説します。
一般にパッチは以下のように作成されております。
- 設計 - ここでは、パッチに対する要件(およびその要件を満足するための方法)が実際に計画される段階です。設計作業はコミュニティから独立して行われることも多いですが、この作業は可能な限りオープンな状態で行った方が後に再設計などで大きな時間をとられることがなくなり、良い結果が得られます。
- 早期のレビュー - パッチを関連するメーリングリストに投稿(ポスト)すると、そのリストに参加している開発者が適宜コメントを寄せます。プロセスがすべて順調に進めばそのパッチに重大な問題がある場合ここで見つけだすことができます。
- 広範囲のレビュー - パッチをメインラインにマージする状態が近くなった段階で、関連するサブシステムのメンテナーの承認を受けます。ただし、この承認は、そのパッチが最終的にメインラインにマージされることを保証するものではありません。パッチはメンテナーのサブシステム・ツリー上に現れ、後述のステージング・ツリー(準備段階のツリー)へと進みます。このプロセスがうまく機能した場合、この段階でそのパッチに対する広範囲なレビューが行われ、また他のメンバーが実施中の作業にそのパッチがマージされた結果に何らかの問題があればその内容が明らかになります。
- メインラインへのマージ - すべてうまく進んだ場合、パッチは最終的にLinus Torvaldsが管理するメインライン・レポジトリにマージされます。この時点で追加のコメントや問題点が浮上する場合もありますが、(パッチの)開発者はこれらに適切に対応して問題点を修正することが大事です。
- 安定リリース - 最近ではパッチの影響を受ける可能性があるユーザーの数が多くなっているため、ここでも新しい問題が発生する可能性があります。
- 長期保守 - 開発者はマージ済のコードについては忘れてしまうことも確かに可能ですが、そのような態度は開発コミュニティに対し悪い印象を与えます。コードをマージすることにより、API変更により発生する問題は誰かが修正してくれるという意味で、将来の保守作業の一部の負担が減らすことが可能です。しかし、そのコードが長期的に使われ続けるのであれば、開発元の開発者は引き続きそのコードに対する責任を負うべきです。
カーネル開発者(またはその事業主)が犯す最大の誤りは、このプロセスを「メインラインへのマージ」というひとつのステップで終わらせようとすることです。このようなアプローチは、まちがいなく関係者すべてにフラストレーションをもたらします。
2.3: パッチをカーネルにマージする方法
パッチをメインライン・カーネル・レポジトリにマージできるのはLinus Torvaldsだけです。しかし、2.6.25カーネルにマージされた12,000件を超えるパッチのうち、Linus自身が直接選んだのは250件(約2%)だけです。このカーネル・プロジェクトは長期にわたる成長を経て非常に大きな規模となったため、他から支援を受けずに1人の開発者、Linus Torvaldsがすべてのパッチを検査し選択することは事実上不可能となっています。カーネル開発者達がこの成長に対処した方法は、「信頼のチェーン」を中心に構築された代理システムを利用することです。
カーネルのコードは、ネットワーク、特定アーキテクチャーへの対応、メモリー管理、ビデオ・デバイスなどいくつかのサブシステムへと論理的にブレークダウンされます。ほとんどのサブシステムに1人の保守メンテナーが指名され、開発者でもあるその保守メンテナーがそのサブシステム内のコードについて全体的な責任を持ちます。これらサブシステムのメンテナーは、その管理するカーネル部分の(あまり厳格でない)門番として活動し、(通常は)パッチをメインライン・カーネルに含める際の承認を行います。
サブシステムのメンテナーは、(必ずではありませんが)通常はソース管理ツールであるgitを使い、それぞれ自分自身用のカーネル・ソース・ツリーを管理します。その他の関連ツール(quiltやmercurial)も含め、gitのようなツールを使うことでメンテナーは作者情報やその他のメタデータも含め、パッチのリストを追跡調査することができます。メンテナーは、自分のレポジトリにはあるがメインラインには含まれていないパッチをいつでも特定できます。
マージ・ウィンドウが開くと、最上位レベルのメンテナーは自分たちがレポジトリから選択したマージ用のパッチを「プル(引き出す)」するようLinusに依頼します。Linusが同意すれば、パッチの流れはLinusのレポジトリへと流れ込み、メインライン・カーネルの一部となります。この「プル」操作で受け取った特定のパッチに対するLinusの関心の度合いは一様ではありません。明らかに、一部について、彼はかなり詳細なレベルまで確認を行っています。しかし、概してLinusは粗悪なパッチがアップロードされることはないという面でサブシステムのメンテナーを信頼しています。
一方、サブシステムのメンテナーも他のメンテナーからパッチをプルすることができます。たとえば、ネットワーキング・ツリーは、まずネットワーク・デバイス・ドライバや無線ネットワーク等の専用のツリーに集積されたパッチで構築されます。このレポジトリ・チェーンの長さは任意の長さに伸ばすことができますが、通常2~3リンク以内におさまっています。そのチェーンのメンテナーはそれぞれその下位のツリーのメンテナーを信頼していることから、このプロセスは「信頼のチェーン」と呼ばれています。
明らかに、このようなシステムの場合、パッチのカーネルへのマージは適切なメンテナーを見つけることに依存しています。パッチを直接Linusに送付するのは、一般に適切な方法ではありません。
2.4: ステージング・ツリー
サブシステム・ツリーのチェーンは、カーネルへとマージされるパッチの流れを導くものですが、ここでもうひとつ興味深い問題があります。それは、次のマージ・ウィンドウに向けて準備中のパッチのすべてを誰かが見たい場合はどうするか、という問題です。開発者は、問題となるコンフリクト(競合)がないかどうかを確認するため、他の部分で準備中の変更にはどのようなものがあるかに関心があると考えられます。たとえば、コア・カーネル関数のプロトタイプを変更するパッチが、その関数の旧バージョンを使用する他のパッチとの間で競合を生じる場合などが考えられます。レビューやテストを行う人は、変更がすべてメインライン・カーネルにマージされる前に、それらの変更がマージされた状態にアクセスしたいと考えます。関心のあるすべてのサブシステム・ツリーから変更をプルすることも可能ですが、これは大きな作業であり間違いの発生しやすい方法です。
このような問題に対する解答がステージング・ツリーで、各サブシステム・ツリーをこのステージング・ツリーに集めてテストやレビューを行います。これらのツリーは従来よりAndrew Mortonが管理するツリーがありました。これは最初に開始されたときの「メモリー管理」という意味で「-mm」と呼ばれています。この -mm ツリーはサブシステム・ツリーの長いリストからパッチを集めてマージするもので、このツリーにはデバッグ作業に役立つパッチも含まれています。
それ以上に、この -mm にはAndrew自身が直接選定したパッチの大きなコレクションが含まれています。これらのパッチはメーリングリストにポストされたものや、指定のサブシステム・ツリーがないカーネル部分に適用されるパッチなども含まれています。その結果、 -mm は最後の頼みとなるサブシステム・ツリーとして機能します。すなわち、パッチをメインラインにマージするための明確な経路が存在しない場合、最終的には -mm を経由する可能性が高くなります。この -mm内に蓄積される種々雑多なパッチは最終的には適切なサブシステム・ツリーに送られるか、または直接Linusへと送られます。標準的な開発サイクルでは、メインラインにマージされるパッチのうち約10%が -mm を経由します。
最新の -mm パッチは、常に以下のページのフロントページに置かれています。 http://kernel.org/
また -mm の最新の状態を見たい場合は、以下のサイトから「-mm of the moment」ツリーを入手できます。
http://userweb.kernel.org/~akpm/mmotm/
ただし、コンパイルさえ不可能という場合もあり、MMOTMツリーの利用はかなり困難なものとなる可能性があります。
最近開始されたその他のステージング・ツリーとして、Stephen Rothwellが管理する linux-next があります。この linux-next ツリーは、その設計上、次回のマージ・ウィンドウが閉じた時にどのような形のメインラインが期待されるかを示すスナップショットとして提供されます。この linux-nextツリーは、その集約後、linux-kernelおよび linux-nextの各メーリングリストで通知され、以下のサイトからダウンロードが可能です。
http://www.kernel.org/pub/linux/kernel/people/sfr/linux-next/
この linux-next に関する一部の情報は以下のサイトに集められています。
http://linux.f-seidel.de/linux-next/pmwiki/
この linux-next ツリーを開発プロセスにマージする方法は、現在も変化を続けています。この文書を執筆した時点は、(2008年7月初旬)linux-next が関係した最初の完全な開発サイクル(2.6.26)が終りに近づいている段階です。これまでのところ、マージ・ウィンドウの開始前にインテグレーションに関係する問題を発見し修正する上で、このリソースの高い価値が実証されています。この linux-nextが2.6.27マージ・ウィンドウのセットアップにどう使われたか、その詳しい内容についてはhttp://lwn.net/Articles/287155/ をご覧ください。
一部の開発者は、将来の開発にも linux-next をターゲットとして使うべきだという提言を始めています。このlinux-next ツリーは、メインラインよりも大きく先行する傾向があり、新しい成果がマージされるツリーとしての性格がより強くなっています。ただしこの考え方の弱点として、 linux-next の不安定さに起因する、開発ターゲットとして使う場合の困難さがあります。この話題についてはhttp://lwn.net/Articles/289013/ を継続的にご覧ください。linux-nextに関してはすべてが依然として流動的です。
2.5: ツール
以上述べたように、カーネル開発プロセスはパッチの集合をあらゆる方面で把握し管理することのできる能力に大きく依存しています。それに適した強力なツールがなければ、カーネル全体が現在の状態やそれに近い状態で開発を続けることはできません。これらツールの使用方法を解説することは本文書の範囲を大きく超えていますが、ここでは多少のスペースを使い、リンク先をいくつか示します。
カーネル・コミュニティが圧倒的に主流のツールとして使うソースコード管理システムは gitです。gitは、フリーソフトウェアのコミュニティで開発され配布されている多数のバージョン管理システムのうちのひとつです。これは特に大きなレポジトリや多数のパッチを扱う場合の性能が優れているという意味で、カーネル開発用に良くチューニングされています。また、長い期間を経て改善されてはいますが、その習得や使用が難しいという評判もあります。カーネル開発を行う上で、仮に自分の仕事には使わない場合でも、他の開発者やメインラインで行われていることに遅れをとらないためには、gitをある程度熟知することはほとんど必須要件となっています。
現在、ほとんどすべてのLinuxディストリビューションにはgitが同梱されています。gitのホームページを以下に示します。
このページには資料や手引きへのリンクが含まれています。特に、以下に示す「Kernel Hacker's Guide to git(カーネル・ハッカーのgitガイド)」には、カーネル開発に特有の情報が含まれています。
http://linux.yyz.us/git-howto.html
gitを使わないカーネル開発者の中での最もポピュラーな選択は、まちがいなく以下のMercurialです。
http://www.selenic.com/mercurial/
Mercurialの多くの機能は git と共通ですが、多くの人から使いやすいと評判のインタフェースが提供されています。
それ以外で知っておく価値のあるツールは以下のQuiltです。
http://savannah.nongnu.org/projects/quilt/
Quiltは、ソースコード管理システムというよりもむしろ、パッチ管理システムです。このツールは時系列による履歴の追跡は行わず、その代わりに改良されるコードのベースに対する特定の変更セットを追跡します。一部の有力なサブシステムメンテナーは、quiltを使って上流へと流す予定のパッチを管理しています。ある特定の種類のツリー(たとえば-mm)の管理を行う場合、そのような作業にはquiltが最適なツールとなります。
2.6: メーリングリスト
Linuxのカーネル開発作業の多くはメーリングリストを通じて行われます。このコミュニティのメンバーとしての完全な役割を果たすためには、少なくともひとつのメーリングリストに参加することが不可欠です。しかし、Linuxのメーリングリストは開発者にとって潜在的な危険性をはらんでおり、電子メールの山に埋もれてしまったり、Linuxメーリングリストで用いられる慣習と衝突してしまったりする危険性があります。
大部分のカーネル・メーリングリストは vger.kernel.org を中心としており、そのマスター・リストは以下の場所にあります。
http://vger.kernel.org/vger-lists.html
それ以外にホストされているメーリングリストがたくさんあり、その多くは redhat.comにあります。
カーネル開発の中核となるメーリングリストは、もちろんlinux-kernelです。このメーリングリストは非常にプレッシャーの高い場所です。すなわち、1日に500件ものメッセージが発信され、ノイズも多く、会話の内容は高度な技術的内容で、また参加者はそれなりの礼儀正しさを心得ているとはかぎりません。しかし、カーネル開発コミュニティ全体が一堂に会する場所は他にありません。開発者がこのメーリングリストを避けてしまえば重要な情報が得られないというリスクを犯してしまう可能性があります。
ここで、linux-kernelで生き残るために役立つヒントがいくつかあります。
- 自分が主に使うメールボックスではなく、別のフォルダにリストが自動配信されるようにすること。長時間継続してこの流れを無視できることが必要です。
- すべての話についていく努力をしないこと。誰もそのようなことは考えません。関心のあるテーマや参加者によるフィルタリングを行うことが重要です(ただし、長く続いたやりとりの場合、メールの件名を変更せずに当初のテーマから外れてしまっている場合があります)。
- 「荒らし」を相手にしないこと。誰かがその場をかき回して怒りの反応を得ようとしている場合、これを無視します。
- linux-kernelのメール(または他のリストのメール)に回答する場合、関係者全員に伝わるよう Cc: ヘッダーはそのまま保存します。(明示的な依頼などの)特別な理由がない限り、決して宛先を変更、削除すべきではありません。自分が回答を送ろうとする相手がCc: リストに含まれていることを常に確認します。この約束事があるため、自分のポストに対する応答に自分をCC:の宛先に含めるよう明示的に依頼することも不要になります。
- 質問する前にリストのアーカイブ(およびネットの全体)を検索し調べること。一部の開発者は、明らかに自分がやるべきこと(宿題)をやらずに質問する人に対して我慢ができません。 - トップ・ポスティング(回答の対象となる引用したテキストの上に自分の返事を置くこと)を避けること。これを行うと、その返事が読みにくくなり、貧弱な印象を与えます。
- 正しいメーリングリスト上で質問すること。Linux-kernelは全体会議の場ですが、すべてのサブシステムからの開発者を見つけるための最適な場所ではありません。
最後のポイントとして、「正しいメーリングリストを見つけること」は、初心者の開発者が間違えやすいことです。ネットワーキングに関係する質問をlinux-kernel上で行った場合、 ネットワーキングに関係する開発者の多くはnetdev リストに参加していることから、netdev リストで質問するよう求める親切なメールがだされるでしょう。それ以外にも、SCSI、video4linux、IDE、filesystem等の各サブシステム用のリストがあります。メーリングリストを探す時の最適な情報は、カーネルのソースにパッケージされているMAINTAINERSファイルにあります。
2.7: カーネル開発の開始
カーネル開発プロセスに着手する方法についての疑問は、個人からの場合でも企業からの場合でも、いずれも同じようなものです。さらに両者が同じように持っている問題は困難なものにしてしまう、様々な失策についてです。
企業は、開発グループを立ち上げるため、名の通った開発者に頼る場合が多くなります。たしかにこれはひとつの有効な手法となり得ます。しかし、これは費用がかさむ場合が多く、また経験の深いカーネル開発者の数を増やすことにはほとんどつながりません。多少の時間を投資して社内の開発技術者を育成し、Linuxカーネルの開発を加速することも可能です。その事業主はこのような時間をかけることにより、カーネルと企業の両方をよく理解し、同時に他のメンバーも教育できる開発者のグループを確保することができます。中期的に見れば、このようなアプローチの方がより有益な場合が多いでしょう。
当然のことですが、個々の開発技術者はどこから最初に手を付けたら良いか、途方に暮れてしまいます。人は最初から大きなプロジェクトを手がけることにはおじけづくもので、最初は何か小さなもので試してみたいと考えます。一部の開発者は、このような段階でスペルミスや軽微なコーディング・スタイルの問題を修正するためのパッチの作成に飛び込みます。残念ながらそのようなパッチは開発コミュニティ全体を混乱させるノイズとなり、その開発者はますます侮りを受けるようになります。このコミュニティへの参加を望む新人の開発者は、このような手段では自分の望んだ歓迎を受けることができません。
Andrew Mortonは向上心のあるカーネル開発者に対し以下のように助言しています。
すべてのカーネル開発の初心者が第一に考えるべきことは、「そのカーネルを、自分の扱えるすべてのマシン上で常に完全な形で実行可能にすること」です。通常、このためには、その物事をまとめるための他人との共同作業が必要になります(これには忍耐が必要です!)。しかし、これは問題ありません。これもカーネル開発の一部です。
(http://lwn.net/Articles/283982/ )
明らかに修正を必要とする問題がない場合の開発者への助言は、まず最新のリグレッションや未解決バグのリストを確認することです。修正を必要とする問題が不足することは決してありません。そのような問題に取り組むことにより、開発者はそのプロセスについての経験を積み、同時に開発コミュニティの他のメンバーから尊敬される関係を築くことができます。



