blk_queue_bio函数学习
//块设备排入bio请求函数
//该接口作为通用的块设备处理bio请求的方式,主要思路是尽可能的将bio合并request中或者生成新的request。
static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
{
//(1)首先尝试在plug链表中寻找能够与该bio合并的request,
//如果能够合并则合并后返回;
//如果不能合并入plug队列则继续去调度队列中寻找合并机会
if (!blk_queue_nomerges(q)) {
if (blk_attempt_plug_merge(q, bio, &request_count, NULL))
return BLK_QC_T_NONE;
} else
request_count = blk_plug_queued_count(q);
spin_lock_irq(q->queue_lock);
//(2)第二步尝试将bio合并到调度队列的request中去
switch (elv_merge(q, &req, bio)) {//寻找能够合并的request并返回合并类型是向前合并还是向后合并
case ELEVATOR_BACK_MERGE://向后合并
if (!bio_attempt_back_merge(q, req, bio))
break;
elv_bio_merged(q, req, bio);
free = attempt_back_merge(q, req);
if (free)
__blk_put_request(q, free);
else
elv_merged_request(q, req, ELEVATOR_BACK_MERGE);
goto out_unlock;
case ELEVATOR_FRONT_MERGE://向前合并
if (!bio_attempt_front_merge(q, req, bio))
break;
elv_bio_merged(q, req, bio);
free = attempt_front_merge(q, req);
if (free)
__blk_put_request(q, free);
else
elv_merged_request(q, req, ELEVATOR_FRONT_MERGE);
goto out_unlock;
default:
break;
}
//(3)如果bio在上面两种合并过程中均未找到能够合并的request,那么只能新申请一个空的request并将其初始化,将bio放在新申请的request中随后放入plug队列;
....
//此处省略了申请新的request代码
plug = current->plug;
//判断是否启动了蓄流机制,如果启用则将新建立的request加入到plug list中;
if (plug) {
/*
* If this is the first request added after a plug, fire
* of a plug trace.
*
* @request_count may become stale because of schedule
* out, so check plug list again.
*/
if (!request_count || list_empty(&plug->list))
trace_block_plug(q);
else {
struct request *last = list_entry_rq(plug->list.prev);
if (request_count >= BLK_MAX_REQUEST_COUNT ||
blk_rq_bytes(last) >= BLK_PLUG_FLUSH_SIZE) {
//判断plug lsit中的request数量是否满了,满了的话就启动泄流;
blk_flush_plug_list(plug, false);
trace_block_plug(q);
}
}
list_add_tail(&req->queuelist, &plug->list);
blk_account_io_start(req, true);
} else {
//如果没有开启plug机制,则将request直接加入到调度队列
spin_lock_irq(q->queue_lock);
add_acct_request(q, req, where);//默认where=ELEVATOR_INSERT_SORT
__blk_run_queue(q);//最差的一种情况,无法合并,也没有开启plug,那么加入到调度器后,有一次通知驱动执行request_fn函数从派发队列中拿取一个request进行处理