UNIX 6th code reading - バッファの状態遷移
各フラグの説明
主要なものだけ簡単に。詳細はThe UNIX I/O Systemを読んでください。
getblk( )
欲しいバッファがb-list内でB_BUSYだったときはB_WANTEDフラグを立てて寝ます。そのバッファを使っている別のプロセス(B_ASYNC読み書きを考えると、同じプロセスの場合もありうる?)がbrelse( )でバッファを解放すると起きます。
特徴的なのはav-listからバッファを取得しようとしたときに、それがB_DELWRI(遅延書き込み)バッファならば非同期(B_ASYNC)でデバイスへの書き込みを行うことです。
av-listからバッファを取得した場合、B_BUSY(とB_RELOC)だけフラグが立つことに注意してください。bp->b_flags =| ではなくbp->b_flags = です。4966行参照。
breada( )
breada( )は実装がごちゃごちゃしているように思えます。
大きな流れは、通常の読み出し処理→先読み処理(B_ASYNC)→通常読み出しの後処理、てな感じです。
先読み処理は、デバイスからの読み出し処理完了を待ちません。デバイスからの読み出し処理が完了するとiodone( )が呼ばれ、そこでbrelse( )が呼び出されてB_BUSYフラグが勝手にリセットされます。
bwrite( ), bawrite( )
bawrite( )はB_ASYNCをセットしてからbwrite( )を呼び出します。
B_ASYNC書き込みの場合はデバイスへの書き込み終了を待ちません。デバイスへの書き込み処理が終わった後iodone( )が呼び出され、そこでbrelse( )が呼び出されB_BUSYフラグが勝手にリセットされます。
通常書き込みの場合はデバイスへの書き込み終了を待ちます。デバイスへの書き込み処理が終わった後iodone( )からwakeup( )で起こされ、自分でbrelse( )を呼び出してB_BUSYフラグをリセットします。
bwrite( ), bawrite( )を実行する前に、getblk( )などでバッファを取得しておく必要があります。
bdwrite( )
bdwrite( )はB_DELWRI(遅延書き込み)フラグとB_DONEフラグを立ててからbrelse( )を呼び出しB_BUSYフラグをリセットしav-listに戻すだけです。
実際に書き込み処理が行われるのは、getblk( )で書いたように、av-listからそのバッファを取得するときにB_ASYNCで書き込まれます。また、update( )などからbflush( )が呼ばれ、B_DELWRIのバッファがまとめてB_ASYNCで書き込まれます。
終わりに
今回描いた状態遷移図にプラスしてbinit( )による初期状態も理解しておくと、バッファの全体像が見えてくるでしょう。
状態遷移図は改良の余地があると思っています。なのでこの図だけで理解しようとせず、ソースを見ながら補足的に使うことをお勧めします。
エラー周りは省略しました。しかし、B_ASYNC動作に関してどこでエラーを拾うのかなどはきちんと考える必要がありそうです。私もまだ理解できていません。
次回はようやくファイルシステムに入っていくつもりです。