---------------------------------
FileSystem - Ext2
Page読み込み関数
ext2_readpage()
mpage_readpage(page, ext2_get_block)
(inode,オフセット(Block数)) -> ブロック番号変換ルーチン
ext2_get_block() - bhにBlock番号を設定して返す
ext2_block_to_path()
ファイル先頭からのオフセット(Block#)から
i_block[]のどこをたどればよいかをoffsetsに格納する。
reread:
ext2_get_branch()
offsetsが指しているi_block[]に格納されているBlock番号をchainに格納していく。
Indirectアクセス(オフセットBlock数が12以上)なら
sb_bread()でi_block[]のあるBlockを読み込んでたどっていく。
<--内部はbread()。デバイスの指定Blockの読み込み。
BufferCacheにCacheされる。(既にCacheにあればディスクアクセスはしない)
chain[]の最後のエントリに格納されたBlock番号が取得したかったBlock番号
if (!partial) { <-- Blockが見つかった
got_it:
map_bh()
BH_Mappedセット
bh->b_bdev = sb->s_bdev;
bh->b_blocknr = block;
:
goto cleanup
}
if (!create || err == -EIO) {
<-- Blockが見つからなかった(新規割り当ても不要) or エラー
cleanup:
brelse()して終了
}
if (err == -EAGAIN)
goto changed - やり直し
以下、新規割り当て処理
ext2_find_goal()
ext2_alloc_branch()
ext2_splice_branch()
BH_Newをセット
goto got_it
changed:
読みかけのバッファをbrelse()してgoto rereadでやり直し。
struct file_operations
struct inode_operations
struct address_space_operations
---------------------------------
generic_file_read()
init_sync_kiocb()
__generic_file_aio_read()
:
do_generic_file_read()
do_generic_mapping_read(filp->f_mapping,...)
<--Pageキャッシュから読み込み
リターンが-EIOCBQUEUEなら
wait_on_sync_kioc()
<--読み込みまち?
do_generic_mapping_read()
page_cache_readahead()
find_page:
find_get_page(mapping,index)でPegaCache検索
PageCacheがなければno_cached_pageへ
PageCacheがあってもUptodate状態でなければpage_not_up_to_dateへ
page_ok:
actor() - (file_read_actor())
Pageのデータをユーザバッファにコピーする
break;
page_not_up_to_date:
lock_page() - PG_lockセット(I/O完了時にunlock)
:
readpage:
mapping->a_ops->readpage() - (ext2ならext2_readpage()) Pageへの読み込み処理
読み込んだPageがUptodate状態ならpage_okへ
wait_on_page_locked() - PG_lockされていたらBlock(Read I/O完了待ち)
読み込んだPageがUptodate状態ならpage_okへ
UptodateでなければEIO
no_cached_page:
PageCacheを割り当ててLRUCacheに登録する
readpageへ
mpage.c <--複数PageのI/O処理用?
mpage_readpage(page, get_block)
do_mpage_readpage()
mpage_bio_submit() <-- do_mpage_readpage()でbioが返されればここで処理
do_mpage_readpage() - mpage_readpage(), mpage_readpages()からコール
Page内のBufferについて以下を実行 (Page -> Blockへの分解)
get_block(inode, block_in_file, &bh, 0) - (ext2ならext2_get_block())
(Readなのでcreate=0)
inodeでファイルを指定。
block_in_fileでファイル先頭からのオフセット(Block#)を指定。
デバイス内のBlock番号に変換する
bh->b_bdevにデバイス、bh->b_blocknrにBlock#が返される。
BH_Mappedがセットされていなければ、Blockの場所を保存して
次のBufferへ
BH_Mappedが立っているということは、
BufferがDiskにマップされている(bh->b_bdev,bh->b_blocknrが
設定されている)ということ。
Pageの途中でEOFになっているとここでUnmappedが見つかる
:
if (BufferのBlock#が非連続になった)
goto confused
if (Page内のBufferでMapされていないものがある) {
Page内の最初のUnmapBuffer以降を0クリア
if (Page内の最初のBlockがMapされていない) {
SetPageUptodate()
goto out
}
} else {
SetPageMappedToDisk(page) - page->flagsにPG_mappedtodiskを設定
}
if (bio && (*last_block_in_bio != blocks[0] - 1))
bio = mpage_bio_submit(READ, bio);
mpage_readpages()からの繰り返し呼出用の処理?
前回の呼出からBlock番号が非連続ならここでI/O要求をだしているみたい
alloc_new: - ここに来たということはPageはDisk上で
連続Blockだった(物理的に連続セクタでもある)
mpage_alloc() - BIOの割り当て
bio->bi_sectorにPageの先頭セクタ#を設定する
bio_add_page() - biovecにPageアクセスのエントリを追加
if (buffer_boundary(&bh) || FullMapされていない)
mpage_bio_submit()
else
*last_block_in_bio = blocks[blocks_per_page - 1];
(Pageの最後のBufferのBlock番号)
out:
return bio
confused:
if (bio)
bio = mpage_bio_submit(READ, bio);
if (PageがUptodate状態でない)
block_read_full_page(page, get_block);
Buffer単位にsubmit_io()する
else
unlock_page(page);
goto out;
mpage_bio_submit(rw, bio)
bio->bi_end_io = mpage_end_io_read IO終了時のハンドラ設定
submit_bio()
返り値はstruct *bioだが本関数は常にNULLリターン
mpage_end_io_read()
Bufferに該当するページをUptodate状態にする
unlock_page() - PG_lockクリア。wait_on_page_locked()でsleepしたプロセスの起床
bio_put(bio);
---------------------------------
block_read_full_page(page, get_block) - 汎用ページ読み込み関数
@@@@@@@