fs.c void ilock(struct inode *ip)

トップページ
jupiteroak.hatenablog.com


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

void ilock(struct inode *ip)
{
  struct buf *bp;
  struct dinode *dip;

  if(ip == 0 || ip->ref < 1)
    panic("ilock");

  acquiresleep(&ip->lock);

  if(ip->valid == 0){
    bp = bread(ip->dev, IBLOCK(ip->inum, sb));
    dip = (struct dinode*)bp->data + ip->inum%IPB;
    ip->type = dip->type;
    ip->major = dip->major;
    ip->minor = dip->minor;
    ip->nlink = dip->nlink;
    ip->size = dip->size;
    memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
    brelse(bp);
    ip->valid = 1;
    if(ip->type == 0)
      panic("ilock: no type");
  }
}

ilock関数は、引数で渡されたiノードをスリープロックします。必要であれば、ハードディスクからiノードの読み込みを行います。

引数 struct inode *ip
スリープロックの対象となるiノード(inode構造体)のアドレスです。


処理の内容

iノードが不正な状態ではないことを確認する

if(ip == 0 || ip->ref < 1)
    panic("ilock");

ip == 0 || ip->ref < 1 が真となる場合→引数ipにiノードが指定されていない、または、iノードの参照回数が0となる場合は、panic関数を呼び出してメッセージを出力します。

iノードに関連しているスリープロックを取得する

acquiresleep(&ip->lock);

acquiresleep関数を呼び出してスリープロックを取得します。

iノードに含まれる内容が無効状態の場合

if(ip->valid == 0){
    
  ....
  }

ip->valid == 0 が真となる場合→iノードの内容が無効状態として記録されている場合は、ハードディスクからiノードの読み込みを行います。

ハードディスクから該当するiノードを含んだセクタに対応しているバッファを取得する

bp = bread(ip->dev, IBLOCK(ip->inum, sb));

bread関数を呼び出して、ハードディスク上にあるiノードの読み込みを行います(あるいは、ハードディスクからiノード番号がinumであるiノードを含んだセクタに対応しているバッファを取得します)。
第二引数に設定されているIBLOCKマクロは、iノード番号がinumであるiノードを含んだセクタのセクタ番号を算出します。
bread関数は、第二引数で指定されたセクタ番号を持つセクタのデータ512バイト(32個のiノード= 512÷dinodeのデータサイズ)を取得します。

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

dip = (struct dinode*)bp->data + ip->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ノードの内容を取得する①

ip->type = dip->type;
ip->major = dip->major;
ip->minor = dip->minor;
ip->nlink = dip->nlink;
ip->size = dip->size;

dinode構造体(ハードディスク上にあるiノードを表現したデータ構造)の各メンバの値で、inode構造体(メインメモリ上にあるiノードを表現したデータ構造)の各メンバの値を、更新します。

ハードディスク上にあるiノードの内容を取得する②

memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));

memmove関数を呼び出して、dinode構造体が持つaddrs配列からinode構造体が持つaddrs配列へ、データブロックの参照をコピーします。
addrs配列には、iノードが直接的に所有しているデータブロックのセクタ番号がそれぞれ格納されています。

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

brelse(bp);

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

iノードの内容が有効であることを記録する

ip->valid = 1;

validメンバに1を設定して、iノードの内容が有効であることを記録します。

iノードの用途が定められていない場合はメッセージを出力する

if(ip->type == 0)
panic("ilock: no type");

タイプメンバの値(ファイル、ディレクトリ、デバイスを識別する値)が0の場合は、panic関数を呼び出してメッセージを出力します。