Linuxカーネルの汎用ブロック層について調べてみた

概要

kernel-4.4.0の汎用ブロック層について、ソースコードをベースに調べてみる。参考書として、詳解 Linuxカーネル 第3版を使用する。

汎用ブロック層とは

汎用ブロック層は、システムに接続されたブロック型デバイスに対して出されたすべての要求を 処理するカーネル要素です。

詳解 Linuxカーネル 第3版より引用

bio構造体

汎用ブロック層の処理の中心となるデータ構造がbio構造体である。kernel4.4.0では、include/linux/blk_types.hで定義され以下のようになっている。

gendisk構造体

ディスクの情報を保持しているのがinclude/linux/genhd.hで定義されているgendisk構造体である。ディスクがパーティションに分割されている場合、part0メンバにhd_struct構造体へのアドレスが保持されている。

同じくinclude/linux/genhd.hで定義されているhd_struct構造体。パーティションの情報を保持する。

I/O要求の発行

ディスクの追加処理

システム起動時などに新しくディスクが追加されるときは、alloc_disk関数 -> add_disk関数の順に関数が呼ばれる。alloc_disk関数で新しくgendiskを生成し、add_disk関数でbio構造体にgendisk構造体を挿入する。

bio構造体の初期化

bio_alloc_bioset関数で行われる。引数のbsがNULLだったら、kmalloc関数でbioが割り当てられる。それ以外の場合はbsのメモリプールから割り当てられる。

generic_make_request関数

汎用ブロック層のエントリーポイントとなる関数でデバイスドライバにI/Oバッファーを渡すために使用する。行いたいI/Oは引数のbioに格納されてドライバに渡される。I/O完了通知はgeneric_make_request返らず、bio->bio_end_io関数により非同期に返される。

make_requeset_fnは一度に1つだけしか処理できない(なぜ?)。そのため、current->bio_listをチェックして、処理中の人がいれば自分もbio_listキューにbioを繋いで処理を終了する。

bdev_get_queue(bio->bi_bdev)により要求キューqをデバイスから取り出す。
blk_queue_enter(q, __GFP_DIRECT_RECLAIM)ですでに要求が処理済みかチェックしていると思われる。処理済みでなければ、q->make_request_fn関数を実行して、要求を処理する。その後、blk_queue_exit関数で後始末をする。そしてbio_listから次の要求をpopしてwhileループの先頭に戻る。

make_request_fn

上記で登場したrequest_queue構造体のmake_request_fnメンバが要求を処理する関数ポインタである。このメンバはblk_queue_make_request関数でセットされる。blk_queue_make_requestは以下のように呼び出されるようである。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です