log.c void log_write(struct buf *b)
トップページ
jupiteroak.hatenablog.com
log.c
https://github.com/mit-pdos/xv6-public/blob/master/log.c#L213
void log_write(struct buf *b) { int i; if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1) panic("too big a transaction"); if (log.outstanding < 1) panic("log_write outside of trans"); acquire(&log.lock); for (i = 0; i < log.lh.n; i++) { if (log.lh.block[i] == b->blockno) // log absorbtion break; } log.lh.block[i] = b->blockno; if (i == log.lh.n) log.lh.n++; b->flags |= B_DIRTY; // prevent eviction release(&log.lock); }
log_write関数は、バッファbに対応しているブロック(セクタ)を、ロギングにおけるトランザクションの管理対象として登録します。
処理の内容
- トランザクション内で管理されているブロック数が不正な値ではないことを確認する
- トランザクション内で管理されているシステムコールの数が不正な値ではないことを確認する
- クリティカルセクションの入口を定める
- バッファbに対応しているブロックをトランザクションの管理対象として登録する
- バッファの状態を示すフラグを変更する
- クリティカルセクションの出口を定める
トランザクション内で管理されているブロック数が不正な値ではないことを確認する
if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1) panic("too big a transaction");
①log.lh.n >= LOGSIZEが真、または、②log.lh.n >= log.size - 1が真となる場合→
①トランザクション内で管理されているブロック数nがログスペースに保存することができるブロック数(LOGSIZEで定められた値)以上となる、または、②トランザクション内で管理されているブロック数nがログスペースに保存することができるブロック数(initlog関数で定められた値)以上となる場合は、panic関数を呼び出してメッセージを出力します。
トランザクション内で管理されているシステムコールの数が不正な値ではないことを確認する
if (log.outstanding < 1) panic("log_write outside of trans");
log.outstanding < 1が真となる場合→トランザクション内において未完了にあるファイルシステム関連のシステムコールがない場合は、panic関数を呼び出して、メッセージを出力します。
バッファbに対応しているブロックをトランザクションの管理対象として登録する
メインメモリ上で管理されているlogheader構造体のメンバであるblock配列に、バッファbに対応しているブロック(セクタ)のセクタ番号を格納します。
logheader構造体のnメンバの値と等しくなるまでblock配列のインデックスをインクリメントする
for (i = 0; i < log.lh.n; i++) { if (log.lh.block[i] == b->blockno) // log absorbtion break; }
for文の継続条件式が偽になるまで(logheader構造体のnメンバの値と等しくなるまで)、block配列のインデックスをインクリメントします。
log.lh.block[i] == b->blocknoが真となる場合→block配列にバッファbに対応しているブロック(セクタ)のセクタ番号が既に格納されている場合は、for文の継続条件式が偽になる前に(logheader構造体のnメンバの値と等しくなる前に)、for文を脱出します。
block配列にバッファbに対応しているブロック(セクタ)のセクタ番号を格納する
log.lh.block[i] = b->blockno;
block配列にバッファbに対応しているブロック(セクタ)のセクタ番号を格納します。
for文の継続条件式が偽になるまで(logheader構造体のnメンバの値と等しくなるまで)block配列のインデックスをインクリメントした場合は、ブロック(セクタ)のセクタ番号が新規にblock配列へ格納されたことになります。
logheader構造体のnメンバの値をインクリメントする
if (i == log.lh.n) log.lh.n++;
logheader構造体のnメンバの値をインクリメントして、次にlog_write関数が呼び出された時に、block配列へセクタ番号を追加できるようにしておきます。
バッファの状態を示すフラグを変更する
b->flags |= B_DIRTY; // prevent eviction
B_DIRTY(#define B_DIRTY 0x4)をビット和代入することで、flagsメンバのbit2のみを1に設定します。バッファbのflagsメンバのbit2が1の時、バッファbが保存しているデータをハードディスクへ書き出す必要がある状態であることを示しています。トランザクションの管理対象として登録されたブロックに対応しているバッファが、バッファキャッシュ内で再利用されるのを防ぐために、バッファの状態を示すフラグを変更しています。