ext4的Extent解析

来源:互联网 发布:格灵深瞳 知乎 衰败 编辑:程序博客网 时间:2024/05/16 10:44

概述

        前面我们在阐述ext2文件系统实现原理的时候了解到,ext2文件系统采用了直接+多级间接映射的方式来存储逻辑块号到物理块号的映射关系。这种方式不仅实现起来较为复杂,而且在面对大文件的时候效率较为低下,且会浪费很多的间接块以存储映射关系。本篇博客中,我们主要阐述ext4文件系统逻辑块至物理块的映射关系实现方式:extent。如果要使用ext4的extent特性,必须在挂载时指定该特性。

数据结构

        所谓的extent指的是一段连续的物理磁盘块,这样,只需要一个extent数据结构我们就能描述一段很长的物理磁盘空间,性价比很高。

        其次,我们得明白,ext4文件系统中的extent是干什么的,又存储在哪里?ext4文件系统中的extent数据结构的主要作用是索引,即根据逻辑块号查询文件的extent能够准确定位逻辑块对应的物理块号,另外,ext4的extent在文件较小的时候存储在inode的i_data[]中,在文件较大的时候,所有的extent会被组织成一棵B+树,这点将会在后面有详细描述。ext4文件系统中与extent相关的数据结构有三:

/*

 * Each block (leaves and indexes), even inode-stored has header.

 */

struct ext4_extent_header {

         __le16      eh_magic;        /*probably will support different formats */

         __le16      eh_entries;      /* number of valid entries */

         __le16      eh_max;           /*capacity of store in entries */

         __le16      eh_depth;       /*has tree real underlying blocks? */

         __le32      eh_generation;       /* generation of the tree */

};

        每个extent节点由一个头部和多个body组成,无论是索引节点还是叶子节点,甚至是直接存储在inode中的extent节点。当一个文件占用的extent数量较少的时候,其extent可直接存储在inode.i_block[]中,当extent数量超过inode.i_block[]的存储容量的时候(一般来说,其里面可保存4个extent),ext4便会用B+树来组织所有的extent。B+树上的每个节点,无论是索引节点还是叶子节点,其主体包含两个部分:extent_header和extent_body。每个节点包含一个extent_header和多个extent_body。描述extent_header的数据结构如上,描述extent_body的数据结构如下。


        extent_body分为两种,索引节点和叶子节点,索引节点用于存储到叶子节点的中间路径,叶子节点记录文件一段连续的逻辑块所对应的物理磁盘块范围。其数据结构分别如下列举:

/*

 * This is indexon-disk structure.

 * It's used at all thelevels except the bottom.

 */

struct ext4_extent_idx {

         __le32      ei_block;     /* index covers logical blocks from 'block'*/

__le32   ei_leaf_lo;      

         __le16      ei_leaf_hi;        /* high 16 bits of physical block */

         __u16       ei_unused;

};//索引节点中的extent_body格式

/*

 * This is the extenton-disk structure.

 * It's used at thebottom of the tree.

 */

struct ext4_extent {

         __le32      ee_block;         /*first logical block extent covers */

         __le16      ee_len;              /*number of blocks covered by extent */

         __le16      ee_start_hi;    /* high 16 bits of physical block */

         __le32      ee_start_lo;    /* low 32 bits of physical block */

};//叶子节点的extent_body格式

        Ext4创建文件/目录的时候,会初始化一棵extent tree,具体来说,在函数ext4_create中会调用ext4_ext_tree_init来为新创建的文件/目录创建extent tree,当然,目前该树还是空的。

extent tree初始化

        在ext4文件系统创建文件或者目录的时候,分配完成inode之后,会初始化一棵extent tree,当然,目前的extent tree只有一个extent节点。而且直接存储在i_data[]域中,如以下代码所示:

int ext4_ext_tree_init(handle_t *handle, struct inode *inode){struct ext4_extent_header *eh;//eh = (struct ext4_extent_header *)(EXT4_I)(inode)->i_dataeh = ext_inode_hdr(inode);eh->eh_depth = 0;eh->eh_entries = 0;eh->eh_magic = EXT4_EXT_MAGIC;//计算该extent中可存储的extent_body数量eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));ext4_mark_inode_dirty(handle, inode);ext4_ext_invalidate_cache(inode);return 0;}
        该函数在被调用的路径是:ext4_create->ext4_new_inode->ext4_ext_tree_init。该函数初始化了extent tree的根节点,而且其使用了inode中的i_data来存储当前根节点,因为我们说过,每个extent节点均包含一个头部和一个或者多个body,可以将头部理解为描述信息,body为真正有用的索引数据。因为i_data存储容量有限(i_data只有60个字节),所以刨去头部占用的特定大小的空间外,我们还必须计算最多能存储多少个body,这就是cpu_to_le16(ext4_ext_space_root(inode, 0))的作用了。
原创粉丝点击