Linux Kernel(2.6)の実装に関するメモ書き

ext2_get_block()


Rev.8を表示中。最新版はこちら

1. 概要

ext2fsのget_blockハンドラであるext2_get_block()の実装まとめ。

編集中

2. 処理概要

2.1 ext2_get_block()


ext2_get_block()の処理概要
/*
 * inodeが示すファイルのiblock番目のブロックにアクセスするための
 * パス(offsets)を取得する。
 * 2.2節参照
 */
int depth = ext2_block_to_path(inode, iblock, offsets, &boundary);
/*
 * offsetsをたどり、必要なブロックが全てディスク上に
 * 存在しているか確かめる。
 * 2.3節参照
 */
partial = ext2_get_branch(inode, depth, offsets, chain, &err);
if (!partial) {
    /* ブロックがディスク上に存在する場合 */
got_it:
    /* 判明したディスクブロックをbh_resultに設定する */
    map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
    if (boundary)
        set_buffer_boundary(bh_result);
    /* Clean up and exit */
    partial = chain+depth-1; /* the whole chain */
    goto cleanup;
}
/* ディスク上に未割り当てのブロックがある場合 */
if (!create || err == -EIO) {
    /* create = 0なら新規割り当てはせず終了 */
cleanup:
    while (partial > chain) {
        brelse(partial->bh);
        partial--;
    }
out:
    return err;
}
if (err == -EAGAIN)
    goto changed;
/*
 * 未割り当てブロックの新規割り当て処理
 */
/* ブロックの割り当て場所(goal)を決める */
goal = 0;
if (ext2_find_goal(inode, iblock, chain, partial, &goal) < 0)
    goto changed;

/* ブロックを割り当てる
 * partial以降のブロックが対象
 */
left = (chain + depth) - partial;
err = ext2_alloc_branch(inode, left, goal,
                         offsets+(partial-chain), partial);
if (err)
    goto cleanup;

if (ext2_use_xip(inode->i_sb)) {
    /*
     * we need to clear the block
     */
    err = ext2_clear_xip_target (inode,
              le32_to_cpu(chain[depth-1].key));
    if (err)
        goto cleanup;
}
/*  ei->i_next_alloc_block = block
このファイルに直近で割り当てたブロック番号(ファイル内のブロック番号)
 linearly ascending allocation requestsを検出するのに使われる。
    ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key);

    このファイルに対して直近で割り当てた物理ブロック番号
連続Request(linearly ascending)を検出した時の次の割り当て位置
*/
if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)
    goto changed;

set_buffer_new(bh_result);
goto got_it;

changed:
    while (partial > chain) {
        brelse(partial->bh);
        partial--;
}
goto reread;


2.2 ext2_block_to_path()

int ext2_block_to_path(*inode, i_block, offsets[4], *boundary)

ext2fsではi-node内にファイル内のブロックがディスク上のどこに存在しているのかブロック番号を格納したテーブルがある。ただしこのテーブルはファイル内の#0〜11番目のブロックのみしか格納しておらず、それ以降のブロックについてブロック番号を取得しようとすると、間接参照用のテーブルをたどっていく必要がある(「Ext2 FS」参照)。

ext2_block_to_path()はinodeで指定されたファイル内のi_block番目のブロックのブロック番号を取得するにあたって、間接参照用のテーブルのどのエントリを参照していけばよいのかをoffsetsに格納して返す。

例えばi_block=14のブロック番号を取得しようとした場合は、offsetsは図2.1のようになる。これは、まずi-node内の#12エントリから間接参照用テーブルのディスクブロック番号を読み出して、2段間接参照用テーブルを読み込んだ後、2段間接参照用テーブルの#2のエントリからi_block=14のブロックのブロック番号を取得できることを意味する(図2.2)。


図2.1 offsetとchain


図2.2 ブロックの間接アクセス


2.3 ext2_get_branch()

Indirect *ext2_get_branch(*inode, depth, *offsets, chain[4], *err)

ext2_get_branch()はext2_block_to_path()によって返されたoffsetsを受け取り、offsetsで指定されたパスのブロックがディスク上に割り当てられているか調べていく。

図2.1のケースだと、i-node内のブロックテーブルの#12エントリからブロック番号を取得して、そのブロックを読み込む(このブロックには間接参照テーブルが格納されている)。次に読み込んだ間接参照テーブルの#2エントリからi_block=14ブロックのブロック番号を取得する。最後までブロック番号を取得できれば、offsetsで指定されたパスのブロックは全てディスク上に存在していることになる。この場合、NULLが返る。

一方、エントリからブロック番号を取得した結果、0だった場合、そのブロックはまだディスク上には存在していないことになる。

offsetsをたどってブロック番号を取得した結果は、図2.1に示すようにchainに格納して返されるが、ブロック番号が未割り当てだった場合は.key=0となり、そのchain要素のアドレスが返される。この値は呼出し元で未割り当てのブロックを割り当てていくのに使われる。

3. 関連ページ



最終更新 2007/08/22 17:56:12 - kztomita
(2007/08/21 21:14:09 作成)
添付ファイル
indirect.png - kztomita
offset_chain.png - kztomita


リンク
最近更新したページ
検索