Linux Kernel(2.6)の実装に関するメモ書き

Read関連


---------------------------------
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) - 汎用ページ読み込み関数
@@@@@@@

最終更新 2007/01/22 21:00:08 - kztomita
(2006/03/27 14:02:27 作成)


リンク
最近更新したページ
検索