II-6-6. カーネルによるファイル操作

ファイルシステムに対する一般的な操作を説明する。ファイルのオープンとクローズ、データの読み書きなど基本的な操作から、ディスクへの書き出しがどのように行われるか、同期がとられるタイミングといったカーネルの内部動作についても解説する。

【学習の要点】

* ユーザプロセスは、openやsocketといったシステムコールを介してファイル記述子を獲得し、カーネル内のオブジェクトにアクセスする。

* カーネルはユーザプロセスから指定されたファイル記述子からファイル構造体を取得する。ファイル構造体はopenをはじめとするシステムコール毎に割り当てられ、以降の対応するシステムコールの呼び出しによって、読み込み、書き込み、ファイル状態取得、ファイルのクローズなどをサポートする。

* ファイル構造体は、ファイルのオフセットを保持する。そのため、異なるopenシステムコールによって割り当てられたファイルオフセットはそれぞれ独立して管理される。read, writeシステムコールは、ファイル構造体の管理するオフセットからそれぞれ処理を開始する。

図II-6-6. 記述子管理と参照関係

【解説】

1) ファイル記述子

* ユーザプロセスが入出力操作を行う際は、ファイル記述子を通して行われる。

* ユーザプロセスは、open, socketなど、オブジェクトの種類に合わせて用意されたシステムコールによって、ファイル記述子を取得することができる。

* カーネルは、プロセス毎に記述子テーブルを管理する。記述子の値は、このテーブルのインデックスとなっており、テーブルの値はファイル構造体のインスタンスを指す。

2) ファイル構造体

* ユーザプロセスが一旦ファイル記述子を取得すると、その後の操作は、取得した記述子を指定したシステムコールによって行われる。カーネル内では、記述子に対する操作はファイル構造体に対する操作として扱われる。

* ファイル構造体のインスタンスは、記述子の対応するカーネル内の実体オブジェクトを指す。実体オブジェクトは、ファイルであったりソケットであったり、メモリマップされたファイルであったりする。

* ファイル構造体は記述子と同様にプロセス毎に生成される。ファイル構造体は、対応するオブジェクトのオフセット(そのプロセスが、記述子に対して次のreadやwriteで読み書きを開始する位置)を保持する。オフセットの値は、readやwriteを行う度に更新される。

* ファイル構造体のオフセットを直接指定するには、lseekシステムコールを用いるが、すべての実体オブジェクトがこれをサポートしているわけではない。ソケットやパイプ、FIFOに対するlseekシステムコールは常に失敗する。lseekシステムコールは、ランダムアクセス可能なオブジェクトでのみ利用可能である。

3) バッファと同期

* ユーザプロセスが自身のプロセス空間にファイルの内容を読み込んだり、書き出したりする際には、通常カーネルバッファを経由して行われる。

* カーネルバッファを経由せずに入出力を行うこともできる。直接転送は、ユーザプロセスの書き込みが、カーネルバッファを経由せずに直接ディスクに対して行われるようにする。また、mmapによってプロセス空間にファイルをマップすることで、ユーザプロセスは自身のプロセス空間への読み書きを通してファイルにアクセスできる。

* openやfcntlシステムコールでは、ファイル記述子を通して間接的にファイル構造体の振る舞いを変更するためのフラグを設定できる。そのうち、以下にあげるコマンドはファイルの読み書きのポリシーを決定する。

- O_SYNC (同期書き込み), O_DIRECT (直接転送), O_ASYNC (非同期書き込み), O_NONBLOCK (ノンブロッキングI/O)

OSS Course Naviのコンテンツは IPA OSS モデルカリキュラムを基としています。