Linux カーネルの徹底調査

その歴史、そしてアーキテクチャーの分解

Linux ® カーネルは大規模で複雑なオペレーティング・システムのコアですが、その大きさのわりには、サブシステムおよび層構造に関してよく整理されています。この記事では Linux カーネルの一般的な構造を調べ、主要なサブシステムとコア・インターフェースを説明します。該当する箇所では、さらに詳しく掘り下げられるように、他の IBM の記事へのリンクも記載しています。

M. Tim Jones, Consultant Engineer, Emulex

M. Tim JonesM. Tim Jones は組み込みソフトウェアのエンジニアであり、『GNU/Linux Application Programming』や『AI Application Programming』(現在、第 2 版)、それに『BSD Sockets Programming from a Multilanguage Perspective』などの著者でもあります。技術的な経歴は静止軌道衛星用のカーネル開発から、組み込みシステム・アーキテクチャーやネットワーク・プロトコル開発まで、広範にわたっています。また、コロラド州ロングモン所在のEmulex Corp. の顧問エンジニアでもあります。



2007年 6月 06日

この記事の目標は、Linux カーネルを紹介し、そのアーキテクチャーと主要なコンポーネントを詳しく説明することです。そこで、まずは Linux カーネルの歴史に簡単に触れ、Linux カーネルのアーキテクチャーのおおまかな概要を捉えてから主要なサブシステムを検討していきたいと思います。Linux カーネルのコードは 6 百万行を超えるので、ここでの説明はすべてを網羅するものではありません。さらに詳しく調べるには、詳細情報へのリンクにアクセスしてください。

Linux の歴史概略

Linux と GNU/Linux の違い

お気付きかもしれませんが、オペレーティング・システムとしての Linux は、「Linux」とも「GNU/Linux」とも呼ばれることがあります。これは、Linux がオペレーティング・システムのカーネルであることが理由です。オペレーティング・システムの有用性を高めている広範なアプリケーションは、GNU ソフトウェアです。例えば、ウィンドウ・システム、コンパイラー、多種多様なシェル、開発ツール、エディター、ユーティリティー、そしてその他のアプリケーションはカーネルの外側にあり、その多くが GNU ソフトウェアとなっています。このため多くの人々は、オペレーティング・システムの名前としては「GNU/Linux」のほうが適切で、カーネルだけを指す場合には「Linux」と呼ぶのが適切だと考えているわけです。

Linux は最も人気の高いオープン・ソースのオペレーティング・システムと言えますが、その歴史はオペレーティング・システム全体の歴史からするとかなり浅いものです。コンピューティングがまだ間もない時代には、プログラマーは必要最小限のハードウェアでハードウェアの言語を使って開発を行っていました。オペレーティング・システムがないということは、つまり一度に 1 つのアプリケーションしか (そして一人のユーザーしか) 高価で大型の機器を使えないということです。そこで 1950年代に初期のオペレーティング・システムが開発され、開発作業の単純化を実現しました。この時代のオペレーティング・システムには、IBM 701 用に開発された GMOS (General Motors Operating System)、IBM 709 用に North American Aviation 社が開発した FMS (FORTRAN Monitor System) などがあります。

1960 年代になると、マサチューセッツ工科大学 (MIT) と多くの企業によって、GE-645 用の試験的オペレーティング・システム、Multics (Multiplexed Information and Computing Service) が開発されました。このオペレーティング・システムの開発に加わった AT&Tは、その後 Multics から手を引き、1970 年代に Unics という独自のオペレーティング・システムを開発します。このオペレーティング・システムに伴っていたのが C 言語です。C 言語は Unicsのために開発されましたが、のちにオペレーティング・システム開発を移植可能にするために作成しなおされました。

それから 20 年後、Andrew Tanenbaum が小型のパーソナル・コンピューターで稼動する MINIX (Minimal UNIX: 最小限機能の UNIX) という UNIX® のマイクロカーネル・バージョンを作り上げました。このオープン・ソースのオペレーティング・システムから発想を得た Linus Torvalds が 1990 年代の初めに Linux の開発を開始したのです (図 1 を参照)。

図 1. 短い歴史のなかでの Linux カーネルの主なリリース
Short history of major Linux kernel releases

Linux は短期間のうちに、一個人のプロジェクトから何千もの開発者が関わる世界規模の開発プロジェクトに発展しました。Linux にとって最も重要な決定の 1 つとなったのは、GPL (GNU General Public License) の採用です。GPL によって Linux カーネルは商業的利用から保護されると同時に、GNU プロジェクトのユーザー空間での開発からも恩恵を受けることになります (具体的には、Richard Stallman のソースが Linux カーネルを小型化しています)。その結果、GCC (GNU Compiler Collection) をはじめとする有益なアプリケーション、そしてさまざまなシェル・サポートが実現しました。


