玩式草子─ソフトウェアとたわむれる日々

第87回Linuxの成長過程をふりかえる[その5]

前々回に引き続き、今回はlinux-2.3シリーズの成長過程を検討します。

linux-2.2を元にした開発版シリーズであるlinux-2.3は、1999年5月に公開されたlinux-2.3.0から始まり、2000年3月のlinux-2.3.51でいったん開発は終了しました。

2年強の開発期間がかかった2.1シリーズに比べると、2.3シリーズの開発期間は1年弱と短かかったものの、2.3.51の後にデバッグやテスト用に公開された2.3.99-preX2.4.0-testXXの期間が9ヵ月近く続き、最終的に次の安定版であるlinux-2.4.0が公開されたのは、2001年1月4日でした。

カーネルサイズの変遷グラフからlinux-2.2と2.3の部分を取り出して描くと、図1のようになります。

図1 linux-2.2.xとlinux-2.3.xのサイズの変遷
図1 linux-2.2.xとlinux-2.3.xのサイズの変遷

この結果を見ると、linux-2.2シリーズは「安定版」として公開されたものの、かなりの期間2.3シリーズと併走するようにサイズが増加し続け、ソースコードの増加が収まるのは次の安定版である2.4シリーズが公開されてからです。

回を改めて紹介する予定ですが、2.4シリーズも公開されてからずいぶん長い間サイズが増加し続けており、linux-2.xでは開発版で追加された新機能が安定版に随時反映されていたようです。

linux-1.xでは、80386CPUに依存したコードを全面的に書き改めたり、SMPに対応するためにカーネルの内部構造が大きく変更されるなど、開発版と安定版の間の互換性が低かったのに対し、2.xではそれら大規模な変更が落ちついてきた結果、開発版の新機能を安定版に取り込むことが可能になりました。

ディレクトリサイズの変化

それではlinux-2.3シリーズでどのような機能が追加されてきたのか、ディレクトリサイズの変化から検討してみることにします。今回チェックしたのは2.3.02.3.182.3.332.3.51の4つのバージョンです。この4バージョンについてサイズの大きい6つのディレクトリを比較したのが図2です。

図2 linux-2.3シリーズのディレクトリサイズの変遷(1)
図2 linux-2.3シリーズのディレクトリサイズの変遷(1)

図2を見るとarchdriversディレクトリはlinux-2.3シリーズ全体に渡ってかなり速いペースで増加し続けており、この期間中も積極的に新しいCPUへの対応が行われていたことがわかります。

具体的にどのようなCPUに対応してきたのかをarchディレクトリのサイズから調べると、下表のようになりました。なお、表中の数字の単位はKB(キロバイト)です。

表1 linux-2.3シリーズの対応CPUとarchディレクトリのサイズ
2.3.02.3.182.3.332.3.51
alpha968928936996
arm584110012001200
i3861200120013001300
ia64 - - - 920
m68K2200250025002400
mips948130013001400
mips64 - - - 700
ppc1500200023002400
sh - - 240272
sparc1500150015001300
sparc641600150015001600
total11000120001300015000

この結果を見ると、組込み用に広く使われていたSH系のCPUに2.3シリーズの中ごろで対応し、後期ではIA64MIPS64といった64ビットCPUに対応するなど、種類も用途もさまざまに異なるCPUに貪欲に対応していったことがうかがえます。

実はこの傾向は2.3.51から2.4.0の間でも続き、linux-2.3.99-preXの段階でIBMの汎用機であるS390用のコードが、linux-2.4.0-testXの段階でHPがワークステーション用に開発していたPA-RISC用のコードが、それぞれarchディレクトリにマージされています。

バージョン付けの慣例に従うなら、2.3.99-preXというバージョンは2.3系で追加した新機能を落ちつかせる安定化段階用、2.4.0-testXは2.4.0に向けたRC(Release Candidate)として最終調整用とするものですが、この時期のlinuxはそのような慣習を無視して、⁠安定版」のリリース直前まで新機能を追加し続けていました。

一方、サイズが小さいディレクトリの変遷を示したのが図3です。これらのディレクトリには、各種CPUやドライバが共通に利用するコードや、カーネルのコアにあたる部分のコードが収められています。

図3 linux-2.3シリーズのディレクトリサイズの変遷(2)
図3 linux-2.3シリーズのディレクトリサイズの変遷(2)

先に見たarchやdriversディレクトリほど急速ではないものの、これらのディレクトリも2.3シリーズ全体に渡って増加しており、機能の追加や改善が続いていたことが見てとれます。たとえばlinux-2.3.0と2.3.51のmmディレクトリを比較してみると、bootmem.c、highmem.c、numa.cの3つのファイルが増えています。

