- 加快write()的响应速度。因为media的读写相对于内存访问是较慢的。如果每个write()都访问media,势必很慢。将较慢的media访问交给writeback thread,而write()本身的thread里只在内存里操作数据,将数据交到writeback queue即返回。
- 便于合并和排序 (merge and sort) 多个write,merge是将多个少量数据的write合并成几个大量数据的write,减少访问media的次数;sort是将无序的write按照其访问media上的block的顺序排序,减少磁头在media上的移动距离。
下面将说明writeback的活动机制。
- 概念:writeback和bdi
- bdi的init, register
(1). 在bdi_init中:
* 创建一个struct backing_dev_info的变量来代表一个bdi。
* 创建一个work queue: bdi_wq用于存放writeback的事件。
* 创建一个delayed work(即bdi->wb.dwork)的thread,这个thread负责完成writeback动作。 (2). 在bdi_register中:
* 将这个bdi链接到全局变量bdi_list所指的bdi list里
- default bdi的init, register
- block device (scsi disk) bdi的init, register
- 从writeback queue到bio
- Writeback thread
首先,我们从writeback thread启动开始。从前面的图中我们已经知道,writeback thread是在bdi_init()时创建的一个delayed work,即bdiX->wb.dwork。当bdiX->wb.dwork->timer expire时,writeback thread的函数bdi_writeback_workfn()就开始运行,它的流程如下:
注意writeback的优先级顺序,先是强制writeback的work,如用户执行了fsync(fd),然后是writeback interval到了之后的work,最后是background的work。'work'是writeback的‘单位’,不管是sync()还是dirty_writeback_interval时间到了的writeback,都要包装成一个'work'交给writeback thread。
- 一个'work'的Writeback过程
wb_writeback()函数负责完成一个work的writeback,下图是其流程。
一般一个文件系统mount的时候会有一个super block,对于文件系统层面的sync产生的writeback work,它的super block即work->sb是确定的。对于dirty_writeback_interval时间到了产生的work,所有在该bdi上的super block的dirty inode都要writeback,work->sb就不能指定了。典型的场景是sda1上有一个文件系统,sda2上有另一个文件系统,它们只有一个bdi。当只sync sda1的时候,产生的work->sb指定为sda1的super block,调用writeback_sb_inode()。当interval时间到了,sda bdi上所有的dirty inode都要sync,此时产生的work->sb就不能指定了,调用__writeback_inodes_wb()。实际上在__writeback_inodes_wb()内部还是遍历每个inode,软后调用writeback_sb_inode()的。所以writeback_sb_inode()是核心函数,下图是它的流程,因为比较长,我画了两页图。简单的说,就是一个一个writeback dirty inode,由__writeback_single_inode() 完成,直到这次writeback的时间到了或者没有dirty inode了。wbc是writeback control,用来控制writeback的。
writeback_sb_inode()的流程(图2, 接图1):
下面是__writeback_single_inode()的流程,其本质是通过实际文件系统实现时注册的address_space_operations的writebackpages() 或writbackpage()将dirty的Page写到media上,如果inode本身也是dirty的(比如文件的meta data, size等也改变了),那么这些文件信息也要写回media。
下面是ext2里aops->writeback的流程,本质是在实际文件系统的格式里找到要写page对应的block位置,构建出相应的buffer head(bh)以及bio,然后调用submit_bio()来产生一个对block device的write。
至此,我们已经讲完了dirty inode从writeback queue到bio的过程。bio还只是一个抽象的读写block device的请求,bio要变成实际的block device access还要通过block device driver,还要再排队,还要受到ioschduluer的控制。这些将在第五章讲述。