トリッキーなバッファ管理

表面的にソースを見ただけでは分からないが, バッファとディスクの同期のメカニズムは非常にトリッキーである. Linuxは性能を稼ぐため(と勝手に解釈している), 書き込みI/O途中のバッファのデータを参照/更新することが可能である.

ディスクI/Oの為のロック処理は存在しないため, 例えば以下の処理を行った後のディスク上のデータの値は不定である.

        bh = getblk();
        bhが管理するバッファのデータを更新
	mark_buffer_dirty(bh);
	ll_rw_block(WRITE, 1, &bh);
	wait_on_buffer(bh);

一見, バッファに書き込んだ値がそのままディスクに反映されるようにだまされてしまうが, getblk関数で得られたバッファがちょうど書き込みI/O中であることがありうる.

まだドライバ内のキューに継れている状態であれば, 運よく今回の更新がディスク上に反映されるが, I/Oコントローラに処理が渡っている場合(もしくは上記処理中にI/Oコントローラが動き出した場合)は, 中途半端にバッファ更新されたバッファがディスクに書き込まれてしまう.

実は, その様な場合でも上手く誤魔化すためのトリックが隠されている. I/O中のバッファに対してmark_buffer_dirtyを行うと, バッファにI/O処理中フラグBH_Lockと共にBH_Dirtyフラグが立つ. ll_rw_block関数はI/O中のバッファに対しては何も処理を行わず全ての処理をスキップする. このような状態になった中途半端なバッファも, いづれkflush/kupdateデーモンにより再度書き込みが行われ, そこで初めて辻褄があうことになる.

ただしこの動作は, 明示的なディスク更新が出来ない事を意味しており, 以下のような場合期待した動作をさせることができない.

  • syncモードマウントにおけるメタデータの同期更新
  • fsyncシステムコール

(NIS)HirokazuTakahashi
2000年12月09日 (土) 23時55分06秒 JST
1