virtio-blk原理:
1.处理数据请求有两条路径
1).request路径:virtblk_request
virtio_blk结构体中的gendisk结构的request_queue队列接收block层的bio请求,按照request_queue队列默认处理过程,bio请求会在io调度层转化为request,然后进入request_queue队列,最后调用virtblk_request将request转化为vbr结构。
2).bio路径:virtblk_make_request
不按照默认路径走,将bio直接转化为vbr结构。
2.通过request队列(virtio-blk初始化时向virtio_ring申请到的)将vdr发送给qemu-kvm处理。
3.qemu-kvm处理过vdr后会将它加入到virtio_ring的request队列,并发一个中断给队列,队列的中断响应函数vring_interrupt调用队列的回调函数virtblk_done。
4.virtblk_done判断是bio处理方式则调用virtblk_bio_done,否则调用virtblk_request_done
virtio-blk层进入点有两个:
1.request方式:virtblk_request
2.bio方式:virtblk_make_request
bio方式的优势在于跳过了io调度层(主要工作是合并多个bio到request),实现了性能的提高,但是对于低速设备,性能却有下降。
virtio-blk层返回点只有一个,那就是队列的回调函数virtblk_done
1.bio结构体的作用就是指明要读或写块设备的哪些地址及长度,所以它最主要的
成员就是bio_vec数组,一个bio_vec对应一个地址和长度(即,一块区域),
bio_vec数组的作用就是读或写指明的多个块设备区域。
2.bio被传递到io调度层时,就会被转换成request结构体,一个request可能包含
多个读取地址区域相邻的bio从而提高读写性能。
3.块设备所包含的gendisk结构中包含一个request_queue,这个队列就是用来接
收io调度层发送过来的request。
4.gendisk结构的request_queue队列包含各种回调函数来处理整个request的生命
流程:
queue的各种回调函数:
/* request process function - 处理request函数 */
request_fn_proc *request_fn;
/* make request function - 将bio转化为request函数 */
make_request_fn *make_request_fn;
/* prepare request function - 创建request时执行的函数 */
prep_rq_fn *prep_rq_fn;
/* unprepared request function - */
unprep_rq_fn *unprep_rq_fn;
/* merge bio_vec function - 合并bio到一个request */
merge_bvec_fn *merge_bvec_fn;
/* 软中断处理函数,request处理完成时的回调函数 */
softirq_done_fn *softirq_done_fn;
/* 超时处理函数 */
rq_timed_out_fn *rq_timed_out_fn;
dma_drain_needed_fn *dma_drain_needed;
lld_busy_fn *lld_busy_fn;
进入block层的接口:generic_make_request
/**
* generic_make_request - hand a buffer to its device driver for I/O
*