Linux Ext2/3/4文件系统

前言

这篇文章介绍了Linux文件系统的一些基础知识:Linux 文件系统简介,接下来主要介绍 Ext( Ext2/3/4) 系列文件系统。

一、Linux文件系统简介

1.1 简介

Linux文件系统是在磁盘驱动器或分区上的一个有结构的文件集合。它用于数据管理,每个分区包含特定的数据。系统化的数据存储的目的是可以快速访问文件。它管理所有的信息,包括文件大小、创建日期、文件名等。

通用计算机系统需要系统地存储数据,这样我们就可以在更短的时间内轻松访问文件。它将数据存储在硬盘(HDD)或某种等效的存储类型上。

Linux文件系统包含以下部分:
(1)根目录(/)
(2)一种特定的数据存储格式(EXT3、EXT4、BTRFS、XFS等)
(3)具有特定文件系统的分区或逻辑卷。

Linux文件系统格式支持Windows操作系统。它支持Ext2、Ext3、Ext4、JFS、ReiserFS、XFS、btrfs和交换文件系统。如下图所示:
在这里插入图片描述

1.2 Linux File System Structure

Linux文件系统具有分层的文件结构,包含根目录及其子目录。所有其他目录都可以从根目录访问。一个分区通常只有一个文件系统,但可能有多个文件系统。

文件系统的设计目的是管理和提供非易失性存储数据的空间。

所有的文件系统都需要提供命名空间,即命名和组织方法。这定义了文件的命名方式,具体包括文件名的长度以及可以用于文件名的字符子集。它还定义了磁盘上数据的逻辑结构,例如使用目录来组织文件,而不是将它们全部混在一个巨大的文件集中。

一旦命名空间被定义,就需要元数据结构来为该命名空间提供逻辑基础。这包括支持分层目录结构所需的数据结构;用于确定磁盘上哪些空间块已被使用和可用的结构;允许维护文件和目录名称的结构;有关文件的信息,如文件大小、创建时间、修改时间和最后访问时间;以及文件数据在磁盘上的位置。其他元数据用于存储有关磁盘分割的高级信息,例如逻辑卷和分区。这些高级元数据及其所代表的结构包含了存储在驱动器或分区上的文件系统的信息,但与文件系统元数据是独立且相互独立的。

文件系统还需要提供一个应用程序编程接口(API),用于访问操作文件和目录等文件系统对象的系统函数调用。API提供了创建、移动和删除文件等任务的功能。它还提供了确定文件在文件系统上放置位置的算法。这些算法可以考虑到诸如速度或最小化磁盘碎片化等目标。

现代文件系统还提供了安全模型,即定义对文件和目录的访问权限的方案。Linux文件系统安全模型有助于确保用户只能访问自己的文件,而不能访问其他用户或操作系统本身的文件。

最后一个构建块是实现所有这些功能所需的软件。Linux使用两部分软件实现来提高系统和程序员的效率。

Linux文件系统包含由两部分组成的文件系统软件实现体系结构,如下图所示:
在这里插入图片描述
这两部分实现中的第一部分是Linux虚拟文件系统。这个虚拟文件系统为内核和开发人员提供了一套单一的命令,用于访问所有类型的文件系统。虚拟文件系统软件调用所需的特定设备驱动程序,以与各种类型的文件系统进行接口。文件系统特定的设备驱动程序是实现的第二部分。设备驱动程序将标准的文件系统命令解释为特定于分区或逻辑卷上的文件系统类型的命令。

1.3 Directory Structure

目录帮助我们存储文件并在需要时定位它们。目录也被称为文件夹,因为可以将其类比为物理桌面上存放文件的文件夹。在Linux和其他一些操作系统中,目录可以按照树状层次结构进行组织。

Linux的目录结构在Linux FHS(文件系统层次结构标准)中有详细的文档和定义。要访问这些目录,可以通过使用斜杠“/”将目录逐级连接起来的方式来引用它们,例如/var/spool/mail和/var/log。这些被称为路径。

下表列出了一些标准、定义明确且众所周知的顶级Linux目录及其用途:

