Read関連
Rev.2を表示中。最新版はこちら。
---------------------------------
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);
---------------------------------
bread(bdev, block, size) - 指定BlockデバイスからBlockを読み込み
__getblk() - Bufferを検索。なければ作成して返す。
__find_get_block() - BufferをPageCacheから検索
lookup_bh_lru() - Buffer LRUリストから指定BHを高速検索
if (見つからなかった) {
__find_get_block_slow()でPageCacheを地道に検索
検索して見つかればBuffer LRUリストに追加
}
touch_buffer(bh) - Bufferに対応するPageがアクセスされたことを示す
フラグを立てる
PageCacheの廃棄処理用
if (Bufferが見つからなかった)
__getblk_slow()
for (;;) {
__find_get_block() <-- また呼ばれるが???
if (Bufferが見つかった)
Bufferを返す
<-- 割り込まれてない限りは見つからないはず
grow_buffers() - 指定デバイス用に新規Bufferの作成
実際にはPage単位で作成
作成失敗ならメモリ解放(free_more_memory())
}
if (BufferがUptodateでない) {
__bread_slow()
bh->b_end_io = end_buffer_read_sync
submit_bh(READ, bh); - デバイスにI/O要求発行
bio作成
submit_bio(); <-- 結局はここをコール
wait_on_buffer(bh); - I/O完了待ち
Bufferのwaitqにcurrentを挿入
(wakeup用関数はbh_wake_function()を指定)
io_schedule() - schedule()実行。Read完了までBlock。
finish_wait()
}
ここに来たと言うことはUptodate状態なのでBufferを返すだけ
end_buffer_read_sync()
BufferをUptodate状態にする
unlock_buffer() - Unlock&バッファ待ちプロセスの起動
wake_up_buffer() - Bufferのwaitqにあるプロセスを起動
__wakeup()
bh_wake_function() <-- waitq挿入時に指定されるルーチン
autoremove_wake_function()
default_wake_function()
try_to_wake_up()
block_read_full_page(page, get_block) - 汎用ページ読み込み関数
@@@@@@@
