Notes

Do not read codes but patch binary.

xv6 code reading (4.file system編)

前回VFS(仮想ファイルシステム)について主に書いたので、今回はFileSystem.
xv6はfsとvfsの差が明確に分かれていないが、fsの役割を担っているのは、mkfs.c/bio.c/log.c/fs.c(一部)のあたりか。

先ず、FileSystemの構築だが、先ず、defaultで動かせるコマンド群(lsやcat)のfileなどは、qemuが起動する際に必要なimgの中に
含ませる構成となっている。この時点で既に、superblockの構成単位,defaultfileへのinode付与,root directoryからそのdirectoryにある
fileへのlink等の処理が行われて,binary情報としてimageに含まれている。
xv6のdefaultのsuperblockの構成は以下の様。

全ブロック:1000個(block byte数:512byte)
bootblock:1
superblock:1
logblock:30
inodeblock:26
bitmapblock:1
datablock:残り:1000-59

blockbyte x block数により、全体で512kbyteがdisk容量とされている。
inode blockが26個で、disk上に置くinodeのbyte数が64byte,ゆえに26x512byte / 64 = 208個のinodeが置けるという計算.
inodeに対応したdataBlockの数が941個なので、大体1つのfile(またはdevice/directory)当たり4個位block消費すると最も効率が良い
という計算か。

blockの書き込み/読み込み/消去に関してだが、fs.cからbread(読み出し),bwrite(書き込み),brelse(消去)という関数で持って,device番号/
(super block内における)blockのindexを指定して行われる。

ここで、少し例を出して肝の一つであるcacheの説明をしよう。

lsを例に採る。lsコマンド実行時のuserlandでの処理の流れは以下の通りだ。

ls .を実行
1. sys_openにより(.)directory のfile descriptorをuserlandで取得。
2. file descriptorを元にsys_fstatを実行し、file typeがfile/dir/devのどれかを確認
3. file typeがdirなので,dirのdirectory entryを取得。
4. directory entryに書かれたpath名とinode番号を取得。
5. inode番号にmatchしたfileのメタ情報を取得
5. それらをconsole devに書き込み。

この時,最低何個のblockにアクセスするのだろうか。

1. sys_openでcurrent dirのinode情報にアクセス(metablock内に存在)
2. inode情報がpointerするaddressが指し示すdatablockの中のdirectory entry内を探索
(directory entryの先頭にcurdirの.があるので1block途中の16byteのみseek)
3. matchしたcurrent dirのメタ情報(type)を再度取得(この時cacheに存在するのでdiskへのアクセスなし)
4. current dirのdirectory entry内のblockをseek(最初のblockはcache済み)
5. block内のinode番号からメタ情報へアクセス
6. 4.5をdirectory entryの個数だけ繰り返す。

上から答えは、datablockに対しては最低1回(directory entryの長さが1block(512byte以上)>=32個以上のentry)、metadataに関してはcurrent dirの1回に加え,
そのdirectory内のinodeが別のblockに存在していれば(inodeは1つのblockに8個あるが並んでいるかはmkfsの実装依存),その分だけアクセスが必要。

たかが,lsコマンドだが、多くのsystemcallから構成され、更に別々のblockへのaccessを必要とし、更に、cacheの存在によって、diskへのアクセスが減少するという
ことがわかる。また、ls .を打った直後にls .を叩いた場合、cacheにblockが全て載っているのでblockへのアクセスは全くないはずだ。cache機能をもつbuffer blockはbio.cに書かれているがdefaultで30block分割り当てられている。

xv6のFSではdefaultで、1000個のblockの中で30個がlog blockとして割り当てられている。これは偶然cache用bufferの数と同じである。が、実際の所、必然であり、logによる書き出しは、bufferを活用している。logは、multiprocessからsystemcallが複数呼ばれた際、1度にblockをその都度書き出しせず、logheaderという所に貯めておき、最後のsystemcallが終了した段階で、logheaderの内容をbufferに移し替え、一斉にメモリに書き込む。そのようにすることで、複数processが同一blockの内容を書き換え用とした場合、各processがそのblockへのアクセスでlockされることを防ぐことができる。