/(根文件系统):这是顶级文件系统目录。在挂载其他文件系统之前,它必须包含启动Linux系统所需的所有文件。系统启动后,每个其他文件系统都会挂载到一个明确定义且标准的挂载点上,这些挂载点位于根文件系统目录之后。
/boot:包含启动Linux计算机所需的静态内核、引导加载程序配置文件和可执行文件。
/bin:该目录包含用户可执行文件。
/dev:该目录包含连接到系统的所有硬件设备的设备文件。这些不是设备驱动程序,而是指示系统上所有设备并提供对这些设备的访问的文件。
/etc:包含主机系统的本地系统配置文件。
/lib:包含启动系统所需的共享库文件。
/home:用于存储用户文件的主目录。每个用户在/home目录下都有一个子目录。
/mnt:这是一个临时挂载点,用于在管理员工作或修复文件系统时使用的基本文件系统。
/media:用于挂载外部可移动媒体设备,如可能连接到主机的USB闪存驱动器。
/opt:包含可选文件,如供应商提供的必须放置在此处的应用程序。
/root:这是root用户的主目录。请注意,它不是'/'(根)文件系统。
/tmp:这是操作系统和多个程序用于存储临时文件的临时目录。用户也可以暂时在此处存储文件。请注意,该目录中的文件可能随时被删除,而无需事先通知。
/sbin:这些是系统二进制文件。它们是用于系统管理的可执行文件。
/usr:这些是只读且可共享的文件,包括可执行库和二进制文件、man文件以及多种文档类型。
/var:这里保存着可变数据文件。它可以包含MySQL、日志文件、其他数据库文件、电子邮件收件箱、Web服务器数据文件等等。

如下图所示:
在这里插入图片描述

二、Ext2/3/4文件系统

文件系统具有以下功能:
(1)数据存储:任何文件系统的主要功能是提供一个结构化的存储和检索数据的地方。
(2)命名空间:一种命名和组织方法,为命名和组织数据提供规则。
(3)安全模型:定义访问权限的方案。
(4)API:用于操作文件系统对象(如目录和文件)的系统函数调用。
(5)实现:实现上述功能的软件。

本文着重介绍列表中的第一项,并探讨提供EXT文件系统中数据存储的逻辑框架的元数据结构。

2.1 Minix

尽管EXT文件系统是为Linux编写的,但它的根源可以追溯到Minix操作系统和Minix文件系统。Minix文件系统比Linux早约五年,于1987年首次发布。如果我们从Minix的根源开始,了解EXT文件系统家族的历史和技术演变,就能更容易地理解EXT4文件系统。

在编写最初的Linux内核时,Linus Torvalds需要一个文件系统,但他当时并不想编写一个新的文件系统。因此,他简单地包含了Minix文件系统,该文件系统由Andrew S. Tanenbaum编写,是Tanenbaum的Minix操作系统的一部分。Minix是一个类Unix的操作系统,是为教育目的而编写的。它的代码是自由可用的,并且获得了适当的许可,使得Torvalds能够将其包含在他的第一个Linux版本中。

Minix具有以下结构,其中大部分位于生成文件系统的分区中:
(1)安装在硬盘的第一个扇区上的引导扇区。引导块包括一个非常小的引导记录和一个分区表。
(2)每个分区中的第一个块是超级块,其中包含定义其他文件系统结构并在分区分配的物理磁盘上定位它们的元数据。
(3)一个inode位图块,用于确定哪些inode已被使用,哪些是空闲的。
(4)inode,它们在磁盘上有自己的空间。每个inode包含有关一个文件的信息,包括文件数据块(即属于文件的区域)的位置。
(5)一个区域位图,用于跟踪已使用和空闲的数据区域。
(6)一个数据区,实际存储数据的地方。

如下图所示:
在这里插入图片描述

对于这两种位图,一个位表示一个特定的数据区域或一个特定的inode。如果该位为零,表示该数据区域或inode是空闲的,可供使用,但如果该位为一,则表示该数据区域或inode正在使用中。

什么是inode?inode是磁盘上的一个256字节块,用于存储有关文件的数据。这包括文件的大小、文件的用户和组所有者的用户ID、文件的模式(即访问权限)以及三个时间戳,分别指定文件的最后访问时间、最后修改时间和inode中的数据最后修改的时间。

inode还包含指向文件数据在硬盘上位置的数据。在Minix和EXT1-3文件系统中,这是一个数据区域或数据块的列表。Minix文件系统的inode支持九个数据块,其中包括七个直接块和两个间接块。

// linux-3.10/include/uapi/linux/minix_fs.h

/*
 * This is the original minix inode layout on disk.
 * Note the 8-bit gid and atime and ctime.
 */
struct minix_inode {
	__u16 i_mode;
	__u16 i_uid;
	__u32 i_size;
	__u32 i_time;
	__u8  i_gid;
	__u8  i_nlinks;
	__u16 i_zone[9];
};

/*
 * The new minix inode has all the time entries, as well as
 * long block numbers and a third indirect block (7+1+1+1
 * instead of 7+1+1). Also, some previously 8-bit values are
 * now 16-bit. The inode is now 64 bytes instead of 32.
 */
