【Linux】Linux Ext2文件系统

article/2025/10/14 17:06:40

下面以Linux的Ext2为例介绍文件系统的组成。

Ext2采用了分立式目录结构,即一个文件的目录分为目录项和索引节点两个部分。

 

Ext2的索引节点

在一个实际分立式目录的文件系统中,索引节点(inode)主要需要两部分内容来支持:一是inode结构;二是对于节点的操作函数。

Ext2的索引节点

Ext2的每个文件(或目录)都有唯一的i节点ext2_inode,它保存了一个文件所有与存储有关的属性。

Linux在文件include/linux/ext2_fs.h中定义的i节点结构ext2_inode如下:

struct ext2_inode {__le16	i_mode;		/* 文件模式 */__le16	i_uid;		/* 文件拥有者uid的低16位 */__le32	i_size;		/* 文件大小 */__le32	i_atime;	/* 最后访问时间 */__le32	i_ctime;	/* 创建时间 */__le32	i_mtime;	/* 修改时间 */__le32	i_dtime;	/* 删除时间 */__le16	i_gid;		/* 块组id的低16位 */__le16	i_links_count;	/* 链接计数,即文件别名的数目 */__le32	i_blocks;	/* 文件占用的存储块数 */__le32	i_flags;	/* 标志 */union {struct {__le32  l_i_reserved1;} linux1;struct {__le32  h_i_translator;} hurd1;struct {__le32  m_i_reserved1;} masix1;} osd1;				/* OS dependent 1 */__le32	i_block[EXT2_N_BLOCKS];/* 文件索引表 */__le32	i_generation;	/* File version (for NFS) */__le32	i_file_acl;	/* File ACL */__le32	i_dir_acl;	/* Directory ACL */__le32	i_faddr;	/* 碎片地址 */union {struct {__u8	l_i_frag;	/* 碎片数目 */__u8	l_i_fsize;	/* 碎片大小 */__u16	i_pad1;__le16	l_i_uid_high;	/* these 2 fields    */__le16	l_i_gid_high;	/* were reserved2[0] */__u32	l_i_reserved2;} linux2;struct {__u8	h_i_frag;	/* 碎片数目 */__u8	h_i_fsize;	/* 碎片大小 */__le16	h_i_mode_high;__le16	h_i_uid_high;__le16	h_i_gid_high;__le32	h_i_author;} hurd2;struct {__u8	m_i_frag;	/* 碎片数目 */__u8	m_i_fsize;	/* 碎片大小 */__u16	m_pad1;__u32	m_i_reserved2[2];} masix2;} osd2;				/* 与操作系统相关的数据 */
};

其中,最重要的成员i_mode和指针i_block[]。i_mode指定文件类型;而指针数组i_block[]则是文件索引表。

i_block[]指针数组的示意图如下:

i_block[]共有15项,其中前12项为直接指向文件数据块的指针,后3项分别为采用多级索引结构的“一次间接指针”、“二次间接指针”和“三次间接指针”。其作用与内存管理中的多级页表类似,便于大型文件的存储处理。

也就是说:如果文件比较小,其数据块少于12个,其数据块索引就放在i_block[]的前12项中,如果文件比较大,超过12个数据块就需要分配间接块来保存数据块索引。

Ext2的i节点操作函数

为了对Ext2的i节点进行操作,系统还定义了Ext2文件i节点的操作函数集:

struct inode_operations ext2_file_inode_operations = {.truncate = ext2_truncate,
#ifdef CONFIG_EXT2_FS_XATTR.setxattr = generic_setxattr,.getxattr = generic_getxattr,.listxattr = ext2_listxattr,.removexattr = generic_removexattr,
#endif.setattr = ext2_setattr,.permission = ext2_permission,
};

可以看到,这里操作集中没有熟悉的文件操作函数,这是因为这都是对磁盘文件的底层操作,文件还要再经一层乃至多层的封装才能变成我们所熟悉的函数。

 

