fs.c void iput(struct inode *ip)

トップページ
jupiteroak.hatenablog.com


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

void iput(struct inode *ip)
{
  acquiresleep(&ip->lock);
  if(ip->valid && ip->nlink == 0){
    acquire(&icache.lock);
    int r = ip->ref;
    release(&icache.lock);
    if(r == 1){
      // inode has no links and no other references: truncate and free.
      itrunc(ip);
      ip->type = 0;
      iupdate(ip);
      ip->valid = 0;
    }
  }
  releasesleep(&ip->lock);

  acquire(&icache.lock);
  ip->ref--;
  release(&icache.lock);
}

iput関数は、引数で渡されたiノードの参照回数をデクリメントします。引数で渡されたiノードの参照回数が0になった場合は、iノードを未使用状態に戻します。

引数 struct inode *ip
参照回数をデクリメントさせたいiノード(inode構造体)のアドレスです。


処理の内容

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

acquiresleep(&ip->lock);

iノードを排他制御する際にIDEへの入出力処理を行うので(itrunc、iupdateの処理内でプロセスが休止状態になる可能性があるので)、acquiresleep関数を呼び出してiノードに関連したスリープロックを取得します。

iノードの内容が有効かつiノードを参照しているディレクトリがない場合

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

ip->valid && ip->nlink == 0 が真となる場合→iノードの内容が有効 かつ iノードを参照しているディレクトリの数が0の場合は、if文内の処理に入ります。

クリティカルセクション内でiノードの参照回数を取得する

acquire(&icache.lock);
    int r = ip->ref;
release(&icache.lock);

クリティカルセクション内でip->refの値を取得します。iget関数やidup関数によってip->refの値が変更されるのを防ぐために、acquire関数とrelease関数を呼び出してクリティカルセクションを設けます。

参照回数が1の場合はiノードを未使用状態にする

if(r == 1){
      // inode has no links and no other references: truncate and free.
      ....
}

r == 1が真となる場合→iノードの参照回数が1の場合は、iノードを未使用状態にする処理を実行します。

iノードを未使用状態にする
itrunc(ip);
ip->type = 0;

itrunc関数を呼び出してiノードを未使用状態にし、typeメンバ(iノードの用途を指定するメンバ)を0で初期化します。

iノードの変更をハードディスクに反映させる
iupdate(ip);
ip->valid = 0;

iupdate関数を呼び出して、メインメモリ上にあるiノードの内容を使って、ハードディスク上にあるiノードの内容を更新します。
続いて、validメンバを0にします(iノードの内容が無効であることを記録します)。

スリープロックを解放する

releasesleep(&ip->lock);

releasesleep関数を呼び出して、スリープロックを解放します。

クリティカルセクション内でiノードの参照回数をデクリメントする

acquire(&icache.lock);
ip->ref--;
release(&icache.lock);

クリティカルセクション内で参照回数をデクリメントします。
iget関数やidup関数によってip->refの値が変更されるのを防ぐために、acquire関数とrelease関数を呼び出してクリティカルセクションを設けます。