I/Oスケジューラ
1. 概要
ブロックI/O要求のスケジュールを行いI/Oを効率化する。Linux2.6から導入された。スケジューラには表1に示す4種類がある。デフォルトではAnticipatoryスケジューラが使用される(RedHatではCFQがデフォルトらしい)。chosen_elevator[]には選択されたI/Oスケジューラの名前が格納される。I/Oスケジューラはシステムで1つ。混在はできない。
表1 I/Oスケジューラの種類
スケジューラ |
関連config |
ElevatorType |
---|---|---|
Anticipatory(Default) | CONFIG_IOSCHED_AS | iosched_as |
Deadline |
CONFIG_IOSCHED_DEADLINE | iosched_deadline |
CFQ | CONFIG_IOSCHED_CFQ | iosched_cfq |
NOOP |
CONFIG_IOSCHED_NOOP | elevator_noop |
2. RequestQueue
デバイスドライバは、初期化時にblk_init_queue()によってブロックI/O要求を受け付けるRequestQueue作成する。スケジューリングはRequestQueue毎に行われる。3. Elevator
I/Oスケジューラの実体。I/Oスケジューラ種別に非依存な部分を実装しており(ファイルシステムでいうVFS的なもの)、ここから、各スケジューラの処理が呼び出される。RequestQueueにはElevatorが関連づけられる。ブロックI/OのRequestは一旦Elevatorに入れられて、スケジューリングされた後、Dispatchされる。DispatchされたRequestはRequestQueueに入れられてデバイスドライバがI/Oを実行していく(図1)。
図1 Requestの流れ
request_fn - ドライバのI/O Request処理ルーチン
blk_init_queue()でRequestQueueを作成する時に指定する。
このルーチンはelv_next_request()でElevatorのRequestをDispatchしてRequestQueueに入れてI/Oを実行していく。
Unplug時、I/O完了時に呼ばれる。
他にもスケジューラ個別のタイミングで呼ばれることがある(Anticipatoryスケジューラの場合はAnticipation終了時に呼び出される)。
このルーチンはelv_next_request()でElevatorのRequestをDispatchしてRequestQueueに入れてI/Oを実行していく。
Unplug時、I/O完了時に呼ばれる。
他にもスケジューラ個別のタイミングで呼ばれることがある(Anticipatoryスケジューラの場合はAnticipation終了時に呼び出される)。
4. Elevatorとのインタフェース
Elevator(I/Oスケジューラ)へのアクセスルーチンelv_merge(q,req,bio)
bioを既存のRequestにMergeできるかチェックする。Merge可能ならMerge先のRequestをreqに返す。
elv_latter_request(q,rq)
Elevator内のrqの次のRequestを取得
elv_next_request(q)
RequestQueue(q->queue_head)からRequestを取得する。空だったなら、.elevator_dispatch_fn()を呼び出し、Elevator内のRequestをDispatchしてからそれを返す。どのRequestがDispatchされるかはI/Oスケジューラ次第。デバイスドライバが実行するRequestを取得するのに使う。また、Unplug時にRequestを取得するのにも使う。
elv_add_request(q, req, where, plug)
RequestをElevatorに追加
elv_completed_request()
I/O完了時にコールされる (実際は__blk_put_request()からのみコール)
elv_insert(q,rq,where)
RequestQueueのwhereで指定した位置にRequestを入れる。
elv_add_request()の内部ルーチン。
elv_add_request()の内部ルーチン。
elv_dispatch_sort(q,rq)
RequestをDispatchしてRequestQueue(q->queue_head)に入れる。