Ext2的目录文件及目录项

Ext2的目录文件实质上是一个目录项列表,其中每一项都是一个ext2_dir_entry_2结构的数据。它所包含的主要信息:

  • 目录项中文件名所对应的文件i节点号;
  • 文件类型;
  • 文件名称。

在文件include/linux/ext2_fs.h中定义的目录项结构ext2_dir_entry_2如下:

struct ext2_dir_entry_2 {__le32	inode;			/* 文件的i节点号 */__le16	rec_len;		/* 目录项的长度 */__u8	name_len;		/* 文件名的长度 */__u8	file_type;        //文件类型char	name[EXT2_NAME_LEN];	/* 文件名 */
};

结构中的域file_type描述文件类型。不同文件类型的取值用枚举定义如下:

enum {EXT2_FT_UNKNOWN,EXT2_FT_REG_FILE,            //普通文件EXT2_FT_DIR,                 //目录EXT2_FT_CHRDEV,              //字符设备文件EXT2_FT_BLKDEV,              //块设备文件EXT2_FT_FIFO,                //管道文件EXT2_FT_SOCK,                //Sock文件EXT2_FT_SYMLINK,EXT2_FT_MAX
};

按照通常的概念,目录文件应该是ext2_dir_entry_2类型的数组,但Ext2没有这样做。为了用户方便,结构ext2_dir_entry_2中的文件名是一个可以根据文件名的长度变化的数组,这种做法就使得各个目录项的长度并不相等,从而难以用数组来组成目录文件。所以Ext2的目录文件采用一个比较特殊的链表结构,如下图:

在这种结构中,目录项是连续存放的,而目录项的连接则通过结构ext2_dir_entry_2中的域rec_len来实现的,即程序通过rec_len作为偏移量来查找下一个目录项。

每个目录文件中的前两项为代表目录自身的“.”和代表其上一级目录(父目录)的“..”。

每当用户需要打开一个文件需要打开一个文件时,首先要指定待打开文件的路径和名称,文件系统会根据路径和名称搜索对应的目录项;然后用该目录项中的i节点号找到该文件的i节点;最后通过访问i节点结构中的i_block[]数据块来访问文件。

目录项、索引节点与文件数据块之间的关系如下所示:

 

Ext2在磁盘上的存储结构

Ext2文件系统把它所占用的磁盘空间分成若干个块组,如下所示:

每个块组的内部结构如下图所示:

每个块组中都有一个内容完全相同的块——超级块,这个块保存着Ext2整个文件系统的信息。在超级块的后面,依次排序有:用来描述本块组信息的块组描述符表、用来表示本组内存储块使用情况的存储块管理位图、用来记录本块组所有i节点被占用情况的i节点管理位图、本块组的i节点表以及用来存储各种文件的数据块五个部分。

Ext2的超级块

像一本书需要一个前言一样,文件系统也需要有个类似的说明部分,但它说明的是文件系统基本信息,目的是使文件系统的使用者(操作系统)可以了解文件系统的结构、类型等,这个说明部分叫做文件系统的超级块。不同的文件系统具有不同的超级块。系统管理员及系统可以利用超级块中的信息来对文件系统进行维护。

照理说,每个文件系统只要有一个超级块就够了,但Ext2为了保险起见,在每一个块组中都配置了一个超级块。在正常情况下,Ext2只使用第一个块组(块组0)中的超级块,而其他块组中的超级块只是一个备份。

在文件include/linux/ext2_fs.h中定义的超级块数据结构ext2_super_block如下:

