ext4的延迟分配

来源:互联网 发布:开淘宝的流程及费用 编辑:程序博客网 时间:2024/05/17 10:24


ext4的延迟分配

http://blog.csdn.net/kai_ding/article/details/9914629

Ext4文件系统在应用程序调用write的时候并不为缓存页面分配对应的物理磁盘块,当文件的缓存页面真正要被刷新至磁盘中时,ext4会为所有未分配物理磁盘块的页面缓存分配尽量连续的磁盘块。

        Linux文件系统Vfs层总是将应用程序的写入请求分割成页面(默认大小4KB)为单位,对于每个页面,VFS会检查其是否已经为其创建了buffer_head结构,如果没有创建,则为其创建buffer_head,否则检查每个buffer_head的状态,如该buffer_head是否已经与物理磁盘块建立映射等,这些功能是由write_begin()函数实现的,该函数是由VFS提供的一个接口,具体文件系统负责实现该接口,如ext3文件系统的ext3_write_begin()。而ext4如果采用了delay allocation特性的话,其实现的函数为ext4_da_write_begin()。

        ext4_da_write_begin()会检查页面所有的buffer_head的状态,如buffer_head是否已经建立映射等,对于没有建立映射的buffer_head,需要将其与物理磁盘块建立映射关系,调用的函数是ext4_da_get_block_prep(),该函数又调用了ext4_map_blocks()来建立逻辑块和物理磁盘块的映射关系,如果启用extent特性的话,那么该函数又调用了ext4_ext_map_blocks(handle, inode, map, 0)来建立这种映射关系,之所以列举该函数的参数是要特别注意其最后一个参数0,这是一个标志位,调用者ext4_map_blocks()将该标志位设置为0,告诉被调用者,如果没有建立映射关系,那么此刻无需真正地分配物理磁盘块。这在ext4_ext_map_blocks函数中可以看到会有对该标志位的判断。就不再详细列举代码了。因为在ext4_map_blocks()中并没有建立映射关系,因此其向ext4_da_get_block_prep()返回0,表示没有映射,在ext4_da_get_block_prep()函数中判断如果返回值为0,那么为当前block设置标志位BH_New,BH_Mapped,BH_Delay(表示该块在写入的时候再进行延迟分配)。



        以上我们确认了在ext4中延迟分配的前半部分,即应用程序将数据写入文件时只是简单地将数据以页面为单位写入页面缓存中,而并不真正地为其分配物理磁盘块。接下来我们要弄明白的是,ext4何时会为缓存中未分配物理磁盘块的缓存分配磁盘空间。

        当刷新线程开始将脏的缓存页面写回至物理磁盘时,根据我们之前的描述,回写线程会以文件为单位进行回写,即对脏inode链表上的所有脏inode依次回写。对于每个脏inode(也即每个脏的文件),回写线程会将inode上的所有脏页面进行回写,这时候就需要判断每个脏页面的状态了。

        回写线程中实现的时候将一个文件的脏页面分多次进行回写,每个回写一部分脏页面。关于回写机制可参考Linux的“脏页面回写机制”。回写脏页面最终调用到函数writepages,与writebegin一样,它也是VFS提供的一个虚拟接口,由具体文件系统负责相应的实现。对于采用延迟分配的ext4文件系统来说,该函数的具体实现是ext4_da_writepages()。该函数中实现的时候有三个要点:

  1.  要将逻辑上连续的脏且尚未建立磁盘块映射到物理页面形成一个extent,以便可采用ext4的mblock分配策略提升文件连续性,这也是我们后面要介绍的内容;
  2. 对1中连续页面形成的extent,为其进行磁盘块分配,分配采用了ext4的mblock allocation策略。
  3. 提交2中的extent至bio层完成脏页面的写入,此时已经为尚未映射的缓存页面分配了物理磁盘块。

上图描述了延迟分配的核心思想:等到刷新脏缓存页面时再建立脏页面与物理磁盘块之间的联系,而且,分配之前将逻辑上连续的文件块映射至物理上连续的磁盘块。在ext4_da_writepages()函数中调用了三个非常重要的函数来完成上述功能:write_cache_pages_da()负责将逻辑上连续的文件块合并成一个extent;mpage_da_map_blocks()负责为合并后的extent建立映射关系;mpage_da_submit_io()负责提交上面映射的extent。

0 0