iノードとデータブロックの結合の解除

ファイルのトランケート処理は以下の場合に呼び出される。明示的なtruncateシステムコール呼び出しでは、iノード内のi_sizeで示されるところまで解放する。

  • 明示的なtruncateシステムコール呼び出し
  • トランケートモードのopen時
  • ファイルの削除時
  ext2_truncate(iノード)
       先行拡張したブロックの解放(ext2_discard_prealloc関数)
       while(ブロックが残っている間) {
            直接ブロックの解放(trunc_direct関数)
            間接ブロックの解放(trunc_indirect関数)
            二段間接ブロックの解放(trunc_dindirect関数)
            三段間接ブロックの解放(trunc_tindirect関数)
            if(全ての解放が完了したら)
                 break
            if(SYNC属性 かつ iノードがDIRTY) {
                 ◆iノードのディスクへの書き込み(ext2_sync_inode関数)
            }
            スケジューラを呼び出し少し待つ(schedule関数)
       }
       if (ファイルの最後がブロック境界でない) {
            ファイル終端のブロックをバッファに読み出す(ext2_bread関数)
            このバッファにおいてファイル終端から最後までをクリアする。
            このバッファのファイル終端から最後までを0クリア
            ◇このバッファの遅延書き込み要求(mark_buffer_dirty関数)
            このバッファの解放
       }
       iノード更新時間更新
       ◇iノードの遅延書き込み要求(mark_inode_dirty関数)

  trunc_direct(iノード)
       iノードのファイルサイズから解放する直接ブロックの先頭エントリを求める
       while(iノードに解放する直接ブロックある間) {
	    if(その直接ブロックエントリが空?)
                  continue;
            if(解放しようとしているブロックのバッファが使用中)
                  continue;
            iノードのそのブロックが登録されていたエントリをクリア
            iノードに登録されているブロック数を減らす(メンバi_blocks)
            ◇iノードの遅延書き込み要求(mark_inode_dirty関数)
            バッファを無効化(bforget関数)
            連続分したブロックをまとめて解放(ext2_free_blocks関数)
       }
       連続分したブロックをまとめて解放(ext2_free_blocks関数)
       return 全て解放できたら0、失敗したら1

  trunc_indirect(iノード, 間接ブロックが登録されているエントリ番号, 
                   間接ブロックが登録されているエントリ)
       if(間接ブロックがない) return 0;

       間接ブロックを読み出す(bread関数)
       while(間接ブロックに解放するブロックがある間) {
            if(解放しようとしているブロックのバッファが使用中)
                   continue;
            間接ブロックのそのブロックが登録されていたエントリをクリア
            iノードに登録されているブロック数を減らす(メンバi_blocks)
            ◇iノードの遅延書き込み要求(mark_inode_dirty関数)
            バッファを無効化(bforget関数)
            連続分したブロックをまとめて解放(ext2_free_blocks関数)
       }
       連続分したブロックをまとめて解放(ext2_free_blocks関数)
       間接ブロック自体の解放(check_block_empty関数)
       return 全て解放できたら0、失敗したら1

  trunc_dndirect(iノード, 二段間接ブロックが登録されているエントリ番号, 
                   二段間接ブロックが登録されているエントリ)
       if(二段間接ブロックがない) return 0;
       二段間接ブロックを読み出す(bread関数)

       while(二段間接ブロックに解放する間接ブロックがある間) {
            間接ブロックに登録されているデータブロックの解放(trunc_indirect関数)
       }
       二段間接ブロック自体の解放(check_block_empty関数)
       return 全て解放できたら0、失敗したら1

  trunc_tindirect(iノード)
       if(三段間接ブロックがない) return 0;
       三段間接ブロックを読み出す(bread関数)

       while(三段間接ブロックに解放する二段間接ブロックがある間) {
            二間接ブロックに登録されている間接ブロックと
               データブロックの解放(trunc_dindirect関数)
       }
       三段間接ブロック自体の解放(check_block_empty関数)
       return 全て解放できたら0、失敗したら1

  check_block_empty(inode, bh, ind_bh)
       if(間接ブロックのバッファがI/O中なら)
             I/O完了を待ち合わせる

       if (間接ブロックに何か残っているなら) {
             if(SYNC属性 かつ 間接ブロックのバッファがDIRTY) {
                 ◆間接ブロックの書き込み(ll_rw_block関数, wait_on_buffer関数)
             }
             間接ブロックのバッファの解放(brelse関数)
             return 0;
       }
       if (他から、この間接ブロックのバッファが参照されている)
             return 1;
       if (間接ブロックが空なら) {
             iノード(または別の間接ブロック)から、この間接ブロックの登録を消す
             iノードに登録されているブロック数を減らす(メンバi_blocks)
             ◇iノードの遅延書き込み要求(mark_inode_dirty関数)
             間接ブロックのバッファを無効にする(bforget関数)
             間接ブロック自体を解放(ext2_free_blocks関数)
       }

下図は、ファイルトランケート処理の順番を図に表した物である。◆は同期書き込み、◇は遅延書き込みを表している。◆◇の後ろの数字は、その処理の順番を示している。

img40.gif

 

(NIS)HirokazuTakahashi
2000年06月11日 (日) 22時29分57秒 JST
1