flashcache_md_write
来源:互联网 发布:易用进销存软件 编辑:程序博客网 时间:2024/06/09 20:18
flashcache_md_write函数会在某一cache块由脏变干净或者由干净变脏的情况下调用:这一点可以从代码中这部分看出来:
VERIFY(job->action == WRITEDISK || job->action == WRITECACHE || job->action == WRITEDISK_SYNC);
当然也可以从flashcache_md_write_kickoff函数中(同步元数据的实际代码)看出来:
if (job->action == WRITECACHE) { /* DIRTY the cache block */ md_block[INDEX_TO_MD_BLOCK_OFFSET(dmc, job->index)].cache_state = (VALID | DIRTY); } else { /* job->action == WRITEDISK* */ /* un-DIRTY the cache block */ md_block[INDEX_TO_MD_BLOCK_OFFSET(dmc, job->index)].cache_state = VALID; }
如果该块元数据上已经有IO在进行处理,那么就加到等待队列的队尾上去,这里有一个问题,等待队列上的请求会等到什么时候才被处理呢?
md_block_head = &dmc->md_blocks_buf[INDEX_TO_MD_BLOCK(dmc, job->index)]; spin_lock_irqsave(&md_block_head->md_block_lock, flags); /* If a write is in progress for this metadata sector, queue this update up */ if (md_block_head->nr_in_prog != 0) { struct kcached_job **nodepp; /* A MD update is already in progress, queue this one up for later */ nodepp = &md_block_head->queued_updates; while (*nodepp != NULL) nodepp = &((*nodepp)->next); job->next = NULL; *nodepp = job; spin_unlock_irqrestore(&md_block_head->md_block_lock, flags);
这就要看flashcache_md_write_done(struct kcached_job *job)再处理完本次元数据写后是怎么处理的:
if (md_block_head->queued_updates != NULL) { /* peel off the first job from the pending queue and kick that off */ job = md_block_head->queued_updates; md_block_head->queued_updates = job->next; spin_unlock(&md_block_head->md_block_lock); job->next = NULL; spin_unlock_irq(&cache_set->set_spin_lock); VERIFY(job->action == WRITEDISK || job->action == WRITECACHE || job->action == WRITEDISK_SYNC); flashcache_md_write_kickoff(job);
可以看到,在该函数的末尾处,也就是完成了处理这次元数据写完的过程后,会检查该元数据块的等待队列,如果等待队列非空,则需要继续进行元数据写操作。这样可以保证对cache的写操作能够尽快完成(元数据写到cache上才算这次对cache写数据的操作完成)
那么如果原本等待队列为空呢?
} else { md_block_head->nr_in_prog = 1; spin_unlock_irqrestore(&md_block_head->md_block_lock, flags); /* * Always push to a worker thread. If the driver has * a completion thread, we could end up deadlocking even * if the context would be safe enough to write from. * This could be executed from the context of an IO * completion thread. Kicking off the write from that * context could result in the IO completion thread * blocking (eg on memory allocation). That can easily * deadlock. */ push_md_io(job); schedule_work(&_kcached_wq); }
这里看else语句,通过注释得知,一般会在一次IO完成后,写元数据时,进入该else子句,这时候为了防止执行该子句的线程死锁(因为写元数据嘛,可能要申请内存,而如果内存申请不到,该线程就可能阻塞在这)。这时,就需要把写元素据的任务交给work_queue去处理,而此次对数据的IO就可以结束了。这样就避免了该线程的死锁。我用下面的代码测试了一下workqueue。可以发现workqueue和调用schedule_work的线程是两个线程去做的,所以就避免了死锁的情况:
#include <linux/module.h> #include <linux/init.h> #include <linux/workqueue.h> #define N 1000static struct work_struct work; static void work_handler(struct work_struct *data) { int i; for(i = 0 ; i < N ;i++){ printk("handle"); }} static int __init workqueue_init(void) { int i; // printk("init work queue demo.\n"); INIT_WORK(&work, work_handler); schedule_work(&work); for(i = 0 ; i < N ; i++){ printk("init _just a demo for work queue.\n"); } return 0; } static void __exit workqueue_exit(void) { printk("exit work queue demo.\n");} MODULE_LICENSE("GPL");module_init(workqueue_init); module_exit(workqueue_exit);
输出结果会先输出N条init _just a demo for work queue.再输出N个handle,中间没有交叉从输出结果来看工作队列会推迟任务的执行。
0 0
- flashcache_md_write
- [leetcode]344. Reverse String
- push代码到github时,每次都要输入用户名和密码的问题
- spring从头开始(三)----bean织入进阶
- 百度之星2016 资格赛 java 代码实现
- Spring Mvc那点事---(5)Spring Mvc请求参数传递
- flashcache_md_write
- 常用的正则表达式
- html 语义化的理解
- centos6.4下安装mongodb-3.2.6
- BestCoder Round #83 1004 zxa and xor
- Javascript基础知识盲点总结——函数
- Remus和Xen
- C/C++标准误导篇
- 位运算