热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

这篇文章主要给大家介绍了关于Linux中EXT系列文件系统格式的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Linux系统具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

Linux文件系统

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

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

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

  • - 表示普通文件
  • d 表示文件夹
  • c 表示字符设备文件
  • b 表示块设备文件
  • s 表示套接字socket文件
  • l 表示软链接

Inode和块存储

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

struct ext4_inode {
 __le16 i_mode;  /* File mode */
 __le16 i_uid;  /* Low 16 bits of Owner Uid */
 __le32 i_size_lo; /* Size in bytes */
 __le32 i_atime; /* Access time */
 __le32 i_ctime; /* Inode Change time */
 __le32 i_mtime; /* Modification time */
 __le32 i_dtime; /* Deletion Time */
 __le16 i_gid;  /* Low 16 bits of Group Id */
 __le16 i_links_count; /* Links count */
 __le32 i_blocks_lo; /* Blocks count */
 __le32 i_flags; /* File flags */
 union {
  struct {
   __le32 l_i_version;
  } linux1;
  struct {
   __u32 h_i_translator;
  } hurd1;
  struct {
   __u32 m_i_reserved1;
  } masix1;
 } osd1;    /* OS dependent 1 */
 __le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
 __le32 i_generation; /* File version (for NFS) */
 __le32 i_file_acl_lo; /* File ACL */
 __le32 i_size_high;
 __le32 i_obso_faddr; /* Obsoleted fragment address */
 union {
  struct {
   __le16 l_i_blocks_high; /* were l_i_reserved1 */
   __le16 l_i_file_acl_high;
   __le16 l_i_uid_high; /* these 2 fields */
   __le16 l_i_gid_high; /* were reserved2[0] */
   __le16 l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */
   __le16 l_i_reserved;
  } linux2;
  struct {
   __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
   __u16 h_i_mode_high;
   __u16 h_i_uid_high;
   __u16 h_i_gid_high;
   __u32 h_i_author;
  } hurd2;
  struct {
   __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
   __le16 m_i_file_acl_high;
   __u32 m_i_reserved2[2];
  } masix2;
 } osd2;    /* OS dependent 2 */
 __le16 i_extra_isize;
 __le16 i_checksum_hi; /* crc32c(uuid+inum+inode) BE */
 __le32 i_ctime_extra; /* extra Change time (nsec <<2 | epoch) */
 __le32 i_mtime_extra; /* extra Modification time(nsec <<2 | epoch) */
 __le32 i_atime_extra; /* extra Access time (nsec <<2 | epoch) */
 __le32 i_crtime; /* File Creation time */
 __le32 i_crtime_extra; /* extra FileCreationtime (nsec <<2 | epoch) */
 __le32 i_version_hi; /* high 32 bits for 64-bit version */
 __le32 i_projid; /* Project ID */
};

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

#define EXT4_NDIR_BLOCKS 12
#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
#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的数据。可以看出这种索引结构在文件用连续的块存储时非常高效。

struct ext4_extent_header {
 __le16 eh_magic; /* ext4 extents标识:0xF30A */
 __le16 eh_entries; /* 当前层级中有效节点的数目 */
 __le16 eh_max; /* 当前层级中最大节点的数目 */
 __le16 eh_depth; /* 当前层级在树中的深度,0为叶子节点,即数据节点,>0代表索引节点 */
 __le32 eh_generation; 
}
struct ext4_extent {
 __le32 ee_block; /* extent的起始block逻辑序号 */
 __le16 ee_len; /* extent包含的block个数 */
 __le16 ee_start_hi; /*extent起始block的物理地址的高16位 */
 __le32 ee_start_lo; /*extent起始block的物理地址的低32位 */
};//数据节点中的extent_body格式
struct ext4_extent_idx {
 __le32 ei_block; /* 索引所覆盖的文件范围的起始block的逻辑序号 */
 __le32 ei_leaf_lo; /* 存放下一级extents的block的物理地址的低32位 */ 
 __le16 ei_leaf_hi; /* 存放下一级extents的block的物理地址的高16位 */
 __u16 ei_unused;

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

举一个/var/log/messages文件的例子如下图所示:

inode位图和块位图

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

硬链接和软链接

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

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。


推荐阅读
  • Linuxchmod目录权限命令图文详解在Linux文件系统模型中,每个文件都有一组9个权限位用来控制谁能够读写和执行该文件的内容。对于目录来说,执行位的作用是控制能否进入或者通过 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文主要讨论了在xps15上安装双系统win10和MacOS后,win10无法正常更新的问题。分析了可能的引导问题,并提供了解决方法。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 树莓派Linux基础(一):查看文件系统的命令行操作
    本文介绍了在树莓派上通过SSH服务使用命令行查看文件系统的操作,包括cd命令用于变更目录、pwd命令用于显示当前目录位置、ls命令用于显示文件和目录列表。详细讲解了这些命令的使用方法和注意事项。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
author-avatar
柳绿海蓝
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有