ファイルの移動 rename

ファイルの移動処理は、vfs sys_rename(do_rename)関数が行っている。移動元のファイルのdentryと移動先になるdentryを、lookup_dentry関数を用いて求めたあと、移動元のファイルの親ディレクトリのiノードのrenameオペレーションを呼び出す。

ext2ファイルシステムの場合、ディレクトリのrenameオペレーションは、 ext2_rename関数である。通常ファイルやシンボリックリンクファイルはrenameオペレーションを持っていない。

  ext2_rename(リンク元のファイルのdentry、移動先のディレクトリのiノード, 新しいdentry)
      移動元のファイルが登録されているディレクトリエントリを検索(ext2_find_entry関数)
      移動先のディレクトリに同名のファイルが登録されているか検索(ext2_find_entry関数)
      if(移動するファイルがディレクトリなら) {
           if(移動先に(ディレクトリ)ファイルが存在) {
                 if(空ディレクトリでない) return エラー
           }
           移動する(ディレクトリ)ファイルの先頭データブロックを読みだす(ext2_bread関数)
           if(移動する(ディレクトリ)ファイルの親ディレクトリのiノード番号が間違っている)
                return エラー
      }
      if(移動先にファイルが存在しないなら) {
           移動先の親ディレクトリに新しいdentryを登録(ext2_add_entry関数)
      } else { /* 移動先のファイルを上書きする場合 */
           移動先の親ディレクトリエントリに、移動するファイルのiノード番号を書き込む
           ◇移動先親ディレクトリブロックの遅延書き込み要求(mark_buffer_dirty関数)
           if(SYNC属性 ?) {
                ◆移動先親ディレクトリブロックの書き込み(ll_rw_block関数, wait_on_buffer関数)
           }
      }
      移動するファイルのiノードの更新時間設定
      ◇移動するファイルiノードの遅延書き込み要求(mark_inode_dirty関数)
      移動元の親ディレクトリエントリを削除(ext2_delete_entry関数)
      if(移動先のファイルを上書きした場合) {
           上書きされたiノードのリンク数を1減らす(i_nlinkメンバ)
           ◇上書きされたiノードの遅延書き込み要求(mark_inode_dirty関数)
      }
      移動元親ディレクトリiノードの更新時間設定
      ◇移動元親ディレクトリiノードの遅延書き込み要求(mark_inode_dirty関数)
      if(ディレクトリファイルの移動の時) {
           移動するディレクトリのデータブロック中の親ディレクトリの
              iノード番号を移動先の親ディレクトリのものに書き換える。
           ◇移動する(ディレクトリ)ファイルの先頭データブロックの遅延書き込み要求(mark_buffer_dirty関数)
           移動元親ディレクトリiノードのリンク数を一減らす
           ◇移動元親ディレクトリiノードの遅延書き込み要求(mark_inode_dirty関数)
           if(移動先のファイルを上書きした場合) {
                上書きされたiノードのリンク数を1減らす(i_nlinkメンバ)
                ◇上書きされたiノードの遅延書き込み要求(mark_inode_dirty関数)
           } else {
                移動先親ディレクトリiノードのリンク数を一増やす(i_nlinkメンバ)
                ◇移動先親ディレクトリiノードの遅延書き込み要求(mark_inode_dirty関数)
           }
      }

上書きされたファイルは、システムコール出口で呼び出すdput関数の延長で整理される。どこからも参照もリンクもされていないため、ファイルを構成するiノードとブロックがフリービットマップに返却される。

ファイルの移動の場合を下図に示す。

img53.gif

ディレクトリの移動の場合を下図に示す。

img54.gif

問題点など

  1. rename処理(ext2_rename)の途中で落ちると、リンクカウントが 1の状態のまま二つのディレクトリに登録されてしまう可能性もある。 このタイミングでシステムクラッシュしても、 fsckにより、容易に修復可能である。 ただし、fsck前にこのファイルを削除すると、存在しないiノードを 指すディレクトリエントリが残る。
  2. rename処理により上書きされたファイルがリンクされたもので あった場合、そのiノードが持つリンク数は遅延書き込みと なっているため、このタイミングでシステムがクラッシュすると、 実際にディレクトリに登録されている数より一つ大きいリンク数を iノードが保持してしまう。 これは、fsckにより容易に修復可能である。 もしfsckを行わずに運用した場合でも、このファイルの削除時に 浮きブロックとなるだけであり、ファイルシステム構造破壊には 継らない。
  3. 移動先のディレクトリの拡張が発生した場合、ディレクトリサイズを 保持する移動先ディレクトリiノードを同期書き込みしていない。 このタイミングでシステムがクラッシュすると、 移動したファイルが参照できなくなる可能性がある。 ただし、ファイルシステム構造の破壊に継るものではない。
  4. ディレクトリのrename処理において、".." の更新が 遅延書き込みになっている。システムクラッシュが発生すると、 移動したディレクトリに古い親ディレクトリ情報が残る ことがある。これもfsckにより容易に修正可能である。 もし、fsckなしで運用した場合でも、パスサーチルーチンは ".." の解決をVFSレベルで行ってしまうため、現在の版の linuxのアルゴリズムでは正常に動作してしまう。 しかし、このディレクトリを再びrenameしようとすると、 ".." のエラーチェックを行っているため、renameが失敗する。

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