src/flashcache_main.c,
主入口,
EXPORT_SYMBOL() 注册了很多外部接口, 但都是在内部调用, 只是为了作为回调所以注册?
flashcache_ctr()
src/flashcache.h,
struct cache_c, cache context,
dmc 核心数据结构, 维护target, queue, 和其他count
dmc->num_sets = dmc->size >> dmc->assoc_shift
dmc->cache_sets[dmc->num_sets]
dmc->cache[]
#define DEFAULT_CACHE_ASSOC 512
#define DEFAULT_MD_BLOCK_SIZE 8 /* 4 KB */
struct cache_set, 2层LRU, warm + hot
struct cacheblock
u_int16_t lru_prev, lru_next,
u_int16_t hash_buckets[512], 环形队列
dmc->cache_mode, 构造时从参数中获取,
FLASHCACHE_WRITE_BACK
FLASHCACHE_WRITE_THROUGH
FLASHCACHE_WRITE_AROUND
dmc->cache, 根据dmc->cache_mode, 由
flashcache_writeback_create()/flashcache_writethrough_create()之类的函数分配,
dmc->cache = (struct cacheblock *)vmalloc(order)
flashcache_conf.c,
flashcache_init() =>
flashcache_target, 注册到dm的target, ctr/dtr/map/ioctl等
ctr() => flashcache_ctr()
=>
flashcache_reclaim_init_lru_lists()
LRU布局
-- LRU_HOT | LRU_WARM --
需要为每个dmc->cache_sets[set] 分配
两段式的LRU, nothing new ...
Add/del pids whose IOs should be non-cacheable.
flashcache_ioctl()
参考 src/flashcache_ioctl.h
NCPID_CMD => BLACKLIST
WHITELIST_CMD => WHITELIST
估计是先有了black list, 再发明了white list
dmc->blacklist_head, blacklist_tail
dmc->whitelist_head, whitelist_tail
就是对应的pid 是否执行cache, 大概吧
drivers/md/dm.c,
__map_bio()
将对设备bio转换成tio, 分发到各个dm_target上去
ti->type->map(struct dm_target * ti, clone_bio)
=>
flashcache_map()
read()/ write()
async() =>
flashcache_io_callback()
基本都是生成job, push到对应的job list中,
flashcache_init(), flashcache_conf.c,
INIT_WORK(&_kcached_wq, do_work);
由work_queue, 调用
do_work(), flashcache_subr.c
对5个job list,
LIST_HEAD(_pending_jobs);
LIST_HEAD(_io_jobs); LIST_HEAD(_md_io_jobs);
LIST_HEAD(_md_complete_jobs);
LIST_HEAD(_uncached_io_complete_jobs);
执行对应的处理函数
在flashcache_main.c中, **_callback()会调用
schedule_work(&_kcached_wq), 处理work_queue
为什么flashcache效率高?
1. 使用大块连续cache block, 维护cache和lru的都是cache内部的offset id,
而不是指针
不会产生太大影响
2. 多个job list, 不同的async操作在不同的list排队, 避免相互干扰
特别是区分了io和md_io(meta data)
flashcache_io_callback(), flashcache_main.c
区分方法:
1) READDISK -> push_io(), 只有readdisk用
2) WRITECACHE先执行写metadata,
flashcache_dirty_writeback() =>
flashcache_kcopyd_callback() =>
flashcache_md_write()
3) 写data丢给pending
jobs在flashcache_subr.c中实现, 其中是否有优先级实现 ???
该文件中应该没有, work_queue到哪里都一样
do_work() =>
process_jobs() 对5个jobs list, 每次只处理FLASHCACHE_YIELD = 32个,
一旦超过就yield(), 将会导致排在前面的jobs比后面的jobs有更多的执行机会,
从而实现优先级机制
排列顺序:
_md_complete_jobs
_pending_jobs
_md_io_jobs
_io_jobs
_uncached_io_complete_jobs
是否可以进一步优化 ???
很有趣, 很精彩, 这里才是效率提升的关键
3) flashcache_lookup(struct cache_c *dmc, struct bio *bio, int *index)
通过dmc和bio在连续内存dmc->cache[]中查找index
还是靠hash获取index
用数组或tree实现index定位, 效率上应该相差不大
flashcache_write()
在执行flashcache_lookup()后, 再检查cacheblk->dbn == bio->bi_sector,
避免hash冲突导致index误命中
flashcache_write_miss()
在发现hash冲突后, 必须先将原有的冲突hash和block清洗掉
flashcache_hash_remove()
能否重用冲突hash, 例如list ?
4) flashcache分区格式对性能的帮助
src/utils/flashcache_create.c,
最终调用dmsteup命令 =>
flashcache_ctr(), src/flashcache_conf.c
atomic_set(&dmc->hot_list_pct, FLASHCACHE_LRU_HOT_PCT_DEFAULT);
其中, FLASHCACHE_LRU_HOT_PCT_DEFAULT = 50
flashcache_reclaim_rebalance_lru(dmc, dmc->sysctl_lru_hot_pct),
flashcache_procfs.c
dmc->sysctl_lru_hot_pct = 75;
hot_blocks_set = (dmc->assoc * atomic_read(&dmc->hot_list_pct)) / 100
flashcache_reclaim.c
注意细节
flashcache_reclaim_rebalance_lru(),
使得warm list与hot list之间block数量在偏向dmc->sysctl_lru_hot_pct的比例变动,
即由50%向75%变化
阅读(2508) | 评论(0) | 转发(0) |