页缓存回写时,导致sync阻塞的问题
来源:互联网 发布:一洋电商软件 编辑:程序博客网 时间:2024/06/10 16:22
问题抽象出来是这样:
有一块ubifs文件格式的flash,挂在/mtd3上
拷贝一个大文件big_flash(大约40M),到/mtd3上
如果在拷贝文件的时候,执行sync命令,则会导致sync长时间阻塞,阻塞链为:
wait_on_bit(WS_USED_B)
bdi_wait_on_work_clear
bdi_sync_writeback(sb)
sync_inodes_sb(sb)
__sync_filesystem
sync_filesystems
其中,关键代码为线程将自己挂载到新初始化的work等待队列里,等待flusher处理。
bdi_queue_work
list_add_tail_rcu(&work->list, &bdi->work_list);
wake_up_process(wb->task);
可以看出,sync将本刷新请求封装到work里,挂到bdi的work_list链表,然后唤醒flusher,尝试处理这些回写。
因为flusher处理不及时,导致sync长时间阻塞。
于是,就要找出问题时,flusher线程在做什么。
猜测如下场景:
1) cp命令,在big_flash的inode里的mapping页缓存里,产生大量脏页,flusher线程处理这些脏页的回写,
以每次1024个页面的规模,往flash写数据。疑问:这个flusher正在处理的work是如何生成的。
2)当刷出的page cache数目达到系统水线后,不再继续刷此work代表的page cache,退出返回上一层后,唤醒处于等待此刷新work
的进程
3)继续取下一个work进行处理。这个work正好就是sync提交的刷页请求。在最终调用pagevec_lookup_tag 找不到更多的脏页后,
退出此work处理,唤醒sync线程
所以问题还是在于1步骤太耗时导致的。
循环拷贝文件时, 执行sync一直不能退出问题测试分析结论如下:
原理及知识要点:
1) sync: 同步等待所有脏页刷入 flash
2) 内核flusher线程,负责将脏页刷入 flash后,通知1完成
3) 测试用例,循环拷贝,删除文件,不断产生脏页
4) 大部分flash文件系统,采取的是异地更新策略。即不修改当前数据,而重新拷贝一份,修改好拷贝的数
据后,删除原来的废弃数据。
5)在出问题时,2的速度,小于3的速度,导致1完成不了。
出问题时,发现flusher一直在处理sync提交的刷新任务(即sync阻塞等待的任务)
为什么会一直处理sync的任务?
因为,sync提交的任务是同步刷新,即带有WB_SYNC_ALL标志。这个标志的意思是,等待bdi设备里的所有脏页
刷完为止。
具体的内核实现点在write_cache_pages函数,这个函数本身是个大循环:
int write_cache_pages(struct address_space *mapping,
struct writeback_control *wbc, writepage_t writepage,
void *data)
{
...
while (!done && (index <= end)) {
int i;
nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
PAGECACHE_TAG_DIRTY,
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
//每次尝试从inode的mapping里取出14个脏页,刷到flash里,如果这个inode没有脏页了,就停
止刷新
if (nr_pages == 0)
break;
...
for (i = 0; i < nr_pages; i++) {
...
ret = (*writepage)(page, wbc, data);
if (nr_to_write > 0) {
nr_to_write--;
if (nr_to_write == 0 &&
wbc->sync_mode == WB_SYNC_NONE) {
//非同步方式的刷新,当回写1024个页面后,就退出不再回写,但我们是
WB_SYNC_ALL,因此会一直遍历inode的脏页
//直到没有脏页可写为止。
//由于ubifs(其实所有异地更新文件系统都有这个问题),在修改文件过程中,
//会产生大量无效的物理块,如果不及时回收,则ubi写flash会非常慢。
//就算最后,终于刷完从index=0后的所有脏页,由于此时一定有nr_to_write =
0,即已经刷完了1024个页面,返回到外层函数
//wb_writeback后,还会再次进入write_cache_pages尝试从index = 0刷1024
个页,
//因此,造成不能退出的位置在 wb_writeback函数的循环里
done = 1;
break;
}
}
}
}
}
static long wb_writeback(struct bdi_writeback *wb,
struct wb_writeback_args *args)
{
for (;;) {
writeback_inodes_wb(wb, &wbc);
if (wbc.nr_to_write <= 0) //这里无法退出到上层,不能设置work处理完毕,也就不能
通知sync线程刷新完成
continue;
}
}
- 页缓存回写时,导致sync阻塞的问题
- 非阻塞connect导致的问题
- sync问题导致shell脚本执行失败
- ibatis 缓存导致的一个问题
- 如何解决Connect超时导致的阻塞问题
- 1.并发情况导致的线程阻塞和数据一致性问题
- Activity 跳转导致的 webView js 阻塞问题:
- 针对FastDB commit时sync到文件导致效率降低问题的官方权威解决方法
- IE的缓存导致ajax不走后台的问题
- debuggerd阻塞问题导致冻屏
- Spring对iBatis封装导致的缓存问题
- 浏览器缓存导致FLASH资源更新问题的解决方案
- IE6异步请求缓存导致的乱码问题
- 并发时,缓存锁导致的相关问题
- phpStorm 的严重问题,自动缓存导致SVN被还原
- [JAVA]Socket中BufferedReader.readLine()的阻塞特性导致的数据无法多次发送的问题
- Apache HttpClient 没有设置time out导致应用长时间阻塞的问题
- 关于启用sessionState外部存储,导致IHttpAsyncHandler长连接阻塞线程的问题
- 关联规则学习-序列模式挖掘
- 对想了解某个领域的初学者来说最值得推荐的一本书
- Android系统常用隐藏命令大全
- 重力感应调试记录
- Guava 库整理
- 页缓存回写时,导致sync阻塞的问题
- java多线程编程
- 查看repo库上分支版本
- Linux学习路线浅谈
- 关联、组合、聚合、依赖关系比较
- va_list和vsnprintf
- jsp获取多个checkbox的值
- Linux学习建议
- 一位ACMer过来人的心得