ファイルオフセットからブロック番号への変換

ext2ファイルシステムでは、ext2_getblk関数がファイルオフセットからブロックへの変換処理とデータブロック割り当て処理を同時に行っているが、ページI/Oなどでは、vfsから直接ページとブロック間のI/Oが起動される。このとき必要となる純粋にファイルオフセットに対応するブロック番号を求める関数(ext2_bmap関数、ext2_get_block関数)も用意している。(処理本体は、ext2_get_block関数。ext2_bmapを呼び出すとファイル拡張無しでext2_get_block関数が呼び出される)

あるファイルのファイル内オフセットに対応するブロックのバッファを獲得する関数がext2_getblk関数である。この関数は、指定されたファイル内オフセットに対応するブロックが割り当てられていない時、自動的にブロック割当を行う。つまりext2_get_block関数をファイル拡張ありで呼び出す。(自動確保するかどうかは、引き数により指定可能)

  ext2_get_block(iノード、オフセット、返却値設定用バッファヘッド、createフラグ)
        if(ファイル拡張指定でない場合) {
               ファイルオフセットをブロック番号に変換(ext2\_block\_map関数)
               得られたブロック番号を指定されたバッファヘッドに設定
               return バッファヘッド
        }
        if(ファイルオフセットが直接ブロックの範囲) {
               データブロックのバッファ =
                   inode_getblk(iノード, iノード内のブロック登録エントリ番号, ...);
        } else if(ファイルオフセットが一段間接ブロックの範囲) {
               間接ブロックのバッファ =
                   inode_getblk(iノード, iノード内の間接ブロックの登録エントリ番号, ...);
               データブロックのバッファ =
                   block_getblk(iノード, 間接ブロックのバッファ, 間接ブロック内のデータブロック登録エントリ番号, ...);
        } else if(ファイルオフセットが二段間接ブロックの範囲) {
               一段目の間接ブロックのバッファ =
                     inode_getblk(iノード, iノード内の一段目の間接ブロックの登録エントリ番号, ...);
               二段目の間接ブロックのバッファ =
                     block_getblk(iノード, 一段目の間接ブロックのバッファ, 一段目の間接ブロック内の二段目の間接ブロック登録エントリ番号, ...);
               データブロックのバッファ =
                     block_getblk(iノード, 二段目の間接ブロックのバッファ, 二段目の間接ブロック内のデータブロック登録エントリ番号, ...);
        } else { /* 三段間接 */
               一段目の間接ブロックのバッファ =
                     inode_getblk(iノード, iノード内の一段目の間接ブロックの登録エントリ番号);
               二段目の間接ブロックのバッファ =
                     block_getblk(iノード, 一段目の間接ブロックのバッファ, 一段目の間接ブロック内の二段目の間接ブロック登録エントリ番号);
               三段目の間接ブロックのバッファ =
                     block_getblk(iノード, 二段目の間接ブロックのバッファ, 二段目の間接ブロック内の三段目の間接ブロック登録エントリ番号);
               データブロックのバッファ =
                     block_getblk(iノード, 三段目の間接ブロックのバッファ, 三段目の間接ブロック内のデータブロック登録エントリ番号);
        }
        バッファにブロックを登録
               return データブロックのバッファ;

下記は、ファイル拡張が指定されていない場合に呼び出される、純粋なファイルオフセットからブロック番号への変換ルーチンである。

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

inode_bmap関数は、単純に指定されたメモリiノードの指定されたエントリに登録されているブロック番号を読み出すだけ。block_bmap関数は、単純に指定されたメモリ上の間接ブロックの指定されたエントリに登録されているブロック番号を読み出すだけ。

inode_getblk関数は、直接iノードに継っているブロック(直接データブロック、および一段目の間接ブロック)に対応するバッファを獲得する関数である。もし指定されたブロックがiノードに登録されていなければ、フリーブロックを見つけて来てiノードに登録する。アルゴリズム中に付いている◆印は同期書き込みを、◇印は遅延書き込みを表す。

  inode_getblk(iノード、iノード内オフセット)
      if(iノード内オフセットで指定された箇所にブロックが登録されている) {
            if(間接ブロックアクセスなら) {
                 そのブロックに対応したバッファを確保(getblk関数)
                 return バッファ
            } else {
                 return ブロック番号
            }
      }
      空きブロックを確保(ext2_alloc_block関数)
      if(間接ブロックアクセスなら) {
            確保したブロックに対応するバッファを確保(getblk関数)
            バッファがI/O中なら完了を待ち合わせる。
            バッファをクリア(memset関数)
            バッファを有効にする(mark_buffer_update関数)
          ◇バッファの遅延書き込み要求をだす(mark_buffer_dirty関数)
      } else {
            確保したブロックを返却値に登録
      }
      iノードにこの確保したブロックを登録
      iノードの登録ブロック数情報更新(i_blocks)
      if(SYNC属性 または、同期モードopen?) {
          ◆iノードをディスクに書き込む(ext2_sync_inode関数)
      } else {
          ◇iノードの遅延書き込み要求を出す(mark_inode_dirty関数)
      }
      return 確保したブロックのバッファ;

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

  block_getblk(iノード, 間接ブロックのバッファ, 間接ブロック内オフセット)
      if(間接ブロック内オフセットで指定された箇所にブロックが登録されている) {
            if(間接ブロックアクセスなら) {
                 そのブロックに対応したバッファを確保(getblk関数)
                 return バッファ
            } else {
                 return ブロック番号
            }
      }
      空きブロックを確保(ext2_alloc_block関数)
      if(間接ブロックアクセスなら) {
            確保したブロックに対応するバッファを確保(getblk関数)
            バッファがI/O中なら完了を待ち合わせる。
            バッファをクリア(memset関数)
            バッファを有効にする(mark_buffer_update関数)
          ◇バッファの遅延書き込み要求をだす(mark_buffer_dirty関数)
      } else {
            確保したブロックを返却値に登録
      }
      間接ブロックに確保したブロックを登録
      ◇間接ブロックの遅延書き込み要求をだす(mark_buffer_dirty関数)
      if(SYNC属性 または、同期モードopen?) {
          ◆間接ブロックをディスクに書き込む(ll_rw_block関数,wait_on_buffer関数)
      }
      iノードの登録ブロック数情報更新(i_blocks)
      ◇iノードの遅延書き込み要求を出す(mark_inode_dirty関数)
      間接ブロックのバッファの解放(brelse関数)
      return 確保したブロックのバッファ

 

(NIS)HirokazuTakahashi
2000年12月09日 (土) 23時55分06秒 JST
1