タダノキロク

日々の考えたことの記録 主に無駄なこと

詳細Linuxカーネル 14章 ブロック型デバイスドライバ 3/12

詳細Linuxカーネル 14章 ブロック型デバイスドライバ 3/12

@詳解Linuxカーネル読書会

ブロックデバイスへのI/Oドライバは、 平均アクセス時間が非常に長いことを前提に作られている。
(大体msオーダー/CPUメモリはnsオーダー)

この特徴が入っているソースの部分を読んで行こうと思う。

ブロック型デバイスの管理

とりあえず全体のアーキテクチャ。(14.1章を参照)

LinuxでのブロックデバイスへのReadアクセスは以下のレイアを踏む(図14−1)

  1. VFS
    情報(ファイルディスクリプタとファイルの位置)からRAM上に
  2. マッピングレイヤ
    ファイルデータの物理的な位置を特定
  3. 汎用ブロック層
    読み込み操作発行(ブロックI/O)する。デバイス毎の特性は隠蔽
  4. I/Oスケジューラ層
    I/Oデータの転送要求の並べ替えを行う。
  5. ブロック型デバイスドライバ
    ハードのディスクコントローラにて適切なコマンドを転送し、データ転送。

この後、データサイズに関して書いてある。 * セクタ(ブロックデバイスの物理サイズ)
* ブロック(ファイル・システムが管理する最小単位)
* セグメント(アクセスを連続で行うために物理的な隣接ブロックのまとまり)
* ページ(RAM上にキャッシュするサイズ)

ブロックデバイスを性能を気にしていそうなのは、I/Oスケジューラ層な感じ。 14.3章I/Oスケジューラを読むことにする。

I/Oスケジューラ

14.3参照

ブロックデバイスへのアクセスを可能限り複数のセクタをまとめて取り扱う。 その結果、ドライブデバイスのヘッド移動回数を減らす。 セクタ単位のI/O処理はブロック型デバイス要求を生成で実施。 カーネルは要求をI/O操作のスケジュールに追加して処理は遅延させる。 そしてスケジュールを連続するセクタへのアクセスに並び替えを行う。

!!この辺は当たり前かな・・・

具体的な実現方法は、汎用ブロック層がI/Oスケジューラを呼び出し、 新しいブロック型要求を新たに生成するか、 すでにある要求を拡張して(連続していたら要求をひっくるめる)新たには要求を生成しない。
要求は物理ブロックデバイス毎に1つの要求キューを持っていいて、
* 要求キューディスクリプタ(14.3.1章)
* 要求ディスクリプタ(14.3.2章)
で管理する。
ディスクリプタ(bio構造体から構成)がそれぞれの要求を示す。 I/Oスケジューラが要求に対して既存のbioに追加 or 別のbio構造体と結合して、 要求を拡張する。 要求キューはそれらのデイスクリプタの並べかえを行うために使う。

I/Oスケジューリングアルゴリズム(14.3.4章)

新しい要求をキューに追加するときは、 I/Oスケジューラが幾つかのアルゴリズムに基づき追加する。

基本的には"エレベータ"で実施。セクタ番号順に並び替えるようにする。 Linux2.6では単なるエレベータではなく、4種類がアルゴリズムとして提供
* 予測(Anticipatory)
* 期限付き(Deadline)
* 完全公平型(Complete Fairness Queueing)
* 無処理(No Operation)

Linux2.6では予測エレベータが最も洗練されていると行ってたが、 wikiを見ると完全公平型(CFQ)がデフォルト見たい。 ただ、ブロックデバイスにHDDよりSSDが採用されている2016年、 これらのアルゴリズムは邪魔なのかもしれない。

このアルゴリズムの詳細を追うのもいいが、 一旦要求を拡張するところ当たりを見てみたい。

I/Oスケジューラに対する要求の発行(14.3.5章)

I/Oスケジューラへの要求は関数__make_queueで実装。
引数は
* 要求キュー(request_queue)ディスクリプタq
* bioディスクリプタbio
現在のカーネルだとraid10.cにしか__make_queueが定義されてない。 多分違う関数になっているのでは?->そうみたい。

qのメンバで関数ポインタmake_request_fnに入れられているのは、
* blk_mq_make_request
* blk_sq_make_request
* blk_queue_bio
* brd_make_request
* drbd_make_request
* pkt_make_request
* cached_dev_make_request
* flash_dev_make_request
* dm_make_request
* pmem_make_request
他いろいろある。ブロックデバイス向けはblk_mq_make_requestかな。
探し方はデバイスドライバの初期化で、blk_queue_make_requestに格納されている関数ポインタかな。

もし続けるならblk_mq_make_requestからかな。 =>ちがうらしい。blk_queue_bioが実体らしい。 以上ここまで。