Linux中struct buffer_head标记为脏后如何被刷写到磁盘?
Linux
buffer_head 脏状态刷写磁盘机制 你找不到单独遍历脏buffer_head的后台例程是正常的:2.6版本之后内核就废弃了独立的缓冲区缓存,所有buffer_head都是页缓存(page cache)中内存页的块级描述符,刷写逻辑归属writeback(回写)子系统,不会单独扫描buffer_head做脏状态检查。
核心后台刷写线程
你推测的周期性检查逻辑确实存在,现在的实现是每个块设备独立的flush-<major>:<minor>内核线程,由两类触发源唤醒:
- 周期性唤醒:全局工作队列上的
wb_workfn任务会按照dirty_writeback_centisecs内核参数配置的周期(默认500,即5秒)运行,检查所有块设备回写队列的脏页 - 事件触发:包括系统可用内存低于水位线、脏页占内存比例超过
dirty_background_ratio阈值、用户态调用sync/fsync/fdatasync等显式刷盘接口、文件系统主动触发刷写等场景。
历史版本说明:2.4及更早内核确实存在
bdflush后台线程专门扫描脏缓冲区,2.6早期替换为全局pdflush线程,后续为了避免块设备锁竞争又改成了现在的per-block-device flush线程架构,老资料里提到的bdflush/pdflush在5.x及以上版本内核中已经完全移除。
完整刷写链路
当buffer_head被标记为脏(置BH_Dirty位)时,它所属的内存页(高版本内核为folio)也会同步被标记为脏,挂入所属inode的脏页链表、对应块设备的回写队列,后续刷写流程如下:
- 回写线程被唤醒后,首先从队列中筛选出脏时长超过
dirty_expire_centisecs(默认30秒)的脏页,构造回写批次 - 针对每一个脏页,调用对应文件系统注册的
address_space_operations->writepages回调,该回调会遍历页的private指针挂载的buffer_head链表,筛选出所有置了BH_Dirty标记的块 - 文件系统层为这些脏块构造
bioIO请求,同时清除对应buffer_head的BH_Dirty标记,置BH_Lock、BH_WriteReq标记,将bio提交给块层IO调度器 - 块层调度器对IO按物理扇区地址排序、合并后,下发给块设备驱动
- 磁盘硬件完成写入后触发中断,内核在IO完成回调中清除
buffer_head的BH_Lock标记,唤醒所有等待该块写入完成的进程,单次刷写流程结束。
代码定位参考
核心逻辑集中在三个内核源文件中,顺着入口就能捋完完整流程:
- 回写框架核心逻辑:
mm/page-writeback.c、mm/backing-dev.c buffer_head相关的刷写辅助逻辑:fs/buffer.c
内容的提问来源于stack exchange,提问作者shengjiang
相关产品推荐
相关产品推荐

