fs.c struct inode* ialloc(uint dev, short type)

トップページ
jupiteroak.hatenablog.com


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

struct inode* ialloc(uint dev, short type)
{
  int inum;
  struct buf *bp;
  struct dinode *dip;

  for(inum = 1; inum < sb.ninodes; inum++){
    bp = bread(dev, IBLOCK(inum, sb));
    dip = (struct dinode*)bp->data + inum%IPB;
    if(dip->type == 0){  // a free inode
      memset(dip, 0, sizeof(*dip));
      dip->type = type;
      log_write(bp);   // mark it allocated on the disk
      brelse(bp);
      return iget(dev, inum);
    }
    brelse(bp);
  }
  panic("ialloc: no inodes");
}

ialloc関数は、ハードディスク上のiノード領域から未使用状態となっているiノードを取得し、メインメモリ上にあるiノードのキャッシュ領域からそのiノードを利用できるようにします。

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

引数 short type
取得対象となるiノードの用途(ファイル、ディレクトリ、デバイスのいずれか)を指定します。

戻り値 inode構造体のアドレス
取得対象となるiノードを指定するアドレスです。


処理の内容

ハードディスク上のiノード領域から未使用状態となっているiノードを探す

for(inum = 1; inum < sb.ninodes; inum++){
    bp = bread(dev, IBLOCK(inum, sb));
    dip = (struct dinode*)bp->data + inum%IPB;
    if(dip->type == 0){  // a free inode
      memset(dip, 0, sizeof(*dip));
      dip->type = type;
      log_write(bp);   // mark it allocated on the disk
      brelse(bp);
      return iget(dev, inum);
    }
    brelse(bp);
  }

ハードディスク上のiノード領域内にあるセクタを先頭から順に1つずつ読み込み、未使用状態となっているiノードを探します。

iノード番号inumのiノードが含まれるセクタに対応しているバッファを取得する

bp = bread(dev, IBLOCK(inum, sb));

bread関数を呼び出して、iノード番号がinumであるiノードを含んだセクタに対応しているバッファを取得します。
第二引数に設定されているIBLOCKマクロは、iノード番号がinumであるiノードを含んだセクタのセクタ番号を算出します。

取得したバッファのデータから該当するiノードを取り出す

dip = (struct dinode*)bp->data + inum%IPB;

iノード番号inumのiノードを取得するために、取得したバッファに格納されているデータの先頭アドレスbp->dataをdinode構造体へのポインタに格納し、そのポインタにinum%IPBを加算します。dinode型へのポインタに加算する操作により、sizeof(struct dinode)バイト境界のアドレス(dinode構造体のデータサイズの倍数値となるアドレス)で、取得したバッファに格納されているデータにアクセスすることができます。これは、取得したバッファに格納されているデータがdinode構造体の配列として、ポインタに加算する値inum%IPBが配列のインデックスとして、機能していることと実質的に同じです。
IPBは、ブロック1個当たりのiノード数を算出するマクロです。inumをIPBで剰余演算した値であるinum%IPBは、dinode構造体の配列(取得したバッファに格納されているデータ→セクタ内のデータ)において、iノード番号inumのiノードを指定するインデックスとなります。

取り出したiノードが未使用状態だった場合

 if(dip->type == 0){  // a free inode
      ...
    }

dip->type == 0 が真となる場合→未使用状態のiノードがみつかった場合は、そのiノードを初期化して、メインメモリ上にあるiノードのキャッシュからそのiノードを取得できるようにします。

iノードを初期化する
memset(dip, 0, sizeof(*dip));

memset関数を呼び出して、iノード(先頭アドレスdip・サイズsizeof(*dip)のメモリ領域)を0で初期化します。

iノードのタイプを設定する
dip->type = type

引数typeで指定された値をdipのtypeメンバに設定します。

iノードを含んだセクタをロギングにおけるトランザクションの管理対象として登録する
log_write(bp)

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

バッファのスリープロックを解放する
brelse(bp);

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

メインメモリ上にあるiノードのキャッシュからiノードを取得できるようにする
return iget(dev, inum);

iget関数を呼び出して、ハードディスク上からみつけたiノードを、メインメモリ上に用意されているiノードのキャッシュ領域から、取得できるようにします。

取り出したiノードが未使用状態ではなかった場合

brelse(bp);

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

未使用状態のiノードがみつからなかった場合はエラーメッセージを出力する

panic("ialloc: no inodes");

未使用状態のiノードがみつからなかった場合は、panic関数を呼び出してメッセージを出力します。