ディレクトリ操作

ディレクトリから、ファイル名で指定されるファイルのエントリを見つけ出す。アクセス高速化のため、ディレクトリブロック用のバッファを先行して読みだしている。(現在は8ブロック先行読みだし)

  ext2_find_entry(ディレクトリのiノード, ファイル名, ... )

       ディレクトリの先頭ブロックから8つ分(NAMEI_RA_SIZE)のバッファを確保(ext2_getblk関数)
       for(ディレクトリブロックがある間) {
              if(確保したバッファにまだディレクトリデータが読み込まれていないなら)
                    まとめて読み込む(ll_rw_block関数)
              次に検索するディレクトリブロックの入ったバッファのI/O完了を待つ(wait_on_buffer関数)
              while(ディレクトリブロック中にディレクトリエントリがある間) {
	            if(ディレクトリエントリとファイル名が一致) {
                          先行確保したバッファを解放(brelse関数)
                          return 見つかったディレクトリエントリ
                    }
              }
              検索が終わったバッファを解放(brelse関数)
              次の読み込みに利用する代わりのバッファを確保(ext2_getblk関数)
       }
       バッファを全て解放(brelse関数)
       return NULL(発見できず)

ext2_add_entry関数は、ディレクトリにファイル名で指定されるファイルのエントリを追加する。ext2_find_entry関数と異なりディレクトリブロックの先行読み込み処理は行わず、1ブロックずつゆっくりと読み込み処理を行っている。

  ext2_add_entry(ディレクトリのiノード, ファイル名, ... )
       先頭のディレクトリブロックを読み込む(ext2_bread関数)
       while(1){
           if(このブロック中のディレクトリエントリを全て検索しつくした) {
                 ディレクトリブロックを読み込んだバッファを解放(brelse)
                 次のディレクトリブロックを読み込む(ext2_bread関数)
                 if (ディレクトリが拡張された) {
                      拡張されたブロックをディレクトリブロックとして初期化
                      iノード中のディレクトリサイズ情報を変更
                      ◇ディレクトリのiノードの遅延書き込み要求(mark_inode_dirty関数)
                 }
           }
           if (既に存在しているエントリと同じ名前なら)
                  return EEXISTエラー
           if (ディレクトリブロック内にファイル名を登録可能なスペースが見つかった){
               ディレックブロックを読み込んだバッファ内に、目的のファイルを登録する。
                   (空エントリならそこに登録する)
                   (大きなエントリなら、二つのエントリに分割し、そこに登録する)
                   (ディレクトリエントリに、登録するiノード番号を書き込む)
               ◇ディレクトリiノードの遅延書き込み要求(mark_inode_dirty関数)
               ◇ディレクトリブロックの遅延書き込み要求(mark_buffer_dirty関数)
               if(SYNC属性) {
                     ◆ディレクトリブロックの書き込み(ll_rw_block関数, wait_on_buffer関数)
               }
           }
       }
       ディレクトリのデータブロックを読み込んだバッファを解放(brelse)

ディレクトリブロックの先頭のディレクトリエントリ以外は、空のディレクトリエントリは置かず、削除されたディレクトリエントリは一つ前のディレクトリエントリにマージしてしまう。次にディレクトリエントリを追加する場合は、これら大きな空きスペースを持ったディレクトリエントリを探し出し、二つに再分割し利用する。

下図は、ファイル"baa"をディレクトリに登録/削除する時の動きを示している。

img43.gif
  ext2_delete_entry(ディレクトリエントリ, ディレクトリエントリが含まれるディレクトリブロックのバッファ)
       ディレクトリブロックのバッファの中から、目的のエントリを削除する
           (途中のエントリの削除は、一つ前のエントリと結合することにより実現)
           (先頭のエントリの削除は、iノード番号フィールドに0を入れることで実現)
           ◇ディレクトリブロックの遅延書き込み要求(mark_buffer_dirty関数)
           if(SYNC属性) {
                  ◆ディレクトリブロックの書き込み(ll_rw_block関数, wait_on_buffer関数)
           }

問題点、注意点

  1. ディレクトリ拡張が発生した場合、ディレクトリブロックを初期化し ディスクに書き込むタイミングと、iノードのファイルサイズを ディスクに書き込みタイミングは、上位モジュールの動作によって は、ディレクトリブロックより先にiノードが書き込まれてしまう。 これは、このタイミングでシステムクラッシュすると不正な ディレクトリブロックが残る可能性がある。(注)上位モジュールの 作りによる。
  2. ディレクトリ拡張が発生した場合、ディレクトリブロックの割当は ext2_bread関数の延長で行われるが、 ディレクトリのiノードそのものの更新は遅延書き込みとなっている。 つまり、このタイミングでシステムがクラッシュすると ファイルサイズ情報が更新されていないため、ディレクトリに 新規登録したファイルを参照できなくなってしまう。
  3. ディレクトリからのファイル名検索、ディレクトリへのファイル登録は、 毎回ディレクトリ先頭からの線形探索となる為、大きなディレクトリは アクセス速度の面で非常に不利である。

補足

ext2_add_entry関数は、エントリ名の重なりチェックは完全には行わない。呼び出し側で考慮しなければならない。


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