真实的I/O调度层处理

本文详细探讨了Linux内核中的I/O调度层处理,从generic_make_request函数出发,讲解了如何提交请求并进入调度层。重点分析了__make_request函数,包括bio的处理、回弹缓冲区、I/O调度程序的合并策略以及请求插入到队列的过程。最后,提到了请求队列的unplug机制和请求处理的时机。
摘要由CSDN通过智能技术生成

1.5.6 真实的I/O调度层处理

现在我们块设备也有了,队列也有了,要提交请求也就可以开始提交了。那就让我们回到generic_make_request来研究一下如何提交请求如何处理请求吧。我们看到,函数最后调用q->make_request_fn(q, bio)。对 make_request_fn 函数的调用可以认为是 IO调度层的入口,该函数用于向请求队列中添加请求。该函数是在创建请求队列时指定的,代码如下(blk_init_queue 函数中):

q->request_fn = rfn;

blk_queue_make_request(q, __make_request);

 

前面看到函数 blk_queue_make_request 将函数 __make_request 的地址赋予了请求队列 q make_request_fn 成员:

 

void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)

{

       q->nr_requests = BLKDEV_MAX_RQ;

       q->make_request_fn = mfn;

……

 

那么,__make_request函数才是IO调度层的真实入口,来自block/ll_rw_blk.c

 

2846static int __make_request(request_queue_t *q, struct bio *bio)

2847{

2848        struct request *req;

2849        int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;

2850        unsigned short prio;

2851        sector_t sector;

2852

2853        sector = bio->bi_sector;

2854        nr_sectors = bio_sectors(bio);

2855        cur_nr_sectors = bio_cur_sectors(bio);

2856        prio = bio_prio(bio);

2857

2858        rw = bio_data_dir(bio);

2859        sync = bio_sync(bio);

2860

2861        /*

2862         * low level driver can indicate that it wants pages above a

2863         * certain limit bounced to low memory (ie for highmem, or even

2864         * ISA dma in theory)

2865         */

2866        blk_queue_bounce(q, &bio);

2867

2868        spin_lock_prefetch(q->queue_lock);

2869

2870        barrier = bio_barrier(bio);

2871        if (unlikely(barrier) && (q->next_ordered == QUEUE_ORDERED_NONE)) {

2872                err = -EOPNOTSUPP;

2873                goto end_io;

2874        }

2875

2876        spin_lock_irq(q->queue_lock);

2877

2878        if (unlikely(barrier) || elv_queue_empty(q))

2879                goto get_rq;

2880

2881        el_ret = elv_merge(q, &req, bio);

2882        switch (el_ret) {

2883                case ELEVATOR_BACK_MERGE:

2884                        BUG_ON(!rq_mergeable(req));

2885

2886                        if (!q->back_merge_fn(q, req, bio))

2887                                break;

2888

2889                        blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);

2890

2891                        req->biotail->bi_next = bio;

2892                        req->biotail = bio;

2893                        req->nr_sectors = req->hard_nr_sectors += nr_sectors;

2894                        req->ioprio = ioprio_best(req->ioprio, prio);

2895                        drive_stat_acct(req, nr_sectors, 0);

2896                        if (!attempt_back_merge(q, req))

2897                                elv_merged_request(q, req);

2898                        goto out;

2899

2900                case ELEVATOR_FRONT_MERGE:

2901                        BUG_ON(!rq_mergeable(req));

2902

2903                        if (!q->front_merge_fn(q, req, bio))

2904                                break;

2905

2906                        blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);

2907

2908                        bio->bi_next = req->bio;

2909                        req->bio = bio;

2910

2911                        /*

2912                         * may not be valid. if the low level driver said

2913                         * it didn't need a bounce buffer then it better

2914                         * not touch req->buffer either...

2915                         */

2916                        req->buffer = bio_data(bio);

2917                        req->current_nr_sectors = cur_nr_sectors;

2918                        req->hard_cur_sectors = cur_nr_sectors;

2919                        req->sector = req->hard_sector = sector;

2920                        req->nr_sectors = req->hard_nr_sectors += nr_sectors;

2921                        req->ioprio = ioprio_best(req->ioprio, prio);

2922                        drive_stat_acct(req, nr_sectors, 0);

2923                        if (!attempt_front_merge(q, req))

2924                                elv_merged_request(q, req);

2925                        goto out;

2926</

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值