Personal tools
You are here: Home ブログ 学習経過 I/O スケジューラ (その7)
« December 2010 »
Su Mo Tu We Th Fr Sa
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
Recent entries
sysfs tips 02 ohyama 2010-09-09
sysfs tips ohyama 2010-09-02
Haskell で周波数スペクトルを得る ohyama 2010-07-29
Haskell で線形識別関数の学習を行う ohyama 2010-07-19
Haskell で逆行列を求める ohyama 2010-07-16
Recent comments
Re:vim に lisp 機能をつける t.mimori 2010-12-16
Re:Haskell で周波数スペクトルを得る H.OHYAMA 2010-08-01
Re:lkml でお勉強 (その1-1) Hiroyasu OHYAMA 2009-08-21
Re:lkml でお勉強 (その1-1) kosaki 2009-08-20
Re:vim に lisp 機能をつける ohyama 2008-05-08
Categories
学習経過
GNU/Linux
 
Document Actions

I/O スケジューラ (その7)

1. はじめに

 前回は CFQ における elevator_merged_fn メソッドの実体と I/O ブロックレイヤにおける周辺処理をしらべて、こいつがどんな役割を担っているのかという事を調べ、リクエストオブジェクト同士におけるマージの後に呼ばれる処理で、I/O スケジューラではマージしたリクエストを内部キューから外し、必要に応じて内部キューにおけるマージされたリクエストのリスト位置を更新していた。


2. 概要

 今回は I/O スケジューラの elevator_allow_merge_fn メソッドの役割と CFQ の実装、及び関連する I/O ブロックレイヤの処理についてみてゆく。

 例によってまずは、カーネルドキュメント [1] から処理の概要について調べる。

elevator_allow_merge_fn    called whenever the block layer determines
        that a bio can be merged into an existing
        request safely. The io scheduler may still
        want to stop a merge at this point if it
        results in some sort of conflict internally,
        this hook allows it to do that.


 ドキュメントには、bio オブジェクトをリクエストオブジェクトにマージする際に、マージ可能かどうかを判定するという事が書かれている。

 
3. 学習内容のまとめ
 
 elevator_allow_merge_fn メソッドを含む I/O ブロックレイヤにおける bio オブジェクトの request オブジェクトへのマージ関連処理の一連の動作は次のようになっている。
 I/O ブロックレイヤは bio オブジェクトを request オブジェクトにマージする前に elv_rq_merge_ok() 関数を実行し、bio オブジェクトを引数で渡した request オブジェクトにマージできるかどうかの確認を行う。
 そして I/O ブロックレイヤで bio オブジェクトを request オブジェクトに対してマージ可能だと判断した後、I/O スケジューラ的にマージ可能かどうかを確かめるために、I/O ブロックレイヤは elevator_allow_merge_fn メソッドを呼び出してこれを確認する。
 I/O スケジューラ側では、当該マージ要求に対して、マージされては困るケースについて elevator_allow_merge_fn メソッドの実体として記述する。
 尚、I/O スケジューラは、elevator_allow_merge_fn メソッドに対する応答としてマージ可能ならば 1 を返し、マージしてほしくない場合には 0 を返す。


4. 内容詳細
 
 それでは、実際に CFQ の elevator_allow_merge_fn メソッドの実態である cfq_allow_merge() について見て行く。以下がそのコード。

static int cfq_allow_merge(struct request_queue *q, struct request *rq,
               struct bio *bio)
{
    struct cfq_data *cfqd = q->elevator->elevator_data;
    struct cfq_io_context *cic;
    struct cfq_queue *cfqq;

    /*
     * Disallow merge of a sync bio into an async request.
     */
    if (cfq_bio_sync(bio) && !rq_is_sync(rq))
        return 0;

    /*
     * Lookup the cfqq that this bio will be queued with. Allow
     * merge only if rq is queued there.
     */
    cic = cfq_cic_rb_lookup(cfqd, current->io_context);
    if (!cic)
        return 0;

    cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
    if (cfqq == RQ_CFQQ(rq))
        return 1;

    return 0;
}


 引数で渡した bio オブジェクトとリクエストオブジェクトの I/O タイプが異なる場合、CFQ はマージ不可と判断する。I/O タイプについては前回の話を参照してもらいたい。
 又、cfq_cic_rb_lookup() によって cfq_io_context が取得できないケースも同様にマージ不可と判断する。cfq_cic_rb_lookup() 関数については前々回に話をしたので、それを参照してもらいたい。
 cfq_allow_merge() では、cfq_cic_rb_lookup() の呼び出しを行う際に、cfq_data オブジェクトとカレントプロセスの io_context オブジェクトをこれに渡している。
 cfq_data オブジェクトは I/O ブロックレイヤが持つ elevator_queue オブジェクトの elevator_data メンバが参照するオブジェクトであり io_context オブジェクトはカレントプロセスが参照している。
 つまり CFQ I/O スケジューラのデータ構造の設計では、プロセスのブロックデバイスの組合せによって cfq_io_context オブジェクトが一意に決定されるという事がわかる。また、cfq_cic_rb_lookup() から cfq_io_context オブジェクトと cfq_data オブジェクトが1対1に対応する事もわかる。
 そして cfq_allow_merge() では最後に、取得した cfq_io_context オブジェクトが持つ2本の cfq_queue オブジェクトのうち、マージする bio オブジェクトの cfq_queue オブジェクトを取得し、これがマージされるリクエストオブジェクトが参照する CFQ の内部リクエストキューである場合にのみ、マージ可能であると判断する。

 以上が CFQ における elevator_allow_merge_fn メソッドの実装である。
 ここで elevator_allow_merge_fn メソッドを実行している I/O ブロックレイヤの処理を見てみる。次に示すのは後述する I/O ブロックレイヤの elv_rq_merge_ok() コードである。

/*
 * can we safely merge with this request?
 */
inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
{
    if (!rq_mergeable(rq))
        return 0;

    /*
     * different data direction or already started, don't merge
     */
    if (bio_data_dir(bio) != rq_data_dir(rq))
        return 0;

    /*
     * must be same device and not a special request
     */
    if (rq->rq_disk != bio->bi_bdev->bd_disk || rq->special)
        return 0;

    if (!elv_iosched_allow_merge(rq, bio))
        return 0;

    return 1;
}

 
 I/O ブロックレイヤは elv_iosched_allow_merge() [block/elevator.c] から elevator_allow_merge_fn メソッドを呼び出しており、その呼び出し元は elv_rq_merge_ok() [block/elevator.c] である。
 そして、elv_iosched_allow_merge() が 0 を返すと、無条件で elv_rq_merge_ok() は 0 を返す。


5. まとめ

 今回学習した内容は次の3つ。

 (1) CFQ I/O スケジューラにおける elevator_allow_merge_fn メソッドの実装
 (2) I/O スケジューラ一般における elevator_allow_merge_fn メソッドの処理の役割
 (3) I/O ブロックレイヤにおける bio オブジェクト併合許可の確認処理の中身


 [1] Documentation/block/biodoc.txt

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/i-o-30b930b130e530fc30e9-305d306e7/tbping
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.