struct minix2_inode {
	__u16 i_mode;
	__u16 i_nlinks;
	__u16 i_uid;
	__u16 i_gid;
	__u32 i_size;
	__u32 i_atime;
	__u32 i_mtime;
	__u32 i_ctime;
	__u32 i_zone[10];
};

如下图所示:
在这里插入图片描述

2.2 EXT

最初的EXT文件系统(Extended)是由Rémy Card编写的,并于1992年随Linux一起发布,旨在克服Minix文件系统的一些大小限制。主要的结构性变化发生在文件系统的元数据上,它基于Unix文件系统(UFS),也称为伯克利快速文件系统(FFS)。关于EXT文件系统的可验证的已发表信息非常有限,这可能是因为它存在重大问题,并且很快被EXT2文件系统所取代。

在这里插入图片描述

2.3 EXT2

Ext2(第二扩展文件系统)是1993年引入的文件系统,它是第一个商用文件系统,旨在克服Ext文件系统的限制。Ext2没有日志功能,并且推荐在闪存驱动器和USB设备上使用。Ext2支持的单个文件大小为2TB,具体容量取决于块大小,可以从4TB到32TB不等。

在这里插入图片描述
Ext2是一种基本且可移植的文件系统。这种文件系统适用于闪存设备,如SD卡和USB设备,因为它没有日志功能,可以减少写入操作的开销,提高性能。

与Minix类似,EXT2在安装的硬盘的第一个扇区中有一个引导扇区,其中包括一个非常小的引导记录和一个分区表。然后,在引导扇区之后有一些保留空间,它跨越了引导记录和硬盘上的第一个分区之间的空间,通常位于下一个柱面边界上。GRUB2(可能还有GRUB1)使用这个空间作为其引导代码的一部分。

每个EXT2分区中的空间被划分为柱面组,以更精细地管理数据空间。根据我的经验,柱面组的大小通常约为8MB。下面的图显示了柱面组的基本结构。柱面中的数据分配单位是块,通常大小为4K。
在这里插入图片描述
柱面组中的第一个块是超级块(superblock),它包含了定义其他文件系统结构并在物理磁盘上定位它们的元数据。在分区中的一些额外组中会有备份超级块,但并非所有组都有。可以使用诸如dd之类的磁盘工具将备份超级块的内容复制到主超级块来替换损坏的超级块。

每个柱面组都有自己的索引节点位图(inode bitmap),用于确定该组中已使用和空闲的索引节点。每个组都有自己的索引节点空间。每个索引节点包含有关一个文件的信息,包括文件所属的数据块的位置。块位图(block bitmap)用于跟踪文件系统中已使用和空闲的数据块。

EXT文件系统实现了数据分配策略,确保文件的碎片化最小化。减少碎片化可以提高文件系统的性能。这些策略在下面的EXT4部分中进行了描述。

EXT2文件系统最大的问题是,在某些情况下,它可能需要花费很多小时来在崩溃后进行恢复,因为fsck(文件系统检查)程序需要很长时间来定位和纠正文件系统中的任何不一致之处。

// fs/ext2/ext2.h

/*
 * Constants relative to the data blocks
 */
#define	EXT2_NDIR_BLOCKS		12
#define	EXT2_IND_BLOCK			EXT2_NDIR_BLOCKS
#define	EXT2_DIND_BLOCK			(EXT2_IND_BLOCK + 1)
#define	EXT2_TIND_BLOCK			(EXT2_DIND_BLOCK + 1)
#define	EXT2_N_BLOCKS			(EXT2_TIND_BLOCK + 1)

/*
 * Structure of an inode on the disk
 */
