Linux内核mod_delayed_work延迟执行与sync阻塞问题咨询
问题分析与解答
这种300秒的延迟绝对不属于正常情况,而且watchdog并不是导致工作队列休眠的原因——相反,watchdog能正常运行说明系统调度器还在工作,问题出在bdi回写工作队列的调度或者回写路径本身。下面结合你的场景和4.9.13内核的特性拆解问题:
1. mod_delayed_work(bdi_wq, &wb->dwork, 0) 的预期行为
当你传入延迟参数0时,这个调用的语义是立即调度工作项:内核会把wb->dwork标记为待执行状态,并唤醒bdi_wq对应的worker线程来处理wb_workfn()。正常情况下,工作函数应该在毫秒级到1秒内启动,你遇到的300秒延迟明显是异常的。
2. 延迟300秒的可能原因
结合你5块磁盘并发大文件复制+sync+删除的高IO负载场景,大概率是以下几种情况:
- 回写路径锁竞争阻塞:4.9内核的回写逻辑中,
wb_workfn()需要持有wb->list_lock、超级块锁(sb_lock)等关键锁。当系统有大量并发回写请求时,如果某个线程因为慢IO(比如磁盘响应延迟)长时间持有这些锁,后续的回写任务就会被卡在队列里,直到锁被释放。 - 工作队列唤醒机制失效:4.9.13属于比较旧的内核版本,可能存在
mod_delayed_work调用后未正确唤醒bdi_wqworker线程的bug。比如当worker线程处于休眠状态时,新的工作项加入队列,但唤醒信号没有触发,直到某个周期性的回写定时器(默认可能设置为300秒)触发才会唤醒worker。 - 脏页回写队列积压:你的测试脚本不断生成脏页并触发sync,会导致回写任务大量积压。如果
bdi_wq的worker线程数量不足(默认每个bdi对应一个worker),无法及时处理所有任务,就会出现任务排队延迟。
3. watchdog的角色澄清
watchdog线程的作用是监控系统是否出现死锁或无响应,它本身不会干预工作队列的调度。你看到watchdog在运行,恰恰说明系统没有完全卡死,只是bdi_wq的worker线程要么被高优先级任务抢占,要么被锁阻塞,要么处于未被唤醒的休眠状态。
4. 排查与修复建议
- 检查内核日志:查看
dmesg输出,有没有IO超时、锁竞争警告(比如soft lockup)等信息,这些能帮你定位具体的阻塞点。 - 调整回写参数:临时增大
dirty_ratio(比如从默认20调到40)或dirty_background_ratio,减少回写触发的频率,缓解队列积压:echo 40 > /proc/sys/vm/dirty_ratio echo 20 > /proc/sys/vm/dirty_background_ratio - 升级内核补丁:4.9内核后续的稳定版(比如4.9.300+)修复了不少回写和工作队列相关的bug,建议升级后再测试。
- 追踪调度过程:用
trace-cmd或perf工具追踪wb_workfn的调度事件,看看它什么时候被唤醒、被什么函数阻塞,比如:trace-cmd record -e sched_switch -e workqueue_execute_start -e workqueue_queue_work
内容的提问来源于stack exchange,提问作者zhuanyeshiti
相关产品推荐
相关产品推荐

