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测试的支持!


相关文章

分类

9 Comments

ryan said:

robin你好,

关注你的网站一段时间了,对文件系统比较有兴趣,之前接触过FAT,NTFS,对EXT2/3也有一定了解,但是没有在实际工作中大量的接触和使用,想请问一下,有什么ext相关的资料可以推荐阅读的吗? 谢谢.
个人的背景:
6年半的驱动开发背景,接触linux/android大概3年的时间,通读了LDD,LKD,ULK几本书,个人觉得基础还算可以,之前做过NAND FLASH,MMC/SD之类的存储介质的驱动.

DongHao Author Profile Page said:

@ryan,呵呵,ext系列在网上的资料就那些,如果要深入了解,就只剩阅读代码这一个办法了,我也是2011年初才开始看ext4代码,应该还算好理解的。您做驱动这么多年,对内核了解应该不浅的,读代码肯定没问题 :)

我正好还要请教一下,做NAND FLASH驱动有什么相关资料吗?

ryan said:

感谢回复.
我现在的困扰是自己有兴趣往文件系统这些方面发展,但是实际工作中却不怎么用到.苏州这边我这边目前还不知道有什么公司从事这方面的开发的,不知道你有相关的信息不?呵呵.
NAND FLASH我之前是做两个案子的时候接触过,请教不敢当,我自己的理解也不够深入,如果只是驱动部分的话主要也就是看datasheet,如果是一些偏文件系统层或者FTL层的话,我的接触也很少.目前的公司有controller相关的资料,不过目前还只看了一小点,回头要是有什么心得的话再交流,谢谢.
PS.你们公司的不少人的blog都挺不错的.

ryan said:

晕,上午的comment没了.

请教robin兄,我有个同学遇到ext4的问题.
某个mmc的分区是mount成ro的,用户开机状态下把手机的电池拔了下来,过段时间发现ext4的这个分区认不到了,dump出第一个superblock发现,很多都是0(包括magicnumber).
用exfsck 1.41.11去强制检查,发现很多error.
superblock里,s_last_error_ino这个是0x14b,s_last_error_func32是ext4_lookup,错在EXT4_ERROR_INODE(dir, "deleted inode referenced: %u", ino);
看起来是某个文件被删除了,但问题是,这个分区是ro mount的啊.

另外请教个问题,有办法根据ino,直接得到相关文件的信息吗? 比如文件名,大小,存储的位置是在那些block里面等等.

谢谢.

DongHao Author Profile Page said:

@ryan,你的困扰何尝不是我的困扰,我何尝对文件系统没有兴趣,但是我们在互联网公司推新文件系统推得非常吃力:我说ext4文件结构好读写性能高,用户说那10%的性能提升他随便改改应用就可以做到;我说bigalloc能节省空间,用户说硬盘便宜不在乎省那点空间而且很多应用是直接读写裸盘更省空间;我说btrfs有快照功能,用户说集群里随便一个文件都有三个备份要什么快照。所以,互联网公司的开发和运维都太牛逼了,牛逼到了什么都不需要的伟大境界了。所以我现在也没再做ext4开发和推销类的工作了,太他妈累,又没收成。
我个人觉得在消费数码产品上推文件系统才是正确的,毕竟普通用户不会蛋疼到自己去读写裸盘。你如果以后做手机或数码产品的相关工作,学学文件系统挺好。Oracle和Redhat都在招文件系统开发测试相关的职位,好像两家公司都可以work from home,如果你确实有兴趣,咱们可以邮件聊。

DongHao Author Profile Page said:

@ryan,ext4的ro mount应该是可靠的,我怀疑是mmc自己在电池插拔的过程中出了问题掉了数据,当然,纯属瞎猜。只是觉得不像是ext4本身的问题。
根据ino得到文件信息有两个办法:一个是 find 命令带上 -inum 参数;一个是用debuge2fs 再加stat 命令

ryan said:

@robin,谢谢你的建议.我也比较怀疑是否是对裸盘操作或者其他原因导致的.
我之前就是做手机的,但是基于android的平台去做后,公司根本就不投人力去看文件系统的东西,老板们觉得这东西就用kernel本身的挺好,投人去看没什么产出,哎,无奈.
你的邮箱是网页上那个robin.dong@gmail.com那个吗?

ryan said:

是robin.k.dong@gmail.com

DongHao Author Profile Page said:

@ryan,是的,robin.k.dong (at) gmail.com

留言:

关于文章

This page contains a single entry by DongHao published on 10 23, 2012 3:02 PM.

flashcache原理 was the previous entry in this blog.

SSD Internal is the next entry in this blog.

Find recent content on the main index or look in the 存档 to find all content.