struct ext2_inode {
	__le16	i_mode;		/* File mode */
	__le16	i_uid;		/* Low 16 bits of Owner Uid */
	__le32	i_size;		/* Size in bytes */
	__le32	i_atime;	/* Access time */
	__le32	i_ctime;	/* Creation 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;	/* Blocks count */
	__le32	i_flags;	/* File flags */
	.......
	__le32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
	......

如下图所示:
在这里插入图片描述
索引节点中有指向文件数据的前12个块的指针。还有指向间接块(包含指向下一组块的指针)、双重间接块和三重间接块的指针。

因此,在ext2中有一个具有15个指针的结构。指针1到12指向直接块,指针13指向一个间接块,指针14指向一个双重间接块,指针15指向一个三重间接块。

2.4 EXT3

Ext3是指第三扩展文件系统。这个文件日志系统被多个Linux发行版使用。它可以跟踪所有对Ext3所做的更改,提高可靠性并减少可能的文件系统损坏。此外,它还允许你从Ext2升级而无需备份和恢复数据。
如下图所示:
在这里插入图片描述
Ext2和Ext3使用e2fsprogs作为标准工具,它使得这两个文件系统之间的转换更加简单和顺畅。Ext3设计了一些新功能,如日志、在线文件系统扩展和HTree索引大型目录。与其他Linux文件系统相比,Ext3使用较少的CPU资源。它相对较安全,并且可以轻松恢复数据。

EXT3文件系统的主要目标是克服在文件更新操作期间发生不当关闭导致磁盘结构损坏时,fsck程序需要花费大量时间进行完全恢复的问题。EXT文件系统的唯一改进是添加了日志(journal),它提前记录将对文件系统执行的更改。磁盘结构的其余部分与EXT2相同。

在EXT3中,日志不再直接将数据写入磁盘的数据区域,而是将文件数据和元数据一起写入磁盘上的指定区域。一旦数据安全地存储在硬盘上,它可以与目标文件合并或附加,几乎不会丢失数据。当数据提交到磁盘的数据区域时,日志将更新,以便在所有日志中的数据都提交之前,文件系统在系统故障时保持一致状态。在下一次启动时,文件系统将检查不一致性,并将仍留在日志中的数据提交到磁盘的数据区域,以完成对目标文件的更新。

日志功能确实会降低数据写入性能,但日志有三个选项可供用户选择性能和数据完整性之间的平衡。我个人更偏向于安全,因为我的环境不需要频繁的磁盘写入活动。

日志功能大大减少了在故障后检查硬盘不一致性所需的时间,最多只需几分钟,而不是几小时(甚至几天)。多年来,我遇到过许多导致系统崩溃的问题。细节可以填写另一篇文章,但可以说其中大多数是自己造成的,例如拔掉电源插头。幸运的是,使用带有日志功能的EXT文件系统后,引导恢复时间缩短到两三分钟。此外,自从我开始使用带有日志功能的EXT3文件系统以来,我从未遇到过数据丢失的问题。

EXT3的日志功能可以关闭,此时它将作为EXT2文件系统运行。日志本身仍然存在,但是为空并未使用。只需使用mount命令重新挂载分区,使用type参数指定EXT2。根据你使用的文件系统,你可能可以在命令行中执行此操作,但你可以在/etc/fstab文件中更改类型说明符,然后重新启动。我强烈建议不要将EXT3文件系统作为EXT2挂载,因为这会增加数据丢失和恢复时间延长的风险。

现有的EXT2文件系统可以通过添加日志来升级为EXT3,使用以下命令:

tune2fs -j /dev/sda1

其中,/dev/sda1是驱动器和分区的标识符。确保在/etc/fstab中更改文件类型说明符,并重新挂载分区或重新启动系统以使更改生效。

Linux 4.3主线版本移除了 ext3文件系统:
Ext3文件系统已从Linux核心存储库中移除。这个移除的原因是,Ext3文件系统已被Ext4文件系统完全支持,并且主要的发行版已经长期使用Ext4来挂载Ext3文件系统。随着Ext4的稳定,维护者们认为Ext3代码库是多余的重复代码,应该消失。

ext2文件系统也可以被ext4取代,但似乎没有去这样做。ext2非常简单,代码量不到10,000行;而ext3和相关的JBD日志代码总共有28,000行,而ext4和JBD2的代码总量接近60,000行。ext2的简单性使其成为开发人员进行实验的良好文件系统,而且它的维护成本几乎为零。因此,短期内没有真正的理由去除它。

2.5 EXT4

Ext4是对Ext2的一系列向后兼容的扩展,也是大多数Linux发行版使用的文件系统。Ext4也得到其他操作系统的支持,包括Windows、Free BSD、macOS和KolibriOS(只读)。
如下图所示:
在这里插入图片描述
Ext4最初被引入以扩展存储限制并提高系统性能。与先前的Ext文件系统相比,Ext4可以支持高达1EB的卷大小,并且对于单个文件,使用标准4K块大小可以支持高达16TB的大小。

EXT4文件系统主要改进了性能、可靠性和容量。为了提高可靠性,添加了元数据和日志校验和。为了满足各种关键任务的要求,通过添加纳秒级别的时间间隔来改进了文件系统的时间戳。

在EXT4中,数据分配从固定块改为范围(extent)。一个范围由其在硬盘上的起始和结束位置来描述。这使得可以在单个索引节点指针条目中描述非常长的物理连续文件,从而可以显著减少描述大型文件中所有数据位置所需的指针数量。EXT4还实施了其他分配策略,以进一步减少碎片化。

EXT4通过将新创建的文件分散到磁盘上,使其不会像早期的许多PC文件系统那样聚集在磁盘开始的一个位置。文件分配算法尽可能均匀地将文件分布在柱面组中,并在需要碎片化时尽量将不连续的文件范围与同一文件中的其他范围保持接近,以尽量减少磁头寻道和旋转延迟。当创建新文件或扩展现有文件时,还使用其他策略来预分配额外的磁盘空间。这有助于确保扩展文件时不会自动导致碎片化。新文件永远不会分配在现有文件之后,这也可以防止现有文件的碎片化。

除了数据在磁盘上的实际位置外,EXT4还使用一些功能性策略,如延迟分配,允许文件系统在为其分配空间之前收集要写入磁盘的所有数据。这可以提高数据空间连续性的可能性。

旧的EXT文件系统,如EXT2和EXT3,可以以EXT4的方式挂载,以获得一些轻微的性能提升。不幸的是,这需要关闭EXT4的一些重要新功能,因此我建议不要这样做。

自Fedora 14以来,EXT4一直是Fedora的默认文件系统。可以按照Fedora文档中的说明将EXT3文件系统升级为EXT4,但由于残留的EXT3元数据结构,性能仍会受到影响。从EXT3升级到EXT4的最佳方法是备份目标文件系统分区上的所有数据,使用mkfs命令将空的EXT4文件系统写入分区,然后从备份中恢复所有数据。

在Linux内核的2.6.19版本中,包含了ext4的初步开发版本。2008年10月11日,将ext4标记为稳定代码的补丁被合并到Linux 2.6.28的源代码库中,标志着开发阶段的结束并推荐采用ext4。

三、EXT Inode

索引节点(inode)是EXT文件系统中元数据的关键组成部分,如前所述。下图显示了索引节点与存储在硬盘上的数据之间的关系。该图是单个文件的目录和索引节点,该文件在这种情况下可能高度碎片化。EXT文件系统积极努力减少碎片化,因此很不可能会看到具有这么多间接数据块或范围的文件。实际上,正如下面所述,EXT文件系统的碎片化非常低,因此大多数索引节点只会使用一个或两个直接数据指针,而不使用任何间接指针。
在这里插入图片描述
索引节点(inode)不包含文件的名称。通过目录项访问文件,目录项本身是文件的名称,并包含指向索引节点的指针。该指针的值是索引节点号。文件系统中的每个索引节点都有一个唯一的ID号,但是在同一台计算机上的其他文件系统(甚至是同一块硬盘)上的索引节点可以具有相同的索引节点号。

索引节点包含有关文件的元数据,包括其类型和权限以及其大小。索引节点还包含用于描述数据块或范围在柱面组数据部分中的位置和长度的15个指针的空间。其中12个指针提供对数据范围的直接访问,应足以处理大多数文件。然而,对于存在较大碎片化的文件,需要具备一些额外的能力,以间接节点的形式提供支持。

间接节点是文件系统中仅用于描述数据而不用于存储元数据的普通数据块,因此可以支持超过15个条目。例如,4K的块大小可以支持512个4字节的间接节点,允许单个文件具有12(直接)+ 512(间接)= 524个范围。还支持双重和三重间接节点支持,但我们大多数人很少会遇到需要那么多范围的文件。

参考资料

https://www.javatpoint.com/linux-file-system
https://opensource.com/article/17/5/introduction-ext4-filesystem
https://www.easeus.com/partition-master/ext2-ext3-ext4-file-system-format-and-difference.html

相关推荐

  1. 制作ubuntu-base-23.10-base-armhf的根文件系统rootfs

    2024-06-09 22:06:03       59 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-09 22:06:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-09 22:06:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-09 22:06:03       82 阅读
  4. Python语言-面向对象

    2024-06-09 22:06:03       91 阅读

热门阅读

  1. 给自己Linux搞个『回收站』,防止文件误删除

    2024-06-09 22:06:03       38 阅读
  2. 前端通用样式调整方法(整理版)

    2024-06-09 22:06:03       40 阅读
  3. web 前端开发培训:深入探索与实战应用

    2024-06-09 22:06:03       34 阅读
  4. 线程+线程池+锁

    2024-06-09 22:06:03       39 阅读
  5. 多维vector定义

    2024-06-09 22:06:03       35 阅读
  6. 计算各聚类中心

    2024-06-09 22:06:03       27 阅读
  7. 程序代码问题随时记录

    2024-06-09 22:06:03       29 阅读
  8. 栈和队列的转换

    2024-06-09 22:06:03       34 阅读
  9. 全面解析LG webOS:从开发到智能电视的演进

    2024-06-09 22:06:03       40 阅读