CFQ IOスケジューラのコードを見てみる。

LinuxのDiskIO用のスケジューラとして、CFQ IOスケジューラがある。
2.6.34から帯域制御が入ったので、ちょっとコードを見てみた。
大雑把に言うと、デバイスごとにスケジューラを設定し、プロセスグループごとにWeightを考慮してブロックキューを振り分けている。
そして、処理時間は、プロセスグループごとにvdisktimeで積算されており、値の一番小さいものから実行する。なお、時刻としては、jiffiesを用いている。
とはいえ、weightの取れる範囲が100から1000と狭いことや、帯域を保障しているわけでもないから、帯域制御としては基本的な機能が入っているだけともいえる。
これは、サーバ単体で見た話であり、データセンター単位で見ると、Fibre ChannelやiSCSI経由でストレージが接続されるので、
ストレージ側でも制御できてしまう。このため、OSに帯域制御が入らなければならないという理由もない。

  • 構造体
    • cfq_data
      • Per block device queue structure (各デバイスごとの構造体。各デバイスごとの動作が基本になりCFQのIOスケジューラは動く)
      • cfq_rb_root
        • rbtree for CFQ
        • total_weight
        • min_vdisktime
      • idle_slice_timer 定期的に呼び出されるタイマー デフォルトは、8ミリ秒(HZ/125)経過したときに呼び出される
      • unplug_work キューの切り替えの時に呼び出される関数
    • cfq_group(CFQの一塊。これをベースに帯域の割付を行う。)
      • per cgroup per device grouping structure
      • weight
      • vdisktime
    • cfq_queue(各IOリクエスト)
      • Per process-grouping structure
      • pid
  • 関数
    • cfq_group_service_tree_add ランキュー組み込み時の処理を行う。(cfqg->vdisktimeの初期化)
    • cfq_slice_expired ランキュータイムアウト時の処理を行う。(cfqg->vdisktimeの加算)
    • cfq_schedule_dispatch ランキューの切り替えを行う。
    • cfq_idle_slice_timer アイドル時の処理を定期的に行う。
  1. ドキュメント
    1. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/cgroups/blkio-controller.txt
  1. ソースコード
    1. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=block/cfq-iosched.c
    2. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=include/linux/elevator.h
    3. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=block/blk-cgroup.c
  • いうまでもなく、red-black tree (rb-tree)を知っておくとコードを読み易くなる。
  1. もう少し外枠なら、多少古いが以下が詳しい。
    1. http://www.valinux.co.jp/contents/tech/techlib/eos/cfq/cfq_01.html