ext2_getblk関数アルゴリズム

以下にその大雑把なアルゴリズムを示す。アルゴリズム中に付いている◆印は同期書き込みを、◇印は遅延書き込みを表す。

  ext2_getblk(iノード、オフセット, ...)
        if(ファイルオフセットが直接ブロックの範囲)
               データブロックのバッファ =
                   inode_getblk(iノード, iノード内のブロック登録エントリ番号);
               return データブロックのバッファ;
        if(ファイルオフセットが一段間接ブロックの範囲) {
               間接ブロックのバッファ =
                   inode_getblk(iノード, iノード内の間接ブロックの登録エントリ番号);
               データブロックのバッファ =
                   block_getblk(iノード, 間接ブロックのバッファ, 間接ブロック内のデータブロック登録エントリ番号);
               return データブロックのバッファ;
        }
        if(ファイルオフセットが二段間接ブロックの範囲) {
               一段目の間接ブロックのバッファ =
                     inode_getblk(iノード, iノード内の一段目の間接ブロックの登録エントリ番号);
               二段目の間接ブロックのバッファ =
                     block_getblk(iノード, 一段目の間接ブロックのバッファ, 一段目の間接ブロック内の二段目の間接ブロック登録エントリ番号);
               データブロックのバッファ =
                     block_getblk(iノード, 二段目の間接ブロックのバッファ, 二段目の間接ブロック内のデータブロック登録エントリ番号);
               return データブロックのバッファ;
        }
       一段目の間接ブロックのバッファ =
             inode_getblk(iノード, iノード内の一段目の間接ブロックの登録エントリ番号);
       二段目の間接ブロックのバッファ =
             block_getblk(iノード, 一段目の間接ブロックのバッファ, 一段目の間接ブロック内の二段目の間接ブロック登録エントリ番号);
       三段目の間接ブロックのバッファ =
             block_getblk(iノード, 二段目の間接ブロックのバッファ, 二段目の間接ブロック内の三段目の間接ブロック登録エントリ番号);
       データブロックのバッファ =
             block_getblk(iノード, 三段目の間接ブロックのバッファ, 三段目の間接ブロック内のデータブロック登録エントリ番号);
       return データブロックのバッファ;

inode_getblk関数は、直接iノードに継っているブロック(直接データブロック、および一段目の間接ブロック)に対応するバッファを獲得する関数である。もし指定されたブロックがiノードに登録されていなければ、フリーブロックを見つけて来てiノードに登録する。

  inode_getblk(iノード、iノード内オフセット)
      if(iノード内オフセットで指定された箇所にブロックが登録されている) {
            そのブロックに対応したバッファを確保(getblk関数)
            return バッファ;
      }
      if(自動的にブロック割当をしないなら) return;
      空きブロックを確保(ext2_alloc_block関数)
      確保したブロックに対応するバッファを確保(getblk関数)
      iノードにこの確保したブロックを登録
      iノードの登録ブロック数情報更新(i_blocks)
      if(SYNC属性 または、同期モードopen?) {
          ◆iノードをディスクに書き込む(ext2_sync_inode関数)
      } else {
          ◇iノードの遅延書き込み要求を出す(mark_inode_dirty関数)
      }
      return 確保したブロックのバッファ;
  block_getblk(iノード, 間接ブロックのバッファ, 間接ブロック内オフセット)
      if(間接ブロック内オフセットで指定された箇所にブロックが登録されている) {
            そのブロックに対応したバッファを確保(getblk関数)
            return バッファ;
      }
      if(自動的にブロック割当をしないなら) return;
      空きブロックを確保(ext2_alloc_block関数)
      確保したブロックに対応するバッファを確保(getblk関数)
      間接ブロックに確保したブロックを登録
      ◇間接ブロックの遅延書き込み要求をだす(mark_buffer_dirty関数)
      if(SYNC属性 または、同期モードopen?) {
          ◆間接ブロックをディスクに書き込む(ll_rw_block関数,wait_on_buffer関数)
      }
      iノードの登録ブロック数情報更新(i_blocks)
      ◇iノードの遅延書き込み要求を出す(mark_inode_dirty関数)
      間接ブロックのバッファの解放(brelse関数)
      return 確保したブロックのバッファ

下図は、ちょうど二段間接ブロックが作成される時の、データの更新順を表したものである。◆の後ろに書かれた番号が更新順を表している。

img39.gif

問題点など

  1. SYNCモードのマウント時、iノードと間接ブロック(一段〜三段)の 更新順序が逆。iノードに近い方から更新されているが、 その更新途中でシステムクラッシュすると、不定の値を持つ 間接ブロックが登録されてしまうことがある。 この間接ブロックの値によっては致命的なファイルシステム 破壊を引き起こす可能性がある。
  2. SYNCモードのマウント時、ファイル拡張が連続すると、 その度ブロック確保とiノード(間接ブロック)への登録のため、 毎回iノード(間接ブロック)の同期書き込みが発生するため、 I/Oネックとなることが予想される。

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