• 售前

  • 售后

热门帖子
入门百科

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

[复制链接]
愿为素心人 显示全部楼层 发表于 2021-10-26 13:14:40 |阅读模式 打印 上一主题 下一主题
Linux文件体系


常见的硬盘如上图所示,每个盘片分多个磁道,每个磁道分多个扇区,每个扇区512字节,是硬盘的最小存储单元,但是在利用体系层面会将多个扇区构成块(block),是利用体系存储数据的最小单元,通常是8个扇区构成4K字节的块。
对于Linux文件体系,必要思量以下几点:
      
  • 文件体系必要有严酷的构造情势,使文件能够以块为单位存储  
  • 文件体系必要有索引区,方便查找一个文件分成的多个块存在了什么位置  
  • 如果有文件近期常常被读写,必要有缓存层  
  • 文件应该用文件夹的情势构造起来方便管理和查询  
  • Linux内核要在本身的内存里维护一套数据布局,保持哪些文件被哪些历程打开和使用
Linux里面统统皆文件,都有以下几种文件(从ls -l效果的第一位标识位可以看出来):
      
  • - 表示普通文件  
  • d 表示文件夹  
  • c 表示字符装备文件  
  • b 表示块装备文件  
  • s 表示套接字socket文件  
  • l 表示软链接
Inode和块存储

下面就以EXT系列格式为例来看一下文件是如果存在硬盘上的。首先文件会被分成一个个的块,分散得存在硬盘上,就必要一个索引布局来资助我们找到这些块以及记录文件的一些元信息,这就是inode,其中i代表index。inode数据布局如下:
  1. struct ext4_inode {
  2. __le16 i_mode;  /* File mode */
  3. __le16 i_uid;  /* Low 16 bits of Owner Uid */
  4. __le32 i_size_lo; /* Size in bytes */
  5. __le32 i_atime; /* Access time */
  6. __le32 i_ctime; /* Inode Change time */
  7. __le32 i_mtime; /* Modification time */
  8. __le32 i_dtime; /* Deletion Time */
  9. __le16 i_gid;  /* Low 16 bits of Group Id */
  10. __le16 i_links_count; /* Links count */
  11. __le32 i_blocks_lo; /* Blocks count */
  12. __le32 i_flags; /* File flags */
  13. union {
  14.   struct {
  15.    __le32 l_i_version;
  16.   } linux1;
  17.   struct {
  18.    __u32 h_i_translator;
  19.   } hurd1;
  20.   struct {
  21.    __u32 m_i_reserved1;
  22.   } masix1;
  23. } osd1;    /* OS dependent 1 */
  24. __le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
  25. __le32 i_generation; /* File version (for NFS) */
  26. __le32 i_file_acl_lo; /* File ACL */
  27. __le32 i_size_high;
  28. __le32 i_obso_faddr; /* Obsoleted fragment address */
  29. union {
  30.   struct {
  31.    __le16 l_i_blocks_high; /* were l_i_reserved1 */
  32.    __le16 l_i_file_acl_high;
  33.    __le16 l_i_uid_high; /* these 2 fields */
  34.    __le16 l_i_gid_high; /* were reserved2[0] */
  35.    __le16 l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */
  36.    __le16 l_i_reserved;
  37.   } linux2;
  38.   struct {
  39.    __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
  40.    __u16 h_i_mode_high;
  41.    __u16 h_i_uid_high;
  42.    __u16 h_i_gid_high;
  43.    __u32 h_i_author;
  44.   } hurd2;
  45.   struct {
  46.    __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
  47.    __le16 m_i_file_acl_high;
  48.    __u32 m_i_reserved2[2];
  49.   } masix2;
  50. } osd2;    /* OS dependent 2 */
  51. __le16 i_extra_isize;
  52. __le16 i_checksum_hi; /* crc32c(uuid+inum+inode) BE */
  53. __le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
  54. __le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */
  55. __le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
  56. __le32 i_crtime; /* File Creation time */
  57. __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
  58. __le32 i_version_hi; /* high 32 bits for 64-bit version */
  59. __le32 i_projid; /* Project ID */
  60. };
