fs.c static void itrunc(struct inode *ip)

トップページ
jupiteroak.hatenablog.com


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

static void itrunc(struct inode *ip)
{
  int i, j;
  struct buf *bp;
  uint *a;

  for(i = 0; i < NDIRECT; i++){
    if(ip->addrs[i]){
      bfree(ip->dev, ip->addrs[i]);
      ip->addrs[i] = 0;
    }
  }

  if(ip->addrs[NDIRECT]){
    bp = bread(ip->dev, ip->addrs[NDIRECT]);
    a = (uint*)bp->data;
    for(j = 0; j < NINDIRECT; j++){
      if(a[j])
        bfree(ip->dev, a[j]);
    }
    brelse(bp);
    bfree(ip->dev, ip->addrs[NDIRECT]);
    ip->addrs[NDIRECT] = 0;
  }

  ip->size = 0;
  iupdate(ip);
}

itrunc関数は、引数で指定されたiノードを未使用状態に戻します。

引数 struct inode *ip
未使用状態となるiノード(inode構造体)を指定するアドレスです。


処理の内容

iノードが直接的に所有している全てのデータブロックを解放する

for(i = 0; i < NDIRECT; i++){
    ...
  }

iノードが直接的に所有している全てのデータブロックを解放します。iノードのデータ構造を表現したinode構造体のメンバであるaddrs配列には、iノードが直接的に所有しているデータブロックのセクタ番号がそれぞれ格納されています。

addrs配列の要素を初期化する

if(ip->addrs[i]){
      bfree(ip->dev, ip->addrs[i]);
      ip->addrs[i] = 0;
}

ip->addrs[i]が真となる場合→addrs配列の要素にデータブロックのセクタ番号が格納されている場合は、bfree関数を呼び出して、ハードディスク上にあるビットマップ領域にデータブロックのセクタが未使用であることを記録します。その後、addrs配列の要素ip->addrs[i]を0で初期化します。

iノードが間接的に所有している全てのデータブロックを解放する

if(ip->addrs[NDIRECT]){
    ...
  }

ip->addrs[NDIRECT] が真となる場合→ip->addrs[NDIRECT]にセクタ番号が格納されている場合は、iノードが間接的に所有している全てのデータブロック(インダイレクトブロック)を解放します。
addrs配列の最後尾要素addrs[NDIRECT]には、各インダイレクトブロックのセクタ番号を格納したデータブロックのセクタ番号が格納されています。

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

bp = bread(ip->dev, ip->addrs[NDIRECT]);

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

全てのインダイレクトブロックを解放する

a = (uint*)bp->data;
for(j = 0; j < NINDIRECT; j++){
      if(a[j])
        bfree(ip->dev, a[j]);
}

全てのインダイレクトブロックを解放するために、各インダイレクトブロックのセクタ番号を格納しているデータブロックを調べます。
各インダイレクトブロックのセクタ番号を格納しているデータブロック(セクタ)では、4バイト分のデータを使って1つのセクタ番号を記録しているので、各インダイレクトブロックのセクタ番号を格納しているデータブロックには、インダイレクトブロックのセクタ番号が128個格納されています。
配列bp->dataには、各インダイレクトブロックのセクタ番号を格納しているデータブロック(セクタ)のデータが格納されています。
各インダイレクトブロックのセクタ番号を格納しているデータブロックの先頭アドレスbp->dataをuint型へのポインタaに格納し、インデックスjを用いることで、各インダイレクトブロックのセクタ番号を格納しているデータブロックのデータに、4バイトずつアクセスできるようになります(セクタ番号(4バイトサイズ)にアクセスできるようになります)。
a[j])が真となる場合→a[j])にインダイレクトブロックのセクタ番号が格納されている場合は、bfree関数を呼び出して、ハードディスク上にあるビットマップ領域にデータブロックのセクタが未使用であることを記録します。

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

brelse(bp);

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

インダイレクトブロックのセクタを未使用状態にする

bfree(ip->dev, ip->addrs[NDIRECT]);
ip->addrs[NDIRECT] = 0;

bfree関数を呼び出して、ハードディスク上にあるビットマップ領域に各インダイレクトブロックのセクタ番号を格納しているデータブロックのセクタが未使用であることを記録します。
その後、addrs配列の最後尾要素ip->addrs[NDIRECT]を0で初期化します。

iノードのサイズが0であることを記録する

ip->size = 0;

iノードが所有する全てのデータブロックを解放したので、サイズメンバの値を0にします。

iノードの変更をハードディスクに反映させる

iupdate(ip);

iupdate関数を呼び出して、引数で渡されたメインメモリ上にあるiノードipを使って、ハードディスク上にあるiノードを、更新します。