Linuxカーネルに関する技術情報を集めていくプロジェクトです。現在、Linuxカーネル2.6解読室の第2章までを公開中。
writeシステムコールは、vfs sys_write関数にて、ファイルディスクリプタに対応するファイル構造体を見つけ(fget関数)、ファイル構造体に登録されているwriteオペレーションを呼び出す。
ext2ファイルシステムの場合、 通常ファイルではgeneric_file_write関数が呼び出される。(v2.4からページキャッシュ経由の処理に書き換えられた)ディレクトリ、シンボリックリンクファイルの場合、このオペレーションは無登録であるため、sys_write処理はエラー終了する。
I/O要求が丁度ページ単位であるわけではないので、generic_file_write関数は、I/Oの先頭と最後のページをまずキャッシュ上に読み込み、その後I/O要求のあったデータを上書きしてやる必要がある。
generic_file_write(ファイル構造体、ユーザ領域, ファイルポインタ) if(アペンドモードなら) ファイルポインタをファイルエンドにする while(書き込むデータがある間) { ページキャッシュを確保する(__grab_cache_page関数) (もしキャッシュ上になければ新規確保し、登録する) ページの書き込み準備をする(iノードのprepare_writeオペレーションを呼び出す) (ext2の場合は、block_prepare_writeが呼び出される。 必要があればディスクからデータを読み込んだり、 バッファのクリアを行う) ユーザ領域のデータをバッファに読み込む(copy_from_user関数) ページの書き込み要求を出す(iノードのcommit_writeオペレーションを呼び出す) (ext2の場合は、generic_commit_writeが呼び出される。 dirtyなバッファの遅延書き込み要求を出すのみ) ページキャッシュの解放(page_cache_release関数) }
ページキャッシュの章でも説明したように、block_prepare_write関数は、ページ書き込みのための準備をする関数である。generic_commit_write関数を呼ぶ前に呼び出しておく必要がある。
block_prepare_write(iノード、I/O領域、読み込むページ, getblock関数) ページにまだバッファヘッドが割り付けられていなければ、 バッファヘッドを確保しページとリンク(create_empty_buffer関数) for (バッファのある間) { I/O完了コールバック関数としては、end_buffer_io_syncを登録。 if(バッファがブロックと対応付けられていない) { getblock関数(ext2では、ext2_getblock関数)を利用し、 inodeとファイルオフセットからブロック番号を求める。 if (新規確保したバッファなら) { もしバッファキャッシュにキャッシュが残っていれば そいつの解放を行う(unmap_underlying_metadata関数) 0クリアする。 } if (バッファがまだ有効でないなら) I/O要求の発行(ll_rw_block関数) } } I/O完了を待ち合わせる(wait_on_buffer関数)
generic_commit_write関数は、ページの遅延書き込み要求を行う関数である。実際にはバッファキャッシュのフラッシュデーモン類に書き込みI/Oを委ねる。
generic_commit_write(iノード、I/O領域、読み込むページ) for (ページに対応づけられたバッファ群に対し) { バッファを有効状態(BH_Uptodate)にし、 かつバッファをDirtyな状態にする(__makr_dirty関数) } Dirtyなバッファが多いようならkflushデーモンを起動する(balance_dirty関数) ページを有効にする(SetPageUptodate関数)
問題点
(NIS)HirokazuTakahashi
2000年12月09日 (土) 23時55分06秒 JST1
[PageInfo]
LastUpdate: 2008-08-27 14:17:39, ModifiedBy: hiromichi-m
[Permissions]
view:all, edit:login users, delete/config:members