struct ext2_super_block {__le32	s_inodes_count;		/* 文件系统中节点的总数 */__le32	s_blocks_count;		/* 文件系统中块的总数 */__le32	s_r_blocks_count;	/* 超级用户保留块的数目 */__le32	s_free_blocks_count;	/* 空闲块的总数目 */__le32	s_free_inodes_count;	/* 空闲索引节点总数 */__le32	s_first_data_block;	/* 第一个数据块 */__le32	s_log_block_size;	/* Block size */__le32	s_log_frag_size;	/* Fragment size */__le32	s_blocks_per_group;	/* 每个块组中的块数 */__le32	s_frags_per_group;	/* 每组中的片数 */__le32	s_inodes_per_group;	/* 每组中的节点数 */__le32	s_mtime;		/* 文件系统的安装时间 */__le32	s_wtime;		/* 对超级块写操作的左后时间 */__le16	s_mnt_count;		/* 文件系统的安装计数 */__le16	s_max_mnt_count;	/* 文件系统的最大安装数 */__le16	s_magic;		/* 幻数 */__le16	s_state;		/* 文件系统的状态 */__le16	s_errors;		/* Behaviour when detecting errors */__le16	s_minor_rev_level; 	/* minor revision level */__le32	s_lastcheck;		/* time of last check */__le32	s_checkinterval;	/* max. time between checks */__le32	s_creator_os;		/* OS */__le32	s_rev_level;		/* Revision level */__le16	s_def_resuid;		/* Default uid for reserved blocks */__le16	s_def_resgid;		/* Default gid for reserved blocks */__le32	s_first_ino; 		/* First non-reserved inode */__le16   s_inode_size; 		/* size of inode structure */__le16	s_block_group_nr; 	/* 本超级块所在的块组号 */__le32	s_feature_compat; 	/* compatible feature set */__le32	s_feature_incompat; 	/* incompatible feature set */__le32	s_feature_ro_compat; 	/* readonly-compatible feature set */__u8	s_uuid[16];		/* 卷的128位uuid */char	s_volume_name[16]; 	/* 卷名 */char	s_last_mounted[64]; 	/* directory where last mounted */__le32	s_algorithm_usage_bitmap; /* For compression */__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */__u16	s_padding1;__u8	s_journal_uuid[16];	/* uuid of journal superblock */__u32	s_journal_inum;		/* inode number of journal file */__u32	s_journal_dev;		/* device number of journal file */__u32	s_last_orphan;		/* start of list of inodes to delete */__u32	s_hash_seed[4];		/* HTREE hash seed */__u8	s_def_hash_version;	/* Default hash version to use */__u8	s_reserved_char_pad;__u16	s_reserved_word_pad;__le32	s_default_mount_opts;__le32	s_first_meta_bg; 	/* First metablock block group */__u32	s_reserved[190];	/* Padding to the end of the block */
};

由上述定义中可知,Ext2中的超级块中主要具有如下一些内容:

  • 幻数。文件系统的一个标识,在安装文件系统时用于确认Ext2文件系统;
  • 文件系统的版本号;
  • 文件系统安装计数;
  • 超级块所在的块组号;
  • 数据块的大小;
  • 块组中数据块的数目;
  • 文件系统中空闲块的数目;
  • 文件系统中空闲索引节点的数目;
  • 文件系统中第一个索引节点的号码。

在Ext2文件系统中,第一个索引节点时根目录的入口。

块组描述符表

Ext2的一个块组可以看做文件系统空间的一个分区,与超级块的用途类似,为了向使用者提供块组的相关组织信息,每个块组有一个块组描述符表,其中主要提供块组的位图存放位置和i节点位图存放位置等信息。

Linux在文件include/linux/ext2_fs.h中定义的块组描述符表结构ext2_group_desc如下:

struct ext2_group_desc
{__le32	bg_block_bitmap;		/* 指向块组的块位图的指针 */__le32	bg_inode_bitmap;		/* 指向i节点位图的指针 */__le32	bg_inode_table;		/* i节点表的首地址 */__le16	bg_free_blocks_count;	/* 本组块空闲块的数目 */__le16	bg_free_inodes_count;	/* 本组块空闲i节点的数目 */__le16	bg_used_dirs_count;	/* 本组块分配给目录文件的i节点数目 */__le16	bg_pad;__le32	bg_reserved[3];
};

