generic_make_request函数初探

generic_make_request()函数会接手一个已经基本初始化好的bio,并使用make_request_fn将请求置于驱动程序的请求队列上。即把该bio传给设备对应的驱动程序。参数bio中bi_dev和bi_sector都已经设定为要进行IO的对应的设备的具体地址。其中在make_request_fn(每个设备会对应一个请求队列(request_queue),该请求队列上会有对应的make_request_fn指针)函数调用后就不应该再对bio有所改动。
但是make_request可能会递归调用generic_make_request,但是对于内核态来说,栈空间是有限的。所以为了保证递归深度不能超过1,这块做了个聪明的处理。
首先看下面这段代码:

1808         if (current->bio_list) {
1809                 bio_list_add(current->bio_list, bio);
1810                 return;
1811         }

其中current->bio_list是记录了由make_request_fn提交的request组成的链表,一般情况下,如果是第一次调用generic_make_request,该current->bio_list为空的。所以这个if语句并不会执行。
接下来往下看

1827         BUG_ON(bio->bi_next);   //调用者保证bio->bi_next为NULL
1828         bio_list_init(&bio_list_on_stack);
1829         current->bio_list = &bio_list_on_stack;
1830         do {   //获取设备的请求队列
1831                 struct request_queue *q = bdev_get_queue(bio->bi_bdev);
1832                
1833                 q->make_request_fn(q, bio);
1834 
1835                 bio = bio_list_pop(current->bio_list);
1836         } while (bio);

上面说了current->bio_list为空,所以初始化一个链表用来存后来make_request_fn提交的request。接下来获取设备的请求队列(request_queue),然后本次提交的bio可以通过make_request_fn添加到请求队列上,但是在make_request_fn函数中可能会发生递归调用generic_make_request(比如软RAID的实现,把请求拆分到其他设备上)。为了防止这种递归调用层次太深,但是逻辑上又要递归调用,就需要使用到current->bio_list,比如说现在make_request_fn已经调用了generic_make_request,那么就会进入上面提到的if块中,此时只是把该bio加入到bio_list之后就返回没有再做处理了。z

这时候会回到循环中make_request_fn的下一句代码(假设整个过程只调用了一次generic_make_request),可以看见该语句又会从bio_list拿出刚刚添加的bio进行处理。这是不是就把递归问题巧妙地转变成了循环同时又保证了调用递归的方便性?

不过我看深入linux内核架构第六章关于generic_make_request函数的介绍是看了一下午没看懂(2.6的内核貌似),感觉linux内核版本的更新,代码的可读性也提高了啊。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值