0
0

flashcache改造

DongHao 发表于 2012年10月23日 15:08 | Hits: 3336
Tag: 操作系统 | devicemapper | flashcache
flashcache是bio based,也就是说,做为虚拟设备它是直接处理上层发下来的bio们。具体点说,内核所有的block io操作都要走submit_bio,而submit_bio会走generic_make_request,进而调用每个设备自己的make_request_fn函数(代码里是q->make_request_fn),而dm框架对虚拟出来的设备是实现了make_request_fn的,名为dm_request,这样,所有的bio都进了函数dm_request。那dm_request又干了些什么呢?对于bio based的设备,dm_request会把bio克隆出来一份,这个clone出来的bio跟原bio是共享page的(bio和io_vec是独立的,如图,灰色部分为clone出来的部分),

bio clone
然后把clone的bio传给虚拟设备的map回调函数,而flashcache是实现了这个map函数的,名为flashcache_map。这样,flashcache就靠这一个函数处理所有的bio。

但是,我们在使用flashcache中有了新的需求:要求给不同的进程以不同的io带宽。这就需要用到blkio-controller,但是blkio-controller又需要选择io调度器为cfq,而flashcache是个bio based的设备,也就是说,它不合并bio为request,也就没io调度器什么事儿(io调度器是针对request进行排序和处理的),自然也就无法支持blkio-controller(使用block io-throttle似乎也可以控制io带宽,但是缺乏弹性)。

为了让flashcache支持blkio-controller,我们必须把它改造为request based。改动如下:

首先,dm框架提供了给开发者一个struct target_type结构

struct target_type {                                                               
        /*                                                                         
         * 3rd party driver must initialize 'features' to zero or                  
         * set to any of the Target features listed below.                         
         */                                                                        
        uint64_t features;                                                         
        const char *name;                                                          
        struct module *module;                                                     
        unsigned version[3];                                                       
        dm_ctr_fn ctr;                                                             
        dm_dtr_fn dtr;                                                             
        dm_map_fn map;                                                             
        dm_map_request_fn map_rq;                                               
......
}

如果开发者实现了其中的map方法,那么这个虚拟设备就是bio based;如果开发者实现了map_rq方法,那么这个虚拟设备就是request based(当开发者实现map_rq后,dm框架会帮新设备创建queue等一系列request型设备所需的数据结构)。我们要改造flashcache,那么就得把原先实现map方法的flashcache_map函数改成实现map_rq。
糟糕的是,dm框架对request based设备的支持不够,所以我们还在struct target_type里加了一个mk_rq方法,让虚拟设备可以自己实现“从bio合并为request”的函数。

其次,原先flashcache_map里是靠dm_io函数(dm框架提供的通用函数)把bio直接发到底层设备的,

flashcache_map
  --> flashcache_read
    --> flashcache_read_miss
      --> dm_io_async_bvec(flashcache里的bio大部分都要走这个函数)
        --> dm_io

现在不能这样了,我们修改了dm_io函数,让其可以选择不发bio而是把bio串在一个链表上返回出来。

现在逻辑清晰了。一开始,从上层来的bio都要走target_type里的mk_rq方法——我们通过flashcache_mk_rq实现,在flashcache_mk_rq里面,原先通过dm_io_async_bvec直接发送bio到底层设备现在改为把bio放入虚拟设备的queue里(这里是通过__make_request把bio往queue里放的,所以会同时放入queue和io调度器里,而且真正进入queue的是合并后的request而不再是散装的bio),之后block会根据情况(定时器超时或queue满)把虚拟设备queue里的request取走,做map_rq,然后放入对应的底层设备。

flashcache
改造后的flashcache流程

皓庭同学问了个很好的问题:调用__make_request时,flashcache虚拟设备的请求队列(queue)里面混合了对cache设备和disk设备的请求,来自于不同设备的请求会被io调度器合并吗?
答:不会的,elv_rq_merge_ok里面有专门的判断:
        /*      
         * must be same device and not a special request                           
         */                                                                        
        if (rq->rq_disk != bio->bi_bdev->bd_disk || rq->special)                   
                return 0;
所以把不同设备来的bio放入一个queue是能正常工作的。在做flashcache_map_rq时,我们才把request指向对应的底层设备。

最后,感谢皓庭同学对新版flashcache测试的支持!

原文链接: http://donghao.org/2012/10/flashcacheaoi.html

0     0

我要给这篇文章打分:

可以不填写评论, 而只是打分. 如果发表评论, 你可以给的分值是-5到+5, 否则, 你只能评-1, +1两种分数. 你的评论可能需要审核.

评价列表(0)