该接口作为通用的块设备处理bio请求的方式,主要思路是尽可能的合并bio到请求request中,如果可能进一步将连续的request合并;如果不能合并bio,则新建请求,初始化后,plug
互斥方式:加锁,请求队列的锁
涉及到不同的调度算法:将新建的请求添加到调度器的调度队列,由unplug触发调度器,进而将请求按照特定的调度算法将请求派发到请求队列的派发队列。
/*块设备排入bio请求*/
int blk_queue_bio(struct request_queue *q, struct bio *bio)
{
struct request *req;
int el_ret;
unsigned int bytes = bio->bi_size;
const unsigned short prio = bio_prio(bio);
const bool sync = bio_rw_flagged(bio, BIO_RW_SYNCIO);
const bool unplug = bio_rw_flagged(bio, BIO_RW_UNPLUG);
const unsigned int ff = bio->bi_rw & REQ_FAILFAST_MASK;
int where = ELEVATOR_INSERT_SORT;
int rw_flags;
/* BIO_RW_BARRIER is deprecated */
if (WARN_ONCE(bio_rw_flagged(bio, BIO_RW_BARRIER),
"block: BARRIER is deprecated, use FLUSH/FUA instead\n")) {
bio_endio(bio, -EOPNOTSUPP);
return 0;
}
/*
* low level driver can indicate that it wants pages above a
* certain limit bounced to low memory (ie for highmem, or even
* ISA dma in theory)
*/
blk_queue_bounce(q, &bio);
if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
bio_endio(bio, -EIO);
return 0;
}
spin_lock_irq(q->queue_lock);
if (bio->bi_rw & (BIO_FLUSH | BIO_FUA)) { //FLUSH的bio,直接申请新的request
where = ELEVATOR_INSERT_FLUSH;
goto get_rq;
}
if (elv_queue_empty(q)) //调度器队列为空,则无法合并bio请求,申请新的request
goto get_rq;
el_ret = elv_merge(q, &req, bio); //调度器尝试合并bio到req请求
switch (el_ret) {
case ELEVATOR_BACK_MERGE: //1、向后合并bio到req请求
BUG_ON(!rq_mergeable(req));
if (!ll_back_merge_fn(q, req, bio)) //1)查看是否超过请求request的最大字节,或是request的最大段数
break;
trace_block_bio_backmerge(q, bio);
if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff)
blk_rq_set_mixed_merge(req);
req->biotail->bi_next = bio; //2)将bio添加到req请求的尾部
req->biotail = bio;
req->__data_len += bytes;
req->ioprio = ioprio_best(req->ioprio, prio);
if (!blk_rq_cpu_valid(req))
req->cpu = bio->bi_comp_cpu;
drive_stat_acct(req, 0);
elv_bio_merged(q, req, bio); //调度器合并bio到req请求
if (!attempt_back_merge(q, req)) //3)继续尝试将请求req和其后面的请求合并,可以合并返回1,无法合并返回0
elv_merged_request(q, req, el_ret); //无法合并请求后的处理
goto out;
case ELEVATOR_FRONT_MERGE: //2、向前合并bio到req请求
BUG_ON(!rq_mergeable(req));
if (!ll_front_merge_fn(q, req, bio)) //1)查看是否超过请求request的最大字节,或request的最大段数
break;
trace_block_bio_frontmerge(q, bio);
if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff) {
blk_rq_set_mixed_merge(req);
req->cmd_flags &= ~REQ_FAILFAST_MASK;
req->cmd_flags |= ff;
}
bio->bi_next = req->bio; //2)将bio请求添加到req请求的头部
req->bio = bio;
/*
* may not be valid. if the low level driver said
* it didn't need a bounce buffer then it better
* not touch req->buffer ei