$ diff -u <(ls -1 linux-2.3.0/mm/) <(ls -1 linux-2.3.51/mm/)
--- /dev/fd/63  2016-11-08 08:17:25.882034749 +0900
+++ /dev/fd/62  2016-11-08 08:17:25.882034749 +0900
@@ -1,11 +1,14 @@
 Makefile
+bootmem.c
 filemap.c
+highmem.c
 memory.c
 mlock.c
 mmap.c
 mmap_avl.c
 mprotect.c
 mremap.c
+numa.c
 page_alloc.c
 page_io.c
 slab.c

bootmem.cは起動時に実際に存在する物理メモリを調べて割りあてる機能、highmem.cはx86の32ビットな仮想メモリ管理機能をx86_64アーキテクチャ用に拡張する機能、numa.cはSMPを効率化するNUMA(Non-Uniform Memory Access)アーキテクチャ用のメモリ管理機能を提供します。これらはSMPやマルチアーキテクチャ化の進化に伴ない必要となった機能で、linux-2.3では対応アーキテクチャの増加と共に、それらを支える基盤部分の強化も図られていたことがわかります。

linux-2.3シリーズの新機能

さてそれではlinux-2.3シリーズではどのような新機能が追加されたのか、ソースコードをざっと眺めて目についたものを紹介してみましょう。

カーネルレベルでのPCカード対応

最近ではUSBやSDメモリカードに取って替わられほとんど見られなくなったものの、PCカードはノートPCの機能拡張用に広く使われていた周辺機器です。

PCカードは電話回線に接続するためのシリアル通信(モデム)やネットワーク、外付けHDDとのインターフェイスなどに利用されました。

図4 さまざまなPCカード
図4 さまざまなPCカード

実のところ、PCカードはlinux-1.xの時代からカーネル外部のサービスとして利用可能でした。当時のLinuxではPCカードのサポートはpcmcia-csパッケージとして提供され、このパッケージに含まれるcardmgrと呼ばれるデーモンがPCカードの抜き差しを監視し、必要なドライバモジュールをカーネルに組み込んだり取り外したりしていました。

linux-2.3のシリーズでは、カーネル自身が周辺機器の活線挿抜に対応するようになり、それに伴なってPCカードもカーネルレベルで対応することになりました。その結果、linux-2.3.33ではdrivers/pcmcia/というディレクトリが用意され、pcmcia-csが提供していた機能の多くがカーネル内部に取り込まれることになりました。

devfs

カーネル自身が周辺機器の活線挿抜に対応するようになって深刻になったのがデバイスファイルの管理問題です。

Linuxがお手本にしたUNIXの設計では、ユーザ領域とシステム領域を厳密に区別するため、ユーザ領域のソフトウェア(アプリケーション)が周辺機器を利用する際はデバイスファイルという特殊なファイルを経由することになっています。このデバイスファイルは使いたい周辺機器それぞれに必要で、HDDなどの場合はパーティションごとに1つのデバイスファイルが必要になります。

それぞれのコンピュータ会社が閉じた世界を作っていたUNIXワークステーションの時代では、利用できる周辺機器も限られていたため、使うであろうデバイスファイルをあらかじめ全て用意しておくこともそれほど難しいことではありませんでした。

一方、膨大な種類の周辺機器が存在するPC環境で開発されたLinuxでは利用可能な周辺機器の種類も豊富で、それに応じて多種多様なデバイスファイルが必要になります。加えて活線挿抜で動作中に周辺機器が増えたり減ったりするとなると、それらをどうデバイスファイルと結びつけるのかという問題が生じてきます。

そのために考案されたのが、周辺機器のことを一番よく知っているカーネル自身に必要なデバイスファイルを動的に作らせるdevfsという仕組みです。

従来の方式ではデバイスファイルはルートファイルシステム上に用意したdevディレクトリ以下に、周辺機器を表わすメジャー番号、マイナー番号を指定して、mknodコマンドであらかじめ作っておく必要がありました。

それに対しdevfsでは、認識している周辺機器の情報を元に、専用のファイルシステム上にカーネル自身が必要なデバイスファイルを作成するように設計されています。devfsのコードはlinux-2.3.51でfs/devfs/以下に収められました。

