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ノードに関連したスリープロックを取得する
- iノードの内容が有効かつiノードを参照しているディレクトリがない場合
- スリープロックを解放する
- クリティカルセクション内でiノードの参照回数をデクリメントする
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ノードの内容が無効であることを記録します)。
クリティカルセクション内でiノードの参照回数をデクリメントする
acquire(&icache.lock); ip->ref--; release(&icache.lock);
クリティカルセクション内で参照回数をデクリメントします。
iget関数やidup関数によってip->refの値が変更されるのを防ぐために、acquire関数とrelease関数を呼び出してクリティカルセクションを設けます。