ファイルへの書き込みとファイル拡張

writeシステムコールは、vfs sys_write関数にて、ファイルディスクリプタに対応するファイル構造体を見つけ(fget関数)、ファイル構造体に登録されているwriteオペレーションを呼び出す。

ext2ファイルシステムの場合、 通常ファイルではgeneric_file_write関数が呼び出される。(v2.4からページキャッシュ経由の処理に書き換えられた)ディレクトリ、シンボリックリンクファイルの場合、このオペレーションは無登録であるため、sys_write処理はエラー終了する。

I/O要求が丁度ページ単位であるわけではないので、generic_file_write関数は、I/Oの先頭と最後のページをまずキャッシュ上に読み込み、その後I/O要求のあったデータを上書きしてやる必要がある。

   generic_file_write(ファイル構造体、ユーザ領域, ファイルポインタ)
      if(アペンドモードなら) ファイルポインタをファイルエンドにする
      while(書き込むデータがある間) {
           ページキャッシュを確保する(__grab_cache_page関数)
               (もしキャッシュ上になければ新規確保し、登録する)
           ページの書き込み準備をする(iノードのprepare_writeオペレーションを呼び出す)
                (ext2の場合は、block_prepare_writeが呼び出される。
                 必要があればディスクからデータを読み込んだり、
                 バッファのクリアを行う)
           ユーザ領域のデータをバッファに読み込む(copy_from_user関数)
           ページの書き込み要求を出す(iノードのcommit_writeオペレーションを呼び出す)
                (ext2の場合は、generic_commit_writeが呼び出される。
                 dirtyなバッファの遅延書き込み要求を出すのみ)
           ページキャッシュの解放(page_cache_release関数)
      }
img49.gif

ページキャッシュの章でも説明したように、block_prepare_write関数は、ページ書き込みのための準備をする関数である。generic_commit_write関数を呼ぶ前に呼び出しておく必要がある。

    block_prepare_write(iノード、I/O領域、読み込むページ, getblock関数)
        ページにまだバッファヘッドが割り付けられていなければ、
    バッファヘッドを確保しページとリンク(create_empty_buffer関数)
        for (バッファのある間) {
            I/O完了コールバック関数としては、end_buffer_io_syncを登録。
            if(バッファがブロックと対応付けられていない) {
                getblock関数(ext2では、ext2_getblock関数)を利用し、
                   inodeとファイルオフセットからブロック番号を求める。
                if (新規確保したバッファなら) {
                     もしバッファキャッシュにキャッシュが残っていれば
                       そいつの解放を行う(unmap_underlying_metadata関数)
                     0クリアする。
                }
                if (バッファがまだ有効でないなら)
                     I/O要求の発行(ll_rw_block関数)
            }
        }
        I/O完了を待ち合わせる(wait_on_buffer関数)

generic_commit_write関数は、ページの遅延書き込み要求を行う関数である。実際にはバッファキャッシュのフラッシュデーモン類に書き込みI/Oを委ねる。

    generic_commit_write(iノード、I/O領域、読み込むページ)
        for (ページに対応づけられたバッファ群に対し) {
            バッファを有効状態(BH_Uptodate)にし、
              かつバッファをDirtyな状態にする(__makr_dirty関数)
        }
        Dirtyなバッファが多いようならkflushデーモンを起動する(balance_dirty関数)
        ページを有効にする(SetPageUptodate関数)

問題点

  1. ファイル拡張は、ext2_getblock関数の中で自動的に行われる。 ファイル拡張時の問題点は、ext2_getblock関数を参照のこと。
  2. XXXX 2000.6.17現在、O_SYNCは未サポートのようだ。

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