実のところdevfsの機能はそれほど広く使われず、次の安定版であるlinux-2.4シリーズでも長く「実験的(experimental⁠⁠」のラベルが付いたままでした。その理由のひとつは、devfsが提供するデバイスファイル名が/dev/scsi/host0/bus0/target1/lun0/part6のようなスタイルで、伝統的な/dev/sda6といったスタイルとは大きく異なっていたことです。これらをシンボリックリンクで結びつけることも不可能ではないものの、そのような命名規則をカーネル内部に組み込んでしまうと融通が効かなくなって不便です。そのため、devfsが担っていた機能をユーザ領域のソフトウェアで実現するudevというツールが開発され、次第にdevfsに取って代っていくことになりました。

khttpd

もう1つ、このころのカーネルで目に付くのが、カーネルレベルでHTTPに対応しようというkhttpdです。khttpdのコードはlinux-2.3.18からnet/khttpdディレクトリに収められています。

$ ls linux-2.3.18/net/khttpd/
Config.in  accept.c       main.c          prototypes.h  security.c  structure.h  userspace.c
Makefile   datasending.c  make_times_h.c  rfc.c         security.h  sysctl.c     waitheaders.c
README     logging.c      misc.c          rfc_time.c    sockets.c   sysctl.h

linux-2.3が開発されていた1999年から2001年ごろはいわゆる「ITバブル」の時期で、さまざまな企業がインターネットに参入し、WWWが急速に普及し始めていた時期でした。

当時、さまざまな企業が「ITバブル」の波に乗ろうと、Webサービスに特化したようなサーバを開発し、その速度競争がカタログを賑わせていました。

いわゆる「Web 2.0」と呼ばれる動的なコンテンツが普及し始めたのが2005年ごろ、それ以前の時代は、静的なコンテンツをいかに高速にユーザに届けるかが重要なテーマでした。

「静的なコンテンツ」とはファイルシステム上に保存されたファイルです。それをネットワーク経由で可能な限り高速にユーザに送るためには、ユーザプロセスのhttpdを介するよりもカーネル自身が操作した方が速い、khttpdはそのようなアイデアで開発された機能で、カーネル自身がクライアントからのHTTPリクエストを解釈し、指定されたファイルを送信するように設計されています。

khttpdの考え方はそれなりに意味があったものの、⁠Web 2.0」の時代になると、ユーザのリクエストに応じて動的に生成したページを提供するサービスが主流となり、静的なコンテンツの提供に特化したkhttpdは次第に使われなくなりました。その結果、khttpdのコードはlinux-2.5の時代にソースコードから削除されました。

spinlock()の進捗

これは新機能ではないものの、前回指摘したカーネル内部での処理単位を細かくするためのspinlock()のコードは、linux-2.3シリーズを通じて増加しています。

ドキュメントでの言及も拾ってしまうものの、

$ find linux-2.3.0 -type f -a -exec grep -i spinlock {} \; | wc -l

としてソースコード中に出てくるspinlock()処理を数えてみたところ、linux-2.3.0では9392.3.18では12222.3.33では12942.3.51では16292.3.99-pre9では1868と、linux-2.3シリーズを通じて約2倍に増加しています。

ソースコードのサイズを調べたところ、linux-2.3.0が63M、linux-2.3.99-pre9は96Mで、linux-2.3シリーズを通じて約1.5倍の増加となり、spinlock()処理は新しいコードだけではなく、既存のコードが改訂される度にも追加されていったことがうかがわれます。

以上見てきたように、linux-2.3のシリーズは、開発期間が2年以上に及んだ2.1シリーズの反省から、当初は1年程度の開発期間で新しい安定版を公開するつもりだったものの、実際にはリリース直前まで新しいCPUへの対応が続き、ずるずると安定版の公開時期がずれていったようです。

2000年3月に公開された2.3.51の時点では、近いうちに安定版をリリースするつもりだったものの、次から次へと新機能を組み込んで収拾が付かなくなってしまった結果、きりの良い21世紀の最初(2001年1月)でリリースした、というところでしょうか。

一方、linux-2.3ではdevfsやkhttpdなど、伝統的なUNIXには存在しなかった新しい機能への取り組みが目に付きます。初期のLinuxはUNIXをお手本にさまざまな機能を開発してきました。それらUNIXの基本機能への追従はほぼ終了し、新しく未踏の領域に踏み込み始めたのがlinux-2.3シリーズだ、と言うことができそうです。


改めて現在の視点からlinux-2.3の開発状況を省みると、⁠急ぎすぎていたな」という印象を強く持ちます。その原因のひとつは本文中にも触れたように、この時期に生じていた「ITバブル」の影響でしょう。

Linuxを使ってApache httpdを動かし、MySQLをデータベースに、PythonやPerlでサービスを提供するスクリプトを書く、いわゆる「LAMP」が持てはやされていたのがこの時期だったように思います。膨大な数のLinuxサーバを使ってインターネット上の情報を収集、整理し、高精度で検索するGoogleが起業したのもこの時期でした。

実のところ、当時はLinusさん自身がTransmetaというIT系の新興企業に属していたため、⁠ITバブル」の影響をより強く受けていたように感じます。

ソースコードにはこのような外的要因は記録されないものの、LinuxにはKernel-MLに流れた膨大な量のメールアーカイブも存在します。それらをテキストマイニング的な手法で分析できれば、ソースコードの歴史を補完する重要な情報源になりそうです。

おすすめ記事

記事・ニュース一覧