Linux カーネルの概要

歴史に続いて、GNU/Linux オペレーティング・システムのアーキテクチャーの概要を見ていきましょう。オペレーティング・システムは、図 2 に示すように 2 つのレベルで構成されていると考えることができます。

図 2. GNU/Linux オペレーティング・システムの基本アーキテクチャー
The fundamental architecture of the GNU/Linux operating system

システム・コール・インターフェース (SCI) のメソッド

実際のアーキテクチャーは図 2 のように簡潔なわけではありません。例えば、システム・コールを (ユーザー空間からカーネル空間に遷移して) 処理するメカニズムはアーキテクチャーによってさまざまです。古い x86 プロセッサーでは従来の int 80h による方法を使用する一方、仮想化命令をサポートする新しい x86 中央演算処理装置 (CPU) ではこの処理を効率化しています。

上部にあるのはユーザー (つまりアプリケーション) 空間です。ユーザー・アプリケーションはここで実行されます。ユーザー空間の下にあるのはカーネルで、ここが Linux カーネルが存在する場所です。

アーキテクチャーには GNU C Library (glibc) も含まれます。これがカーネルに接続するシステム・コール・インターフェースとなり、ユーザー空間アプリケーションとカーネル間の遷移メカニズムを提供します。このメカニズムは重要です。なぜなら、カーネルとユーザー・アプリケーションはそれぞれ保護された異なるアドレス空間を占有するからです。さらに、ユーザー空間の各プロセスはそれぞれに固有の仮想アドレス空間を占有する一方、カーネルは単一のアドレス空間を占有します。詳細は、「参考文献」セクションのリンクを参照してください。

Linux カーネルはさらに 3 つのレベルに分けられます。まず一番上にあるのはシステム・コール・インターフェースです。このインターフェースは、readwrite などの基本関数を実装します。その下にあるのはカーネル・コードで、さらに正確に言えば、アーキテクチャーに依存しないカーネル・コードとして定義できます。このコードは、Linux がサポートするプロセッサー・アーキテクチャーすべてに共通しています。一番下にあるのはアーキテクチャーに依存するコードです。これは一般的に BSP (Board Support Package) と呼ばれるものを構成し、特定のアーキテクチャーに対してプロセッサーおよびプラットフォームに固有のコードとして機能します。


Linux カーネルの特性

大規模で複雑なシステムのアーキテクチャーを語るときには、システムをさまざまな角度から見ることができます。アーキテクチャーを分解する 1 つの目的は、ソースをより深く理解する手段を提供することです。それこそがまさに、この記事が目的としていることです。

Linux カーネルは、多くの重要なアーキテクチャー属性を実装します。高位レベルにしても、低位レベルにしても、カーネルはそれぞれに独特なサブシステムの層で構成されます。それと同時に、Linux はすべての基本サービスをカーネルでまとめて扱うため、モノリシック・カーネルと見なすこともできます。ここが、マイクロカーネルのアーキテクチャーとは違うところです。マイクロカーネルのアーキテクチャーでは、カーネルは通信、入出力、メモリーおよびプロセスの管理といった基本サービスを提供し、固有のサービスはマイクロカーネル層に接続されます。いずれのアーキテクチャーにしてもそれぞれに利点がありますが、それを論議するのは避けることにします。

時間が経つにつれ、Linux カーネルはメモリーと CPU 両方の使用率という点で効率化され、極めて優れた安定性も持つようになりました。しかし Linux のサイズと複雑さを考えると、ひと際興味深い特徴となるのはその移植性です。Linux は、アーキテクチャー上の制約もニーズも異なるさまざまなプロセッサーおよびプラットフォームで実行するようにコンパイルできます。その一例として、Linux はメモリー管理装置 (MMU) を使用したプロセスでも、MMU がまったくないプロセスでも実行できます。これは、Linux カーネルの uClinux ポートが非 MMU のサポートを提供しているためです。詳細は、「参考文献」セクションを参照してください。


Linux カーネルの主要なサブシステム

それではいよいよ、図 3 に示す構成に従って Linux カーネルの主要なコンポーネントを見てみましょう。

図 3. Linux カーネル・アーキテクチャーの 1 つの見解
One architectural perspective of the Linux kernel

システム・コール・インターフェース

