Linuxのブロック層について調べた。bioをrequest_queueにくっつけて、ブロックドライバがキューを処理する部分を見た。
カーネルバージョン
v4.4.0
bio構造体に書いてあること
submit_bio()
に入った時点でのbioはこんな感じ。ログか何かを書こうとしているところ。
まだリクエストキューに繋がっていないので、bi_next
は空だったり使っていない部分もある。
bi_iter
のbi_sector
とbi_size
は、それぞれ対象とするブロックデバイスのセクタ番号と、そこからのサイズ。
bi_rw
がこのIOの読み書きの種別を表していて、何もセットされていない場合はReadで、それ以外はWriteになる。このフラグはsubmit_bio()
の中でセットされるため、この時点では必ず0になっている。
>>> p/x *bio
$6 = {
bi_next = 0x0,
bi_bdev = 0xffff8802334d09c0,
bi_flags = 0x50002100,
bi_error = 0x0,
bi_rw = 0x0,
bi_iter = {
bi_sector = 0x930170,
bi_size = 0x1000,
bi_idx = 0x0,
bi_bvec_done = 0x0
},
bi_phys_segments = 0x0,
bi_seg_front_size = 0x0,
bi_seg_back_size = 0x0,
__bi_remaining = {
counter = 0x1
},
bi_end_io = 0xffffffff8127e2d0,
bi_private = 0xffff8802335f2240,
bi_ioc = 0x0,
bi_css = 0x0,
{
bi_integrity = 0x0
},
bi_vcnt = 0x1,
bi_max_vecs = 0x100,
__bi_cnt = {
counter = 0x2
},
bi_io_vec = 0xffff88023579b000,
bi_pool = 0xffff880236377980,
bi_inline_vecs = 0xffff8800bb82d188
}
bi_io_vec
がIO要求に対応するメモリ上の領域になっている。
>>> p/x *bio->bi_io_vec
$13 = {
bv_page = 0xffffea0008c5c840,
bv_len = 0x1000,
bv_offset = 0x0
}
blk_queue_bio()は何をするか
概要しか見れなかった。
-
elv_merge()
で既存のリクエストとマージできるかをチェックして、マージをする。マージできたら抜ける。ここでrequest_queueに紐付いたelevatorを呼んでいる。 -
get_request()
で新しいリクエストを初期化、そこにbioを詰める。 -
__blk_run_queue()
でブロックデバイスにキューの処理を依頼する。