块组的块位图

Ext2文件系统用位图来记录块组中数据块的使用情况。数据块位图中的每一位表示该块组中每一个块的使用情况,如果为1,则表示该对应块已经被分配占用;如果为0,则表示该位还未被分配,是空闲块。

块组的i节点位图

Ext2文件系统用位图来记录块组中i节点使用情况。i节点位图中的每一位表示该块组中每一个i节点的使用情况,如果为1,则表示该结点已被分配占用;如果为0,则表示结点还未被分配,是空闲节点。

块组的i节点表

顾名思义,i节点表就是存放文件i节点的表格。每个块组中所有i节点都按i节点号的顺序存储在i节点表中。i节点表通常需要占用若干个数据块。

 

Ext2文件的用户操作函数集

作为一个为用户服务的文件系统,Ext2位用户提供的文件操作函数集如下:

const struct file_operations ext2_file_operations = {.llseek		= generic_file_llseek,.read		= do_sync_read,.write		= do_sync_write,.aio_read	= generic_file_aio_read,.aio_write	= generic_file_aio_write,.unlocked_ioctl = ext2_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl	= ext2_compat_ioctl,
#endif.mmap		= generic_file_mmap,.open		= generic_file_open,.release	= ext2_release_file,.fsync		= ext2_sync_file,.splice_read	= generic_file_splice_read,.splice_write	= generic_file_splice_write,
};

 


http://chatgpt.dhexx.cn/article/glxSw1yp.shtml

相关文章

EXT2文件系统实现原理

目录 一 EXT2文件系统结构概览 2 1.1 EXT2文件系统结构框图 2 1.2 EXT2重要数据结构 3 二 块缓存 6 三 EXT2文件系统挂载 7 3.1 注册ext2文件系统类型 7 3.2 ext2文件系统挂载 7 3.3文件系统操作 9 EXT2文件系统结构概览 1.1 EXT2文…

模拟实现EXT2文件系统

设计EXT2文件系统 实验目的 (1)掌握文件系统的工作原理 (2)理解文件系统的主要数据结构 (3)学习较为复杂的 Linux 下的编程 (4)了解 EXT2 文件系统的结构 实验内容 设计并实现…

WIN10访问linux分区「ext2fsd」

尝试ext2explore、Paragon ExtFS都不好用,强烈安利ext2fsd,可读写,很强大 转自:https://blog.csdn.net/cruise_h/article/details/12894135 ext2fsd是国人发起的项目,主页 http://www.ext2fsd.com/ 下载:h…

windos读写ext3工具_“ ext2fsd” Windows系统工具,用于读写ext2 / 3/4文件系统

在过去的几天里,我使用定制版本的Bridge Linux来扔Arch Linux. 修改lxdm主题时,我无意间无法进入系统,也无法切换命令行模式,因此我不得不找出Windows系统中是否存在可以读写ext4文件系统的工具. 以前尝试过ext2explore&#xff0…

ext2文件系统

