fs.c static void bfree(int dev, uint b)

トップページ
jupiteroak.hatenablog.com


fs.c
https://github.com/mit-pdos/xv6-public/blob/master/fs.c#L81

static void bfree(int dev, uint b)
{
  struct buf *bp;
  int bi, m;

  bp = bread(dev, BBLOCK(b, sb));
  bi = b % BPB;
  m = 1 << (bi % 8);
  if((bp->data[bi/8] & m) == 0)
    panic("freeing free block");
  bp->data[bi/8] &= ~m;
  log_write(bp);
  brelse(bp);
}

bfree関数は、ハードディスク上のビットマップ領域において、引数bで指定されたセクタ番号に対応するbitを0にします(ビットマップ領域上のbitに、引数bで指定されたセクタが未使用状態であることを記録します)。

引数 int dev
操作対象となるビットマップ領域が属しているハードディスクドライブを指定します。
引数devが1の値の時は、マスタードライブを指定しています。
引数devが0の値の時は、スレイブドライブを指定しています。

引数 uint b
ビットマップに未使用状態として記録されるセクタのセクタ番号です。


処理の内容

ハードディスク上にあるビットマップ領域から1セクタを読み込む

bp = bread(dev, BBLOCK(b, sb) );

bread関数を呼び出して、ハードディスク上にあるビットマップ領域から1セクタを読み込みます(あるいは、ハードディスク上にあるビットマップ領域の1セクタに対応しているバッファを取得します)。読み込み対象となるセクタは、セクタ番号bに対応するビットマップ領域上のbitが含まれるセクタです。
セクタ番号bに対応するビットマップ領域上のbitが含まれるセクタを読み込むために、第二引数にはBBLOCKマクロを設定します。BBLOCKマクロは、セクタ番号bに対応するビットマップ領域上のbitが含まれるセクタのセクタ番号を算出するマクロです。

1セクタ分のビットマップにおいてセクタ番号bに対応しているbit番号biを算出する

bi = b % BPB;

ビットマップ領域上のbit番号b(セクタ番号bに対応しているbit番号)を、1セクタ分のビットマップにおけるbit番号bi(ビットマップ領域から1セクタを取り出したデータの範囲内におけるbit番号。0〜4095のいずれか)に変換します。bをBPBで剰余演算することにより、1セクタ分のビットマップにおけるbit番号を算出することができます。

1バイト分のビットマップにおいてセクタ番号bに対応しているbit番号bi%8を算出する

m = 1 << (bi % 8);

1セクタ分のビットマップにおけるbit番号bi(セクタ番号bに対応しているbit番号)を、1バイト分のビットマップにおけるbit番号bi % 8(ビットマップ領域から1セクタを取り出し、その1セクタから1バイトを取り出したデータの範囲内におけるbit番号。0〜7のいずれか)に変換します。
そして、1バイト分のビットマップにおけるbit番号(セクタ番号bに対応しているbit番号)の値を1にした8bit値である(1 << (bi % 8) )をmに保存します。

セクタ番号bに対応しているビットマップのbit番号の値が0ではないことを確認する

if((bp->data[bi/8] & m) == 0)
    panic("freeing free block");

bi/8をインデックスとすることで、1セクタ分のビットマップにおけるbit番号biが含まれる配列の要素(1バイト分のビットマップ)を取得できます。
bp->data[bi/8]の値をmでマスク処理することにより、1バイト分のビットマップにおけるbit番号(bに対応しているbit番号)の値を取り出します。
(bp->data[bi/8] & m) == 0 が真となる場合→1バイト分のビットマップにおけるbit番号(セクタbに対応しているbit番号)の値が0の場合→ビットマップ領域においてセクタbが既に未使用状態として記録されている場合は、panic関数を呼び出してメッセージを出力します。

セクタ番号bに対応しているビットマップのbit番号の値を0にする

bp->data[bi/8] &= ~m;

data[bi/8]の8bit値の内、bに対応するbit番号の値のみを0にします(ビットマップ領域においてセクタbを未使用状態として記録します)。

ブロック(セクタ)をロギングにおけるトランザクションの管理対象として登録する

log_write(bp);

log_write関数を呼び出して、バッファbpに対応しているブロック(セクタ)を、ロギングにおけるトランザクションの管理対象として登録します。

バッファのスリープロックを解放する

brelse(bp);

brelse関数を呼び出して、バッファbpに関わるスリープロックを解放し、他のプロセスがこのバッファを利用できるようにします。