SCI は、ユーザー空間からカーネルへの関数コールを実行する手段を提供するシン・レイヤーです。前に説明したように、このインターフェースは同じプロセッサー・ファミリーのなかでさえも、アーキテクチャーによって異なる場合があります。実際には、SCI は関数コールを多重化および逆多重化する興味深いサービスです。SCI 実装は ./linux/kernel に、アーキテクチャーに依存する部分は ./linux/arch にあります。このコンポーネントについての詳細は、「参考文献」セクションを参照してください。

プロセス管理

カーネルとは何か

図 3 に示すように、カーネルは実際には単なるリソース・マネージャーでしかありません。管理対象のリソースがプロセス、メモリー、ハードウェア・デバイスのどれであれ、カーネルは (カーネルおよびユーザー空間両方での) 複数ユーザー間で統合するリソースへのアクセスを管理および調停します。

プロセス管理は、プロセスの実行に集中的に取り組みます。カーネルではプロセスはスレッドと呼ばれ、プロセッサーの個々の仮想化 (スレッド・コード、データ、スタック、および CPU レジスター) を表します。ユーザー空間ではプロセスという用語が一般的に使用されていますが、Linux 実装ではこの 2 つの概念 (プロセスとスレッド) を区別していません。カーネルは SCI を介して、新規プロセスの作成 (fork、exec、または POSIX (Portable Operating System Interface) 関数)、プロセスの停止 (kill、exit)、そしてプロセス間の通信と同期 (信号、または POSIX メカニズム) を行うためのアプリケーション・プログラム・インターフェース (API) を提供します。

プロセス管理は、アクティブ・スレッド間で CPU を共有するというニーズにも対応します。カーネルが実装するのは、CPU を奪い合うスレッドの数に関わらず一定時間内での動作をする革新的なスケジューリング・アルゴリズムです。これは、多数のスレッドをスケジューリングする場合と、1 つのスレッドをスケジューリングする場合で、スケジューリングに同じだけの時間がかかるという意味で、O(1) スケジューラーと呼ばれます。O(1) スケジューラーは複数のプロセッサー (対称型マルチプロセッシング (SMP)) もサポートします。プロセス管理のソースは ./linux/kernel にあり、アーキテクチャーに依存する部分は ./linux/arch にあります。このアルゴリズムについての詳細は、「参考文献」セクションを参照してください。

メモリー管理

メモリーもカーネルが管理する重要なリソースです。効率的なメモリー管理のために、ハードウェアによって仮想メモリーを管理する方法が用意されており、メモリーはページと呼ばれる単位で管理されます (大抵のアーキテクチャーでは、ページのサイズは 4KB です)。Linux には使用可能なメモリーを管理する手段、そして物理マッピングと仮想マッピング両方のためのハードウェア機構が組み込まれています。

ただし、メモリー管理が対応するバッファー・サイズは 4KB を遥かに超えます。Linux では、4KB を超えるバッファーの抽象化 (スラブ・アロケーターなど) が行われます。このメモリー管理スキームは 4KB のバッファーを基本にしていますが、その中から、すべて使用されているページ、部分的に使用されているページ、そして空のページを追跡して、構造を割り当てます。このようにすることで、メモリー管理スキームがシステムのニーズに応じてバッファー・サイズを動的に拡大縮小できるようにしています。

メモリーを使用する複数のユーザーをサポートしていると、使用可能なメモリーが使い果たされてしまうことはよくあります。そのため、ページはメモリーからディスクに移動できるようになっています。メモリーからハード・ディスクにページがスワップされることから、このプロセスはスワッピングと呼ばれます。メモリー管理のソースは ./linux/mm にあります。

仮想ファイル・システム

複数のファイル・システムに共通のインターフェースの抽象化を行う仮想ファイル・システム (VFS) は、Linux カーネルの興味深い特徴です。VFS は、カーネルがサポートするファイル・システムと SCI との切り替え層となります (図 4 を参照)。

図 4. ユーザーとファイル・システム間の切り替え構造となる VFS
The VFS provides a switching fabric between users and file systems

VFS の最上部に位置するのは、open、close、read、write などの関数の共通 API の抽象化層です。VFS の最下部では、ファイル・システムの抽象化が行われ、上位層にある関数の実装方法が定義されます。これらのファイル・システムの抽象化は、(50 以上存在するなかの) 特定のファイル・システムを対象としたプラグインになっています。ファイル・システムのソースは ./linux/fs にあります。

ファイル・システム層の下にあるのは、ファイル・システム層に共通の関数一式を提供するバッファー・キャッシュです (特定のファイル・システムには依存していません) 。このキャッシュ層は、データを短期間保持することで (あるいはデータが必要なときに使用できるように先を見越した読み取りによって)、物理デバイスへのアクセスを最適化します。バッファー・キャッシュの下にはデバイス・ドライバーがあり、特定の物理デバイスを対象としたインターフェースを実装します。