ext2是Linux早期比较流行的文件系统,很多文件系统(NTFS、FAT32等)的设计都源自于它。只要掌握了ext2文件系统,其他文件系统大同小异。 ext2文件系统的布局如下: 文件系统中存储的最小单位是块(Block&#…

文件系统系列专题之 Ext2/3/4

一、Ext概述 EXT是延伸文件系统(Extended file system,缩写为 ext或 ext1),也译为扩展文件系统,第 1 个扩展文件系统(ext1)由 Remy Card 设计,并于 1992 年 4 月引入到 Linux 中。采…

深入理解ext2文件系统

ext2文件系统需要考虑哪些因素: 1.最重要的是保证数据的安全性。 2.效率,方便文件的查找读写。 3.文件在磁盘空间占用空间小。 (1)树形目录结构 EXT文件系统采用一个独立的顶级树形目录架构(即所有一切都从root根目录开始&…

学习篇 | LINUX 内核的文件系统 -- ext2

引言: 本篇博客中主要讲述的是 LINUX 内核所用的文件系统 —— 第二代扩展文件系统 Ext2,Ext2是数个Linux发行版本的默认文件系统。 百度百科 -- ext2 目录 引言: Ext2 文件系统 磁盘的物理组成 ext2 文件系统的格式 ext2 文件系统目录…

ext2文件系统详解

第一部分磁盘的物理组成 磁盘的基本概念: 扇区为最小的物理存储单位,每个扇区为512字节。 将扇区组成一个圆,那就是柱面,柱面是分区的最小单位。 第一个扇区很重要,里面有硬盘主引导记录(Masterbootrecord…

编译原理——证明文法具有二义性

证明一个文法具有二义性我们需要掌握两个知识点。 1.语法分析树 定义很简单,就是把一个句型的推导写成树的形式,这种表示法就叫语法分析树,或者简称为语法树。大概是这个样子的 2.二义性 一个文法存在某个句子对应两棵不同的语法树&…

二义性文法的理解和消除方法

给定文法G,如果存在句子s,它有两棵不同的分析树,那么称G是二义性文法 从编译器角度,二义性文法存在问题: 同一个程序会有不同的含义 因此程序运行的结果不是唯一的 一个句子有多于一棵分析树,仅与文法和句子…

2.5.3 文法二义性的消除

2.5.3 文法二义性的消除 (1 )不改变文法中原有的语法规则,仅加进一些语法的非形式规定。 例如,对于上例文法 G [ E ],不改变已有的 4 条规则,仅加进运算符的优先顺序和结合规则,即 * 优先于 ; , * 服从左结合。这样,对于文法 G [ E ]中的句子 i * i i 只有唯一的一棵语法树…

C#调用方法时的二义性解决方法

如图中出现的错误: 里面有三个名字为SetCurrentSelectableObject的方法,其中两个的参数都是引用对象,一个是SelectableObject类型,一个是string类型,这样导致引用出现了二义性,解决的办法就是对null进行强制…

[编译原理]如何判断某文法的二义性以及找到文法对应的语言

随便说说 这学期开编译原理课了,觉得还挺有意思的,写点博客记录记录。 如何根据文法找到其对应生成的语言 如图所示,假设我们现在有文法如下: ::�(�):�−>…

证明文法的二义性

例题 证明下面的文法是二义性的: S→ S A S | ( S ) | i A→ | * 证明步骤如下图 (是我自己做的所以不是很严谨) 证明文法二义性的过程 可以自己定义一个句型,我定义的是SS*S,偷了个小懒没有用到(S&…

C++ 多继承的二义性问题

多继承中的二义性问题 在一个表达式中,对函数或变量的引用必须是明确的,无二义性的。对于一个独立的类而言,其成员的标识是唯一的,对其访问不会有二义性问题。但是当类之间具有继承关系时,子类成员可能与父类成员重名&…

C++多继承中的二义性问题

在C中,派生类继承基类,对基类成员的访问应该是确定的、唯一的,但是常常会有以下情况导致访问不一致,产生二义性。 1.在继承时,基类之间、或基类与派生类之间发生成员同名时,将出现对成员访问的不确定性——…

二义性文法和无二义性文法

二义性文法是指一种产生式规则可以被解释成两种或更多种不同的语法结构的文法。这种文法会导致语言的歧义和不确定性,使得相同的语句可以有不同的解释。 以下是三个例子: S → aSb | ε 这个文法可以生成字符串"aaabbb",但是它有两…

如何消除文法的二义性

文法举例 显然,对于not p and q有两种推导方式 默认not优先级高于and,即(not p) and q 默认and优先级高于 not,即not(p and q) 先and再not先not再and 两种消除二义性的方法 简单来说,就是人为规定not\and\or的优先级即可 重写的文法相当于默…