向通用块层提交一个bio请求

来源:互联网 发布:python canny边缘检测 编辑:程序博客网 时间:2024/06/06 07:21

向通用块层提交一个bio请求

当上层构建后io操作对应的bio请求后,通过submit_bio函数向通用块层提交一个 bio请求。

void submit_bio(int rw, struct bio *bio){    bio->bi_rw |= rw;//io操作是读操作还是写操作    ...    generic_make_request(bio);//通用块层的主要入口点}void generic_make_request(struct bio *bio){    struct bio_list bio_list_on_stack;    /*对bio进行检查,查看bio的各种参数是否合理,如bio->bi_sector没有超过块设备的扇区数*/    if (!generic_make_request_checks(bio))        return;    /*在一个进程内,同一时刻内核希望只有一个bio正在被处理,内核使用current->bio_list    来维护当前进程提交的bio请求,如果链表不为空,则说明前面有bio正在被处理,只需要将新    bio挂入链表即可返回(令我疑惑的是并未见加锁操作,是怎么避免竞态的呢?)*/    if (current->bio_list) {        bio_list_add(current->bio_list, bio);        return;    }    //能走到这说明前面没有bio请求等待处理    BUG_ON(bio->bi_next);    bio_list_init(&bio_list_on_stack);//初始化链表,表头就是函数开头定义的那个局部变量    //将表头赋给current->bio_list,后面来的bio都将挂在这个链表上    current->bio_list = &bio_list_on_stack;                       do {        //获取bio要发送的设备对应的请求队列        struct request_queue *q = bdev_get_queue(bio->bi_bdev);         //将请求插入队列,所谓的io调度都是在该函数完成        q->make_request_fn(q, bio);        bio = bio_list_pop(current->bio_list);//从链表移除    } while (bio);    current->bio_list = NULL; /* deactivate */    //该bio链表已经处理完了,下次再进入这个函数将创建新的链表}

最终,调用q->make_request_fn方法进入块设备的I/O调度层,将bio请求插入请求队列q中。
大家一定很好奇q->make_request_fn函数到底是哪个函数

void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn){    ...    q->make_request_fn = mfn;    ...}struct request_queue * blk_init_allocated_queue(struct  request_queue *q, request_fn_proc *rfn, spinlock_t *lock){    q->request_fn       = rfn;  //请求处理函数,负责处理请求队列中的每一个请求     q->prep_rq_fn       = NULL;    ...    blk_queue_make_request(q, blk_queue_bio);  //设置q->make_request_fn    ...    if (elevator_init(q, NULL)) {        mutex_unlock(&q->sysfs_lock);        return NULL;    }//初始化调度算法    ...}

由上可知一般默认的q->make_request_fn就是blk_queue_bio函数。如果被访问的设备是一个有queue的块设备,那么系统会调用blk_queue_bio函数进行bio的调度合并。我们将在io调度层具体分析该函数。

原创粉丝点击