小码虫的公众号:
目前EXT2-4有两种索引方式:
1.间接地址索引
2.extent树索引(仅ext4支持)。
间接地址索引
ext间接地址索引的inode机制。如下:
1.每个文件仅会占用一个inode
2.每个inode大小均固定位128bytes(ext4默认为256,但是可以选择限定为128),大部分空间是用来存储文件属性的,inode记录一个索引信息占用4byte
3.ext文件系统为了让inode记录尽可能多的data block,定义了四个记录block号码的区域,分别为12个直接记录区,一个间接记录区,一个双间接记录区,一个三间接记录区,所谓间接记录区就是用data block记录data block号码
在ext2文件系统中fs/ext2/ext2.h中struct ext2_inode的项__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks /,就是这15个索引指针,指向记录区的blocks。
ext3在kernel3.x版本中,ext3用到的头文件在fs/ext3/ext3.h中,其中struct ext3_inode的项__le32 i_block[EXT3_N_BLOCKS];/ Pointers to blocks /就是这15个索引指针,指向记录区的blocks。
在ext4文件系统中fs/ext4/ext4.h中struct ext4_inode的项__le32 i_block[EXT4_N_BLOCKS];/ Pointers to blocks */,就是这15个索引指针,指向记录区的blocks。ext3在kernel4.x版本中,内核fs目录下都没有ext3这个目录了,根据介绍,是ext3成为了ext4的子集,日志功能用ext2的,其他使用ext4的,也就是头文件用了ext4的头文件,ext4中的inode结构体。
间接索引下文件的最大上限(block为1K,因为1k好算,4k算出来的数太大了):
1个间接记录取大小为4K,inode记录一个索引信息占用4byte,则可以容纳256个索引信息。
(1)12个直接记录区容量:12 * 1K = 48K
(2)1个间接记录区容量:256 * 1K = 256K
(3)1个双间接记录区容量:256 * 256 * 1K = 65536K
(4)1个三间接记录区容量:256 * 256 * 256 * 1K = 16777216K
将四个记录区容量相加,总容量为16843020K,约等于16G,这个大小就是ext采用间接地址索引方式的单个文件的最大上限。可以看出,当文件大于48k时,才会使用第一个间接记录区,大于48+256+65536K时才会使用第三个间接记录区。
extent树索引
在/etc/mke2fs.conf中可以看到ext4的默认格式化参数:
ext4 = {
features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit
inode_size = 256
}
ext4下的extent本质上就是一个B+树。只有叶子节点是数据blocks,其他节点都是索引节点。下面两个图很清晰的解释了索引原理,只要能理解B+树,则很快理解以下两幅图。
图片摘自https://www.xuebuyuan.com/1470646.html
struct ext4_extent_header {
__le16 eh_magic; /* 幻数magic number, 0xF30A. */
__le16 eh_entries; /* 区段数. */
__le16 eh_max; /* 最大的区段数. */
__le16 eh_depth; /* 节点在树中的深度。0则表示为叶子节点,指向数据块;否则指向其它段节点。 */
__le32 eh_generation; /* generation of the tree */
};
struct ext4_extent_idx {
__le32 ei_block; /* 逻辑块号. */
__le32 ei_leaf_lo; /* 区段树中下一层的区段节点块地址(低32位),可以指向叶子节点或者内部节点。 */
__le16 ei_leaf_hi; /* 高16位地址 */
__u16 ei_unused;
};
struct ext4_extent {
__le32 ee_block; /* 此区段的第一个块号,起始块号 */
__le16 ee_len; /* 区段内包含的块数. */
__le16 ee_start_hi; /* 此区段所指向的块号(高16位) */
__le32 ee_start_lo; /* 此区段所指向的块号(低32位) */
};
在inode条目中,不在是使用指针索引的方式来进行与block的映射,而是采用extent来替代指针;此前在ext3中的15个指针被替换成1个extent header和4个extent,一个extent占用12个字节;一个extent描述了一组连续的block,当不够用时extent依旧可以采用间接指针的索引,但没有个数限制。对于很大的文件,ext4采用extent_tree的方式,其本质同样是一种间接寻址的关系
一个extents是一个地址连续的数据块(block,一个block是4KB)的集合。比如一个100MB的文件有可能被分配给一个单独的extents(前提是有一块大于100M的连续空闲空间,其中ee_len是一个无符号16位的整数,最大可以容纳65535吧。也就是2^16-1个blocks。也就是一个extent可以索引65535*4KB的空间,等于256MB-4KB空间)。这样就不用像Ext3那样新增25600个block的索引(一个索引占4个字节,100MB文件的索引也要用100KB的空间,而且寻找间接索引地址也要消耗IO, 磁盘磁头寻找耗时)。很明显,Extents的实现提高了文件系统的性能,减少了文件碎片
参考资料:
ext4_ext_find_extent解析:https://www.xuebuyuan.com/1470646.html
Storage Administration Guide:https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html-single/Storage_Administration_Guide
EXT4-wiki:https://en.wikipedia.org/wiki/Ext4#Limitations
Ext4 Disk Layout:https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout
[ext4] 磁盘布局 - extent tree:https://blog.csdn.net/younger_china/article/details/22287265
What are the file and file system size limitations for Red Hat Enterprise Linux?:https://access.redhat.com/solutions/1532