fs.c static uint bmap(struct inode *ip, uint bn)

トップページ
jupiteroak.hatenablog.com


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

static uint bmap(struct inode *ip, uint bn)
{
  uint addr, *a;
  struct buf *bp;

  if(bn < NDIRECT){
    if((addr = ip->addrs[bn]) == 0)
      ip->addrs[bn] = addr = balloc(ip->dev);
    return addr;
  }
  bn -= NDIRECT;

  if(bn < NINDIRECT){
    // Load indirect block, allocating if necessary.
    if((addr = ip->addrs[NDIRECT]) == 0)
      ip->addrs[NDIRECT] = addr = balloc(ip->dev);
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if((addr = a[bn]) == 0){
      a[bn] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    return addr;
  }

  panic("bmap: out of range");
}

bmap関数は、引数ipで指定されたiノードが所有するデータブロックにおいて、引数bnが指定するデータブロックに割り当てられているセクタのセクタ番号を取得します。

引数 inode *ip
iノード(inode構造体)を指定するアドレスです。

引数 uint bn
引数ipで指定された iノードが所有するデータブロックを指定するインデックスです。
bnが0~11の時、bnはiノードが直接的に所有しているデータブロックを指定するインデックスになります。
bnが12~139の時、 bnはiノードが間接的に所有しているデータブロックを指定するインデックスになります。

戻り値 uint addr
引数bnが指定するデータブロックに割り当てられているセクタのセクタ番号です。

bn < NDIRECTの場合はiノードが直接的に所有しているデータブロックのセクタ番号を取得する

if(bn < NDIRECT){
    if((addr = ip->addrs[bn]) == 0)
      ip->addrs[bn] = addr = balloc(ip->dev);
    return addr;
  }

インデックスbnの値が12(#define NDIRECT 12)未満の場合→インデックスbnの値が11以下の場合は、if文内の処理に入ります。
(addr = ip->addrs[bn]) == 0 が真となる場合 → ip->addrs[bn]にデータブロックのセクタ番号が未だ格納されていない場合 → インデックスbnが指定するデータブロックにセクタが割り当てられていない場合は、balloc関数を呼び出してセクタの割り当てを行ってから、そのセクタのセクタ番号を戻り値としてリターンします。
(addr = ip->addrs[bn]) == 0 が偽となる場合 → ip->addrs[bn]にデータブロックのセクタ番号が既に格納されている場合 → インデックスbnが指定するデータブロックにセクタが割り当てられている場合は、そのセクタのセクタ番号を戻り値としてリターンします。

インダイレクトブロックを指定するインデックス値を求める

bn -= NDIRECT;

インデックスbnが12以上の場合は、インデックスbnに12(#define NDIRECT 12)を減算代入し、インダイレクトブロックを指定するインデックスbnを算出します。

bn < NINDIRECTの場合はiノードが間接的に所有しているデータブロックのセクタ番号を取得する

if(bn < NINDIRECT){
   ....

インダイレクトブロックにおけるインデックスbnが0〜127の場合に、if文内の処理に入ります。

必要であれば各インダイレクトブロックのセクタ番号を格納しているセクタを割り当てる

    if((addr = ip->addrs[NDIRECT]) == 0)
      ip->addrs[NDIRECT] = addr = balloc(ip->dev);

(addr = ip->addrs[NDIRECT]) == 0 が真となる場合→ip->addrs[NDIRECT]にセクタ番号が格納されていない場合→各インダイレクトブロックのセクタ番号を格納するデータブロックにセクタが割り当てられていない場合は、balloc関数を呼び出して、各インダイレクトブロックのセクタ番号を格納するデータブロックにセクタを割り当てます。
addrs配列の最後尾要素addrs[NDIRECT]には、各インダイレクトブロックのセクタ番号を格納したデータブロックのセクタ番号が格納されています。

インダイレクトブロックのセクタ番号を格納しているセクタに対応しているバッファを取得する

 bp = bread(ip->dev, addr);

bread関数を呼び出して、各インダイレクトブロックのセクタ番号を格納するデータブロック(セクタ)に対応しているバッファを取得します。

インダイレクトブロックのセクタ番号を格納しているセクタのデータに4バイトずつアクセスできるようにする

a = (uint*)bp->data;

配列bp->dataには、各インダイレクトブロックのセクタ番号を格納しているデータブロック(セクタ)のデータが格納されています。
各インダイレクトブロックのセクタ番号を格納しているデータブロック(セクタ)では、4バイト分のデータを使って1つのセクタ番号を記録しているので、各インダイレクトブロックのセクタ番号を格納しているデータブロックには、インダイレクトブロックのセクタ番号が128個格納されています。
各インダイレクトブロックのセクタ番号を格納しているデータブロックの先頭アドレスbp->dataをuint型へのポインタaに格納することで、各インダイレクトブロックのセクタ番号を格納しているデータブロックのデータに、4バイトずつアクセスできるようになります(セクタ番号(4バイトサイズ)にアクセスできるようになります)。

インデックスbnが指定するインダイレクトブロックのセクタ番号を戻り値としてリターンする

    if((addr = a[bn]) == 0){
      a[bn] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    return addr;

(addr = a[bn]) == 0 が真となる場合 → a[bn]にインダイレクトブロックのセクタ番号が未だ格納されていない場合 → インデックスbnが指定するインダイレクトブロックにセクタが割り当てられていない場合は、balloc関数を呼び出してセクタの割り当てを行い、そのセクタのセクタ番号を戻り値としてリターンします。
その際リターンする前に、 log_write関数を呼び出してバッファbpに対応しているセクタをロギングにおけるトランザクションの管理対象として登録し、brelse関数を呼び出してバッファbpに関連しているスリープロックを解放しておきます。
(addr = a[bn]) == 0 が偽となる場合 → a[bn]にインダイレクトブロックのセクタ番号が既に格納されている場合 →インデックスbnが指定するインダイレクトブロックにセクタが割り当てられている場合は、そのセクタのセクタ番号を戻り値としてリターンします。
その際リターンする前に、 brelse関数を呼び出してバッファbpに関連しているスリープロックを解放しておきます。

bnの値が大きすぎる場合

panic("bmap: out of range");

インデックスbnの値がNINDIRECTを越える場合は、panic関数を呼び出してメッセージを出力します。