Linuxカーネルに関する技術情報を集めていくプロジェクトです。現在、Linuxカーネル2.6解読室の第2章までを公開中。
ファイルシステムはOSの中心機能です。その機能にはUNIX独特の特徴が表れています。
ファイルシステムは、記憶装置上のデータに対し、ファイルという形式を通して一貫したアクセス手順を提供します。Linuxカーネルにおけるファイルは、伝統UNIXと同じくすべてバイトストリームです。カーネルはファイル内のデータの型を意識せず、そのファイルを利用するアプリケーションそれぞれが意識する必要があります。また、デバイスやLinuxカーネル内のデータ構造もファイルとして扱えることも特徴です。
Linuxカーネルは、おのおののファイルにiノードと呼ばれるデータ構造を割り当てて管理します。各iノードは、そのファイルの属性やファイルの実体が置かれている2次記憶装置上のブロック番号などを管理しています。
すべてのファイルは、ルート(/)から始まる1つのツリー状にまとめ管理されています。ファイルの指定は、ご存じのようにそのファイル位置(パス名)を利用します。本書のPart 4で詳しく説明します。
ファイルへのアクセスは、まずファイルをオープンすることから始まります。目的のファイルへのパス名を指定してopenシステムコールを発行すると、ファイル記述子と呼ぶユニークな番号が返却されます。以後のファイルアクセスでは、このファイル記述子を利用します。また、ファイル記述子の0、1、2は特別なファイル記述子として扱う約束になっていて、通常はファイルを割り当てるのではなく、それぞれ標準入力、標準出力、標準エラー出力があらかじめ割り当てられています。
ファイル記述子を利用したファイル入出力には、面白い特徴があります。ファイルのオープン状態は、forkによって子プロセスに引き継がれます。子プロセスはファイルをオープンすることなく、ファイル記述子に対してファイル入出力を行えます。親プロセスがファイル記述子0、1、2に割り当てたファイルを、子プロセスは標準入出力先として操作します。一般に標準入出力先には端末が割り当てられていますが、ファイルを割り当てたり、パイプを割り当てたりすることも可能です。一般に、標準入出力先はシェルのみが意識することになります。シェルから起動されるコマンド(子プロセス)では、実際の入出力先が何であるかを考慮することなく、利用できます。
Linuxカーネルは、ファイルアクセスを高速化するために、各種データをメモリ上にキャッシュします。ページキャッシュは、ファイルデータそのものをキャッシュします。一度読み込みアクセスを行ったファイルデータはしばらくメモリ上に保存され、2回目以降のアクセスを高速化します。また、ファイルの順次アクセスを高速化するために、先行読み出し機能も備えています。実際の読み込み要求が発生する前に、将来要求が発生すると予測される部分のファイルデータの読み込み処理を陰で行ってしまう機能です。さらに、キャッシュ上のファイルデータを遅延させて2次記憶に書き出すことによって、応答性とスループットを向上させています。またLinuxカーネルは、空きメモリがあるとそのほぼすべてをキャッシュ域として利用し、メモリを無駄にしません。
iノードとファイル名についてもキャッシュが用意されています。iノードキャッシュは、頻繁にアクセスするファイルのiノードの複製を蓄えます。同じファイルが続けて利用される可能性が高いため、この機能は有効に働きます。パス検索を高速化するdエントリキャッシュは、ファイル名をキャッシュします。パス検索は、Linuxカーネルが行う処理の中でも最も重い処理の1つです。このdエントリキャッシュはLinux独特の構造をしており、このパス検索を高速化する大きな効果があります。
より深く知りたい方は、「第17章 ファイルのリード/ライト」を参照してください。
最近のUNIX系OSは、仮想ファイルシステム(VFS)をサポートしています(図0-6)。仮想ファイルシステムの下に、さまざまな種類のファイルシステムを配置可能です。利用者は実際に利用しているファイルシステムが、どのようなファイルシステムであるか意識する必要はありません。下位のファイルシステムの形式によらず、同じインターフェイスで操作可能です。
その実装の解説は、「第15章 仮想ファイルシステム(VFS)」、「第16章 ファイルの操作」で行います。
ローカルファイルシステムは、ホストに直結された2次記憶装置を利用するためのファイルシステムです。Linux標準のファイルシステムExt2のほかに、さまざまなOSが利用しているファイルシステム形式にも対応しています。UNIX系以外のOSのファイルシステム(WindowsのVFATなど)も利用可能です。
2次記憶装置としては、ハードディスク、CD-ROM、フロッピーディスクなどが存在します。これら2次記憶装置の上に、ファイルシステムを形作るためのデータ構造を配置します。
ネットワークファイルシステムは、ネットワークの先にある遠隔マシンが持つファイルシステムを、自ホストのローカルファイルシステムのように利用できる仕組みです。
最も一般的に利用されているネットワークファイルシステムは、NFSです。ほかには、codaファイルシステムやアンドリューファイルシステムなどが存在します。遠隔ホスト上のファイルシステムとの同期に関して、ネットワークファイルシステムごとにさまざまな実装方針が存在します。
記憶装置上にあるファイル以外のものを、さもファイルであるかのように見せかけるファイルシステムです。最もよく知られているファイルシステムは、procファイルシステムでしょう。
procファイルシステムは、Linuxカーネル内のデータ構造をファイルとして見せるためのインターフェイスです。このファイルの読み書きによって、Linuxカーネル内部の情報を得たり、Linuxカーネルコンフィグレーションを動的に変更したりできます。各種カーネル資源の上限の変更、メモリ利用状況の取得、仮想記憶の挙動を決めるパラメータの変更、TCP/IPプロトコル動作の調整など、さまざまな用途に利用されています。
また、Linuxカーネル2.6からはsysfsファイルシステムも用意されました。sysfsは、ハードウェア構成情報とデバイスドライバ情報を統一された階層に見せるためのファイルシステムです。Linuxカーネル2.4で/proc以下に無秩序に置かれていたこれらの情報が、sysfs以下にまとめ直されています。sysfsはハードウェアのホットプラグ(運用中の動的な挿抜)にも対応しており、ホットプラグのタイミングに合わせてsysfs内に対応するファイルが生成/削除されます。
「第19章 疑似ファイルシステム(proc、sysfs)」にて、この話題を扱います。
非常にオーソドックスな作りのファイルシステムで、長らくLinuxの標準ファイルシステムの座に君臨しているのがExt2です。名前が示すとおり、Ext2ファイルシステム以前に、Extファイルシステムが存在していました。Ext2ファイルシステムは、Extファイルシステムの欠点を克服するために新規設計されたファイルシステムです。
Ext2ファイルシステムは、UNIXが誕生した当時のファイルシステムに、BSDのFFS(Fast File System)の考え方を一部取り込んだような構造になっています。各種UNIXの論文や文献を参考にしながら設計したものと思われます。
FFSの設計を参考にしたと思われる点はいくつかあります。その1つがブロックグループです。ブロックグループは、1つのファイルシステムが置かれる2次記憶装置をいくつかの領域に区切り、関連するデータをなるべく同じ領域内から確保し、アクセスを高速化するための仕組みです。2次記憶装置上の空き領域の管理にビットマップを利用していますが、これもFFSの設計を参考にしていると思われます。
FFSの特徴の1つであるフラグメント機能は取り込まれていません。実装しようとした形跡は、Ext2ファイルシステムのコードに残っています。この機能を実装しない代わりに、ほぼ同等の効果を得られるブロック先行確保機能が実装されています。ブロックサイズを小さめに設定したうえで、このブロック先行確保機能を有効にすると、2次記憶域の使用効率向上とアクセスの高速化という両方の効果を、同時に得ることができます。
このように改良を加え続けてきたExt2ファイルシステムですが、2次記憶装置の大容量化に伴い、次第に時代遅れになろうとしています。
Ext2ファイルシステムにジャーナリングを付加したファイルシステムです。耐故障性を高めることと、システムの異常終了後のファイルシステム復旧を高速化するために、導入されました。
導入に当たっては広く普及したExt2ファイルシステムとの互換性を最優先に設計されました。ジャーナル機能の実装には興味深い方式が採用されています。一般のジャーナリングファイルシステムは、ファイルシステム内部にジャーナル機能を実装しますが、Ext3ファイルシステムでは、ファイルシステムの外に用意する方式を採用しています。
まだ利用しているファイルシステムはありませんが、この外付けのジャーナル機能は、Ext3ファイルシステム以外のファイルシステムからも利用可能な構造になっています。
なお、LinuxカーネルはExt3ファイルシステム以外にも、ReiserFSや、商用UNIXから移植されたXFS、JFSといったジャーナリングファイルシステムを提供しています。
「第20章 ローカルファイルシステム(Ext3)」にて、詳しく説明します。
ファイルシステムの要求に応じて、実際の入出力処理を行うのがブロック型デバイスドライバです。
ファイルシステムとブロック型デバイスのインターフェイスは改良が加えられています。伝統UNIXや古いLinuxの実装では、バッファと呼ばれる単位で入出力要求(I/O要求)を処理していましたが、現在のLinuxでは、大きな単位での入出力処理が可能となるように複数ページの集まりを1単位として扱うようになっています。ブロック型デバイスは、この大きな単位で入出力処理を行います。
また、Linuxカーネルのブロック型デバイスドライバは、エレベータと呼ばれる仕組みによって、入出力のスループットを向上させています。伝統UNIXや古いLinuxカーネルの実装では、入出力要求を単純にセクター番号順に並べ替えるだけでしたが、現在のLinuxカーネルでは改良が加えられています。入出力順の並べ替えによって発生する応答性の劣化を、一定以上の遅延を起こさないようにする仕組みで抑えています。また、さらにスループットを向上させる試みとして、まだ存在していない入出力要求の発生を予測し、その存在しない要求までも考慮して、入出力スケジューリングを行う仕組みが提供されています。
「第17章 ファイルのリード/ライト」、「第18章 特殊ファイルのアクセス」にて、その話題に触れます。
[PageInfo]
LastUpdate: 2008-07-07 17:53:52, ModifiedBy: hiromichi-m
[Permissions]
view:all, edit:login users, delete/config:members