WriteBack処理
1. 概要
プロセスがファイルへの書き込みを行うと、カーネルは通常はページキャッシュ(ディスクキャッシュ)に書き込むだけで一旦処理を完了する(ディスクヘの書き込みは行わない)。このデータが書き込まれたページキャッシュは、ディスク上のデータと内容が不一致になっていることを示すためDirty状態になる。Dirty状態のページキャッシュはカーネルスレッドpdflushによって、遅延してディスクに書き込まれる。この処理をWriteBack処理と呼ぶ。
2. WriteBack処理の動作
2.1 WriteBack処理の起動
WriteBack処理はカーネルスレッドpdflushによって実行される。カーネルスレッドpdflushを起動するには、wakeup_pdflush()、balance_dirty_pages_ratelimited()が使われる(図1)。
wakeup_pdflush()はtry_to_free_pages()でメモリを解放しようとする際に、Dirtyページを書き出して解放可能なメモリを増やそうとして呼ばれる。
balance_dirty_pages_ratelimitd()はファイルの書き込み処理の中で、generic_file_buffered_write()の中から呼び出される(「generic_file_write()」参照)。ただし、この関数は呼び出される度に毎回pdflushを起動するのではなく、ratelimit_pages回に1回だけpdlushを起動するようになっている。
pdflushの起動はpdflush_operation()でpdflushにジョブ(background_writeout())を投入することで、行われる。ジョブが投入されると、pdflushが指定された関数(background_writeout())の実行を開始する。
2.2 WriteBack処理
2.1に示すようにpdflushが起動されると、background_writeout()が実行される。WriteBack処理は本関数から始まる。WriteBack処理の流れを図2に示す。
background_writeout()は、WriteBack処理を開始するにあたって制御用データwriteback_controlを作成する。このデータはこれ以降に呼び出す関数に渡されていき、WriteBack処理の制御に使われる。
writeback_inodes()はシステム内のSuperBlockのリストを参照し、各SuperBlock毎にsync_sb_inodes()を呼び出す。
sync_sb_inodes()はSuperBlock(struct super_block)のDirty状態のi-nodeをsb->s_dirtyからs_ioに移し(s_ioはWriteBack中のi-nodeがチェーンされるリスト)、s_ioの各inodeに対して__writeback_single_inode()呼び出して、i-nodeのDirtyページをディスクヘ書き出そうとする。
図2 WriteBack処理の流れ
do_writepages()の流れを図3に示す。do_writepages()はファイルシステムのwritepagesハンドラかgeneric_writepages()を呼び出す。ファイルシステムにより異るが、多くの場合はmpage_writepages()が呼び出され、Dirty状態のページキャッシュのディスクへの書き込みI/Oを開始する。
図3 do_writepages()
3. struct writeback_control
writeback_control構造体は、WriteBack処理を制御するのに使われる。writeback_controlはbackground_writeout()でWriteBackを開始する際に作成され、呼び出し関数に渡されていき、writeback_control内のデータにしたがってWriteBack処理を行っていく。メンバ |
説明 |
---|---|
nr_to_write |
WriteBackするページ数。書き込みI/Oを発行すると減算されていく。 |
nonblocking |
RequestQueue内でのブロックを許すか否かのフラグ。 1だと、RequestQueue内でブロックしないように、ブロックデバイスが輻輳状態だったら、I/Oを発行せずにリターンする。 |