Personal tools
You are here: Home ブログ 学習経過 ファイルシステム(その4)
« December 2010 »
Su Mo Tu We Th Fr Sa
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
Recent entries
sysfs tips 02 ohyama 2010-09-09
sysfs tips ohyama 2010-09-02
Haskell で周波数スペクトルを得る ohyama 2010-07-29
Haskell で線形識別関数の学習を行う ohyama 2010-07-19
Haskell で逆行列を求める ohyama 2010-07-16
Recent comments
Re:vim に lisp 機能をつける t.mimori 2010-12-16
Re:Haskell で周波数スペクトルを得る H.OHYAMA 2010-08-01
Re:lkml でお勉強 (その1-1) Hiroyasu OHYAMA 2009-08-21
Re:lkml でお勉強 (その1-1) kosaki 2009-08-20
Re:vim に lisp 機能をつける ohyama 2008-05-08
Categories
学習経過
GNU/Linux
 
Document Actions

ファイルシステム(その4)

前回、ext2 マウント時における、スーパーブロックオブジェクトと、各ブロックグループディスクリプタのキャッシュ処理について見てきた。
マウント処理の全体のうち、局所的な内容であったが、他の処理については、後々紹介してゆく(と思う)。

今回は、ファイルシステムによるファイル操作の実装について調べてゆく。尚、ファイルアクセスに付随する周辺の仕組みについて多く触れるが、ここでは、ファイルアクセス。特に、ブロックアドレスのアドレス変換に焦点を絞って述べてゆく。ここでは、ディスクからのデータ読み込みを例に話を進める。

ファイルシステムが提供するファイルの中枢を成すデータ構造は、inode と呼ばれ、ファイル 1つ に対して 1つ の inode が存在している。
ファイルのデータはディスク上に存在しているが、ユーザー操作によるファイルの読み書きは、ファイルデータをキャッシュしたページキャッシュに対して行われる( cf. ページキャッシュ(その2) )。
ファイルに対して読み書きを行う際、キャッシュを参照するが、キャッシュツリーに対応するページディスクリプタが存在しなかった場合、カーネルは page_cache_alloc_cold() を呼び出し、ページをキャッシュに追加、そして add_to_page_cache_lru() を呼び出し、キャッシュページを LRUリスト に登録する。
又ページが存在している場合において、ページが無効である(PageUptodate フラグが降りている)場合、有効なデータが含まれていないので、ディスクからデータを取得する。
具体的には、address_space のページ操作メソッドが登録された構造体(address_space_operations 型の a_ops メンバ) の readpage メソッドを呼び出す。
ファイルシステムに ext2 を使っている場合、ここでは、ext2_readpage() が呼ばれる。

ここでは、ページディスクリプタと、get_block のコールバック関数 ext2_get_block を引数に渡して、mpage_readpage を呼び出す。
get_block は、mpage_readpage() 関数内で呼び出され、ファイルポインタ(プロセスが開いているファイル内におけるオフセット)に対するディスクの実ブロック番号を返す、ファイルシステム固有の関数である。つまりここでは、ブロック番号のアドレス変換を低級ファイルシステムに行わせ、結果を受けて、VFS が I/O を行うようになっている。

さて、ext2 におけるディスクの使い方については、"ファイルシステム(その1)"で述べた。又、アドレス変換の仕組みについては、"ファイルシステム(その2)"で述べた。
ここでは、ext2 における get_block() 関数である ext2_get_block() から、実際にアドレス変換を行う実装をみてゆく。

まず、ext2_block_to_path() を呼び出す。
ここでは、ファイルポインタに対する ディスク inode の三段の間接参照における、それぞれの論理ブロック番号を整数型の配列(offsets[4])で表現する。つまり、直接参照の場合、2番目の要素に論理ブロック番号が格納される。二段参照の場合、2番目の要素に、13 (二段参照の際の i_block メンバのオフセット) が格納され、3番目に二段目からのオフセットが格納される。この場合、配列の先頭要素には、EXT2_IND_BLOCK マクロで表される値が格納される。三段参照の場合も同様に論理ブロック番号を求める。

ここで2つのデータ構造を紹介する。一つは、ext2_inode_info 構造体。
これは、ディスク inode に対応する構造体であり、VFS inode (以下、単に inode と呼ぶ )オブジェクトを組み込んでいる。inode からは、EXT2_I() マクロによって ext2_inode_info のアドレスを取得できる。
そしてもう一つが、Indirect 型のデータ構造である。これは、実ブロック番号と実ブロック番号を参照する変数のアドレス、そしてバッファヘッドから成るデータ構造で、それぞれ、"key", "p" そして "bh" メンバがそれに対応する。これは、後に説明する処理で使われる。

さて。ここまでの処理で、ファイルポインタから、ディスク inode のデータ構造における、データブロック位置を求めた。
次に、ext2_block_to_path() によって、ファイルポインタに対応するディスク inode の間接参照の回数を求めることが出来た。depth で返されたこの値を引数で渡し、ext2_get_branch() 関数を呼び出し、論理ブロック番号から実ブロック番号を取得する。

ここで add_chain() 関数に、ディスク inode のデータブロックの配列 i_data と ext2_block_to_path() で設定した offsets の和を引数で渡し、Indirect型 変数 chain の "p"(実ブロック番号を格納したエントリのアドレス), "key"(実ブロック番号) を設定する。初回の呼び出しでは、第二引数に NULL を渡し、chain オブジェクトのバッファヘッドを NULL に設定する。
ここまでの処理で、直接参照における実ブロック番号が取得できた( chain オブジェクトの key メンバに格納されている)。そして、sb_bread() 関数を呼び出し、VFSスーパーブロックオブジェクト(super_block型)の s_bdev メンバから参照できるブロックデバイスから、第二引数で渡される実ブロック番号のブロックバッファを参照(無ければ作成)し、バッファヘッドを返している。

ブロックバッファが作成できたので、バッファページが作成され、キャッシュにページが挿入され、VFS から読み書きを行える。
尚、作成されたキャッシュのディスクへの書き込みについては、"ページキャッシュ(その3)"で述べている。

ここまでが、ext2 ファイルシステムを巻き込んだ、ファイルからのデータ読み込みの処理の大まかな流れである。

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/30d530a130a430eb30b730b930c630e0-305d306e4/tbping
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.