Linux中的EXT系列文件系统格式详解

  


  

  

癓inux中的EXT系列文件系统格式详解"

  

常见的硬盘如上图所示,每个盘片分多个磁道,每个磁道分多个扇区,每个扇区512字节,是硬盘的最小存储单元,但是在操作系统层面会将多个扇区组成块(块),是操作系统存储数据的最小单元,通常是8个扇区组成4 k字节的块。
  对于Linux文件系统,需要考虑以下几点:

  
      <李>文件系统需要有严格的组织形式,使文件能够以块为单位存储李   <李>文件系统需要有索引区,方便查找一个文件分成的多个块存在了什么位置李   <李>如果有文件近期经常被读写,需要有缓存层   <李>文件应该用文件夹的形式组织起来方便管理和查询李   <李> Linux内核要在自己的内存里维护一套数据结构,保持哪些文件被哪些进程打开和使用李   
  

Linux里面一切皆文件,都有以下几种文件(从ls - l结果的第一位标识位可以看出来):

  
      <李>——表示普通文件   <李> d表示文件夹李   <李> c表示字符设备文件   <李> b表示块设备文件   <李> s表示套接字套接字文件   <李> l表示软链接李   
  


  

  

下面就以EXT系列格式为例来看一下文件是如果存在硬盘上的。首先文件会被分成一个个的块,分散得存在硬盘上,就需要一个索引结构来帮助我们找到这些块以及记录文件的一些元信息,这就是inode,其中我代表index.inode数据结构如下:

        struct ext4_inode {   __le16 i_mode;*//*文件模式   __le16 i_uid;/*低16位的所有者Uid */__le32 i_size_lo;/*大小的字节*/__le32 i_atime;/* */访问时间   __le32 i_ctime;/* */Inode改变时间   __le32 i_mtime;/* */修改时间   __le32 i_dtime;/*删除*/__le16 i_gid;/*低16位的组Id */__le16 i_links_count;/* */链接计数   __le32 i_blocks_lo;*//*块计数   __le32 i_flags;*//*文件标志   联盟{   结构体{   __le32 l_i_version;   }linux1;   结构体{   __u32 h_i_translator;   }hurd1;   结构体{   __u32 m_i_reserved1;   }masix1;   }osd1;/*操作系统依赖1 */__le32 i_block [EXT4_N_BLOCKS]; *//*指针块   __le32 i_generation;/*文件版本(NFS) */__le32 i_file_acl_lo;/*文件的ACL */__le32 i_size_high;   __le32 i_obso_faddr;*//*废弃片段地址   联盟{   结构体{   __le16 l_i_blocks_high;/* l_i_reserved1 */__le16 l_i_file_acl_high;   __le16 l_i_uid_high;/* */这两个字段   __le16 l_i_gid_high;/* reserved2 [0] */__le16 l_i_checksum_lo;/* crc32c (uuid + inum + inode) */__le16 l_i_reserved;   }linux2;   结构体{   __le16 h_i_reserved1;/*弃用片段数量/尺寸是删除ext4 */__u16 h_i_mode_high;   __u16 h_i_uid_high;   __u16 h_i_gid_high;   __u32 h_i_author;   }hurd2;   结构体{   __le16 h_i_reserved1;/*弃用片段数量/尺寸是删除ext4 */__le16 m_i_file_acl_high;   __u32 m_i_reserved2 [2];   }masix2;   }osd2;/*操作系统依赖2 */__le16 i_extra_isize;   __le16 i_checksum_hi;/* crc32c (uuid + inum + inode) */__le32 i_ctime_extra;/*额外修改时间(nsec & lt; & lt;2 |时代)*/__le32 i_mtime_extra;/*额外的修改时间(nsec & lt; & lt;2 |时代)*/__le32 i_atime_extra;/*额外的访问时间(nsec & lt; & lt;2 |时代)*/__le32 i_crtime;/*文件创建时间*/__le32 i_crtime_extra;/*额外FileCreationtime (nsec & lt; & lt;2 |时代)*/__le32 i_version_hi;/* */高32位64位版本   __le32 i_projid;*//*项目ID   };      

其中__le32 i_block [EXT4_N_BLOCKS]存储了到数据块的引用,EXT4_N_BLOCKS定义如下:

        #定义EXT4_NDIR_BLOCKS 12   #定义EXT4_IND_BLOCK EXT4_NDIR_BLOCKS   #定义EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)   #定义EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)   #定义EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)      

在ext2和ext3中i_block前12项存储了直接到数据块的引用,第13项存储的是到间接块的引用,在间接块里存储着数据块的位置,以此类推,第14项里存储着二次间接快的位置,第15项里存储着三次间接块的位置,如下图所示:

  

癓inux中的EXT系列文件系统格式详解"

  

不难看出,对于大文件,需要多次读取硬盘才能找到相应的块,在ext4中就提出了区段树来解决这一问题,其核心思想就是把连续的块用开始位置加块的个数来表示,不再是一个一个去记录每一个块的位置,这样就能节约存储空间。首先,它将i_block中原来415=60字节的空间换成了一个程度头(ext4_extent_header)加4个条目(ext4_extent),因为ext4_extent_header和ext4_extent都是占用了12个字节.ee_len中的第一个钻头用来判断是否初始化,所以它还能存储最大32 k个数,所以一个程度条目里最大可以存32 k4k=128的数据,如果一个文件大于4128米=512米或者这个文件被分散到多于4个不连续的块中存储,我们就需要扩展inode中的i_block结构。它的入口就程度要从ext4_extent被换成ext4_extent_idx结构体,它所指向的是一个块,有4 k字节,除去头占用的12字节,还能存340个ext4_extent,最大可以存340128 m=42.5 g的数据。可以看出这种索引结构在文件用连续的块存储时非常高效。

Linux中的EXT系列文件系统格式详解