ネットワーク・スタック

基本的に、ネットワーク・スタックはプロトコル自体に応じてモデル化された階層アーキテクチャーに従います。中核となるネットワーク層プロトコルは、インターネット・プロトコル (IP) で、トランスポート・プロトコル の下に位置していることを思い出してください。大抵の場合、トランスポート・プロトコルは TCP (Transmission Control Protocol)) となります。TCP の上にあるソケット層は、SCI を介して呼び出されます。

ネットワーク・サブシステムへの標準 API であるソケット層は、各種ネットワーク・プロトコルへのユーザー・インターフェースとなります。IP プロトコル・データ・ユニット (PDU) への直接のフレーム・アクセスから TCP およびユーザー・データグラム・プロトコル (UDP) に至るまで、このソケット層が接続を管理してエンドポイント間でデータを移動させる標準化された方法となります。ネットワークのソースが置かれているのはカーネルの ./linux/net です。

デバイス・ドライバー

Linux カーネルの大部分のソース・コードは、特定のハードウェア・デバイスを使用可能にするためのデバイス・ドライバーのなかに存在します。Linux ソースのツリーには drivers サブディレクトリーがあり、このサブディレクトリーはさらに、Bluetooth、I2C、serial など、サポートされる各種デバイスごとに分かれています。デバイス・ドライバーのソースは ./linux/drivers にあります。

アーキテクチャーに依存するコード

Linux の大部分は実行されるアーキテクチャーに依存していませんが、通常の操作や効率性のためにアーキテクチャーを考慮しなければならない要素もあります。カーネル・ソースのアーキテクチャーに依存する部分を定義するのは ./linux/arch サブディレクトリーです。アーキテクチャー依存のコードは、アーキテクチャー固有の多数のサブディレクトリーに含まれていて、これらのコードがすべてまとまって BSP を構成します。一般的なデスクトップに使用されるのは、i386 ディレクトリーです。それぞれのアーキテクチャー・サブディレクトリーのなかには、カーネルの特定の側面 (ブート、カーネル、メモリー管理など) ごとに分けられた多数のサブディレクトリーが含まれています。アーキテクチャーに依存するコードは ./linux/arch にあります。


Linux カーネルの際立った特徴

Linux カーネルの移植性と効率性ではまだ足りないと言うなら、上記のサブシステムには分類できない他の特徴もまだまだあります。

実動オペレーティング・システムであると同時にオープン・ソースでもある Linux は、新しいプロトコルやプロトコルの進歩の優れたテスト・ベッドになります。Linux は代表的な TCP/IP をはじめとするさまざまなネットワーク・プロトコル、そして高速ネットワークの拡張 (1 GbE (ギガビット・イーサネット) および 10 GbE 以上) をサポートします。また、トランスポート・レベル・プロトコルの後継として TCP を超える多数の拡張機能を提供する SCTP (Stream Control Transmission Protocol) などのプロトコルもサポートします。

Linux は動的カーネルでもあり、ソフトウェア・コンポーネントをその場で追加、削除することができます。これらのコンポーネントは動的ロード可能カーネル・モジュールと呼ばれ、必要に応じて (特定のデバイスにこのモジュールが必要だということがわかった場合) ブート時に挿入することも、ユーザーが任意の時点で挿入することもできます。

最近の Linux での進歩は、別のオペレーティング・システムのオペレーティング・システム (ハイパーバイザー) として使用できるようになったことです。近頃、KVM (Kernel-based Virtual Machine) という修正がカーネルで行われています。この修正により、ユーザー空間への新しいインターフェースを使って KVM対応のカーネルをベースとして別のオペレーティング・システムを実行できるようになりました。Linux の別のインスタンスを実行できるだけでなく、Microsoft® Windows® を仮想化することもできます。唯一の制約は、基礎となるプロセッサーが新しい仮想化命令をサポートしなければならないという点です。詳細は、「参考文献」を参照してください。


さらに詳しく調べてください

この記事では、Linux カーネルのアーキテクチャー、そして Linux カーネルの特徴と機能を表面的にかじったに過ぎません。カーネルの内容についてもっと詳細を知りたい方は、すべての Linux ディストリビューションに用意されている Documentation ディレクトリーを調べてみてください。また、記事の最後にある「参考文献」セクションもお見逃しなく。この記事で説明した内容の詳細を調べられます。

参考文献