复制代码
其中__le32 i_block[EXT4_N_BLOCKS]存储了到数据块的引用,EXT4_N_BLOCKS定义如下:
  1. #define EXT4_NDIR_BLOCKS 12
  2. #define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
  3. #define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
  4. #define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
  5. #define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)
复制代码
在ext2和ext3中i_block前12项存储了直接到数据块的引用,第13项存储的是到间接块的引用,在间接块里存储着数据块的位置,以此类推,第14项里存储着二次间接快的位置,第15项里存储着三次间接块的位置,如下图所示:

不丢脸出,对于大文件,必要多次读取硬盘才能找到相应的块,在ext4中就提出了Extents Tree来办理这一题目,其核心思想就是把一连的块用开始位置加块的个数来表示,不再是一个一个去记录每一个块的位置,如许就能节省存储空间。首先,它将i_block中原来415=60字节的空间换成了一个extent header(ext4_extent_header)加4个extent entry(ext4_extent),由于ext4_extent_header和ext4_extent都是占用了12字节。ee_len中的第一个bit用来判断是否初始化,以是它还能存储最大32K个数,以是一个extent entry里最大可以存32K4K=128M的数据,如果一个文件大于4128M=512M大概这个文件被分散到多于4个不一连的块中存储,我们就必要扩展inode中的i_block布局。它的extent entry就要从ext4_extent被换成ext4_extent_idx布局体,它所指向的是一个块,有4K字节,除去header占用的12字节,还能存340个ext4_extent,最大可以存340128M=42.5G的数据。可以看出这种索引布局在文件用一连的块存储时非常高效。
  1. struct ext4_extent_header {
  2. __le16 eh_magic; /* ext4 extents标识:0xF30A */
  3. __le16 eh_entries; /* 当前层级中有效节点的数目 */
  4. __le16 eh_max; /* 当前层级中最大节点的数目 */
  5. __le16 eh_depth; /* 当前层级在树中的深度,0为叶子节点,即数据节点,>0代表索引节点 */
  6. __le32 eh_generation;
  7. }
  8. struct ext4_extent {
  9. __le32 ee_block; /* extent的起始block逻辑序号 */
  10. __le16 ee_len; /* extent包含的block个数 */
  11. __le16 ee_start_hi; /*extent起始block的物理地址的高16位 */
  12. __le32 ee_start_lo; /*extent起始block的物理地址的低32位 */
  13. };//数据节点中的extent_body格式
  14. struct ext4_extent_idx {
  15. __le32 ei_block; /* 索引所覆盖的文件范围的起始block的逻辑序号 */
  16. __le32 ei_leaf_lo; /* 存放下一级extents的block的物理地址的低32位 */
  17. __le16 ei_leaf_hi; /* 存放下一级extents的block的物理地址的高16位 */
  18. __u16 ei_unused;
  19. };//索引节点中的extent_body格式
复制代码
举一个/var/log/messages文件的例子如下图所示:

inode位图和块位图

硬盘上会有专门存放块数据的地区也会有存放inode的地区,但是当我们要新建一个文件时,就必要知道哪个inode地区和哪个块是空的,这就必要分别用一个块来存储inode位图和一个块来存储块位图,每一个bit为1表示占用,为0表示未占用。但是一个块最多有4K*8=32K个位,也就最多能表示32K个块的状态,以是必要让这些块构成一个块组,来搭出更大的体系。
硬链接和软链接

硬链接与原文件共用一个inode,且inode不能跨文件体系,以是硬链接也不能跨文件体系。

软链接有本身inode,只是打开文件时是指向另外一个文件,以是可以跨文件体系且当原文件被删除后仍存在。

总结
以上就是这篇文章的全部内容了,渴望本文的内容对大家的学习大概工作具有一定的参考学习价值,谢谢大家对草根技术分享的支持。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作