学ぶために

  • The GNU サイト では、Linux カーネルとこれに提供されている便利なアプリケーションの大部分に適用される GNU GPL について説明しています。また、GPL よりも制約の少ない LGPL (Lesser GPL) についても説明しています。
  • Wikipedia に、UNIX, MINIX そして Linux についての説明がオペレーティング・システムの系図と併せて記載されています。
  • GNU C Library(glibc) は標準 C ライブラリーの実装で、GNU/Linux オペレーティング・システムだけでなく、GNU/Hurd マイクロカーネル・オペレーティング・システムでも使用されています。
  • Linux カーネルの一部となっているuClinux は、MMU のないシステムで実行できます。この uClinux によって、PDA (PalmPilot Personal Digital Assistant) で使用されている Motorola DragonBall プロセッサーなどの極めて小型の組み込みプラットフォームでも Linux カーネルを実行できるようになっています。
  • 「Linux システム・コールを使用したカーネル・コマンド」 (developerWorks、2007年3月) では、Linux カーネルの重要な層である SCI、そしてユーザー空間とカーネル間の関数呼び出しを可能にする glibc によるユーザー空間のサポートについて説明しています。
  • 「Linux スケジューラーの内側」 (developerWorks、2006年6月) では、Linux 2.6 で新たに導入された O(1) スケジューラーを紹介しています。効率的で多数のプロセス (スレッド) に応じて拡張し、SMP システムを利用する O(1) スケジューラーについて学んでください。
  • 「/proc ファイル・システムを利用した Linux カーネルへのアクセス」 (developerWorks、2006年3月) では、ユーザー空間・アプリケーションがカーネルと通信するための革新的方法を提供する仮想ファイル・システム、/proc ファイル・システムを取り上げています。この記事では /proc だけでなく、ロード可能カーネル・モジュールも実例で紹介しています。
  • 「Server clinic: Put virtual filesystems to work」 (developerWorks、2003年4月) では、Linux が多種多様なファイル・システムを共通インターフェースでサポートできるようにする VFS を掘り下げて説明しています。このインターフェースは、ソケットなどのその他の種類のデバイスにも使用されます。
  • 「Inside the Linux boot process」 (developerWorks、2006年5月) では、Linux のブート・プロセスを検討しています。Linux システムを立ち上げるこのプロセスは、ハード・ディスク、フロッピー、USB メモリー・スティック、あるいはネットワークからブートするにせよ、共通した基本プロセスとなります。
  • 「Linux 初期 RAM ディスク (initrd) の概要」 (developerWorks、2006年7月) では、Linux をブートする物理媒体からブート・プロセスを切り離す初期 RAM ディスクについて検討しています。
  • 「SCTP によるネットワーキングの向上」 (developerWorks、2006年2月) では、非常に興味深いネットワーク・プロトコルの 1 つ、Stream Control Transmission Protocol を取り上げています。SCTP は TCP のように動作しますが、メッセージング、マルチホーミング、マルチストリーミングなど、便利な多数の追加機能があります。ネットワーク・プロトコルに興味があるとしたら、BSD と同じく Linux は理想的なオペレーティング・システムとなります。
  • 「Linux スラブ・アロケーターの徹底調査」 (developerWorks、2007年5月) では、Linux のメモリー管理でとりわけ特徴的なスラブ・アロケーターについて説明しています。このメカニズムは SunOS で開始されたものですが、Linux カーネルにぴったりの場所を見つけました。
  • 「仮想 Linux」 (developerWorks、2006年12月) では、仮想化機能を備えたプロセッサーを Linux が利用する仕組みを説明しています。
  • 「Linux と対称型マルチプロセッシング」 (developerWorks、2007年3月) では、Linux がどのようにチップ・レベルのマルチプロセッシングを実行するプロセッサーを利用するかを説明しています。
  • 「Linux カーネル仮想マシンを探る」 (developerWorks、2007年 4月) では、カーネルに最近導入された仮想化を紹介しています。仮想化により、Linux カーネルは仮想化された他のオペレーティング・システムのハイパーバイザーに変身します。
  • ユーザー空間での Linux プログラミングについての詳細は、著者の本『GNU/Linux Application Programming』で調べてください。
  • developerWorks Linux ゾーンでは、Linux 関連の様々な技術文書週間 Linux 記事アクセス数ランキングをはじめ、Linux 開発者向けの豊富な資料を紹介しています。
  • developerWorks technical events and Webcastsで最新情報を入手してください。

製品や技術を入手するために

  • developerWorks から直接ダウンロードできる IBM ソフトウェア試用版を使用して、Linux で次の開発プロジェクトを構築してください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux
ArticleID=238818
ArticleTitle=Linux カーネルの徹底調査
publish-date=06062007