linux系统编程-文件系统(一)

本文详细介绍了Ext2文件系统的内部结构,包括块组、超级块、块位图、inode位图、inode表和数据块等内容,并解释了数据块寻址方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文件系统

文件存储

首先了解如下文件存储相关概念:inodedentry、 数据存储、文件系统。

inode

其本质为结构体,存储文件的属性信息。如:权限、类型、大小、时间、用户、盘块位置……也叫作文件属性管理结构,大多数的inode都存储在磁盘上。

少量常用、近期使用的inode会被缓存到内存中。

dentry

目录项,其本质依然是结构体,重要成员变量有两个 {文件名,inode...},而文件内容(data)保存在磁盘盘块中。

文件系统

文件系统是,一组规则,规定对文件的存储及读取的一般方法。文件系统在磁盘格式化过程中指定。

常见的文件系统有fat32  ntfs  exfat  ext2 ext3 ext4

ext2文件系统

 

ext2文件系统

我们知道,一个磁盘可以划分成多个分区,每个分区必须先用格式化工具(例如某种mkfs命令)格式化成某种格式的文件系统,然后才能存储文件,格式化的过程会在磁盘上写一些管理存储布局的信息。下图是一个磁盘分区格式化成ext2文件系统后的存储布局。

文件系统中存储的最小单位是块(Block),一个块究竟多大是在格式化时确定的,例如mke2fs-b选项可以设定块大小为102420484096字节。而上图中启动块BootBlock)的大小是确定的,就是1KB,启动块是由PC标准规定的,用来存储磁盘分区信息和启动信息,任何文件系统都不能使用启动块。启动块之后才是ext2文件系统的开始,ext2文件系统将整个分区划成若干个同样大小的块组(Block Group),每个块组都由以下部分组成。

超级块Super Block) 描述整个分区的文件系统信息,例如块大小(1k2k4K……)、文件系统版本号、上次mount的时间等等。超级块在每个块组的开头都有一份拷贝。

块组描述符表GDTGroup Descriptor Table) 由很多块组描述符组成,整个分区分成多少个块组就对应有多少个块组描述符。每个块组描述符(Group Descriptor)存储一个块组的描述信息,例如在这个块组中从哪里开始是inode表,从哪里开始是数据块,空闲的inode和数据块还有多少个等等。和超级块类似,块组描述符表在每个块组的开头也都有一份拷贝,这些信息是非常重要的,一旦超级块意外损坏就会丢失整个分区的数据,一旦块组描述符意外损坏就会丢失整个块组的数据,因此它们都有多份拷贝。通常内核只用到第0个块组中的拷贝,当执行e2fsck检查文件系统一致性时,第0个块组中的超级块和块组描述符表就会拷贝到其它块组,这样当第0个块组的开头意外损坏时就可以用其它拷贝来恢复,从而减少损失。

块位图Block Bitmap) 一个块组中的块是这样利用的:数据块存储所有文件的数据,比如某个分区的块大小是1024字节,某个文件是2049字节,那么就需要三个数据块来存,即使第三个块只存了一个字节也需要占用一个整块;超级块、块组描述符表、块位图、inode位图、inode表这几部分存储该块组的描述信息。那么如何知道哪些块已经用来存储文件数据或其它描述信息,哪些块仍然空闲可用呢?块位图就是用来描述整个块组中哪些块已用哪些块空闲的,它本身占一个块,其中的每个bit代表本块组中的一个块,这个bit1表示该块已用,这个bit0表示该块空闲可用。

为什么用df命令统计整个磁盘的已用空间非常快呢?因为只需要查看每个块组的块位图即可,而不需要搜遍整个分区。相反,用du命令查看一个较大目录的已用空间就非常慢,因为不可避免地要搜遍整个目录的所有文件。

与此相联系的另一个问题是:在格式化一个分区时究竟会划出多少个块组呢?主要的限制在于块位图本身必须只占一个块。用mke2fs格式化时默认块大小是1024字节,可以用-b参数指定块大小,现在设块大小指定为b字节,那么一个块可以有8bbit,这样大小的一个块位图就可以表示8b个块的占用情况,因此一个块组最多可以有8b个块,如果整个分区有s个块,那么就可以有s/(8b)个块组。格式化时可以用-g参数指定一个块组有多少个块,但是通常不需要手动指定,mke2fs工具会计算出最优的数值。

inode位图inode Bitmap) 和块位图类似,本身占一个块,其中每个bit表示一个inode是否空闲可用。

inodeinode Table) 我们知道,一个文件除了数据需要存储之外,一些描述信息也需要存储,例如文件类型(常规、目录、符号链接等),权限,文件大小,创建/修改/访问时间等,也就是ls -l命令看到的那些信息,这些信息存在inode中而不是数据块中。每个文件都有一个inode,一个块组中的所有inode组成了inode表。inode表占多少个块在格式化时就要决定并写入块组描述符中,mke2fs格式化工具的默认策略是一个块组有多少个8KB就分配多少个inode。由于数据块占了整个块组的绝大部分,也可以近似认为数据块有多少个8KB就分配多少个inode,换句话说,如果平均每个文件的大小是8KB,当分区存满的时候inode表会得到比较充分的利用,数据块也不浪费。如果这个分区存的都是很大的文件(比如电影),则数据块用完的时候inode会有一些浪费,如果这个分区存的都是很小的文件(比如源代码),则有可能数据块还没用完inode就已经用完了,数据块可能有很大的浪费。如果用户在格式化时能够对这个分区以后要存储的文件大小做一个预测,也可以用mke2fs-i参数手动指定每多少个字节分配一个inode

inode表中每个inode的大小:ext2ext3128字节,ext4256字节

数据块(Data Block) 根据不同的文件类型有以下几种情况:

对于常规文件,文件的数据存储在数据块中。

对于目录,该目录下的所有文件名和目录名存储在数据块中,注意文件名保存在它所在目录的数据块中,除文件名之外,ls -l命令看到的其它信息都保存在该文件的inode中。注意这个概念:目录也是一种文件,是一种特殊类型的文件。

对于符号链接,如果目标路径名较短则直接保存在inode中以便更快地查找,如果目标路径名较长则分配一个数据块来保存。

设备文件、FIFOsocket等特殊文件没有数据块,设备文件的主设备号和次设备号保存在inode中。

 

数据块寻址:

如果一个文件有多个数据块,这些数据块很可能不是连续存放的。这些数据块通过inode中的索引项Block来找到。

这样的索引项一共有15个,Block[0]--Block[14],每个索引项占4字节。前12个索引项都表示块的编号,如Block[0]保存27,表示第27个块是该文件的数据块。

如果块的大小是1KB,这种方法可以表示从0-12KB的文件。如果剩下的三个索引项也这么用,那就只能表示最大15KB的文件了。这是远远不够的。

剩下的3个索引项Block[12]Block[13]Block[14]都是间接索引。假设块的大小为b,那么一个间接寻址块中可以存放b/4个索引项,指向b/4个数据块。

如:b=1KB,那么Block[0]--Block[12]都用上,最大可以表示 1024/4 + 12 = 268K大小的文件。虽然大很多,但仍然不够用。

于是有了二级间接寻址块Block[13],三级间接寻址块Block[14]。这样1K的块最大可以表示16.06GB大小的文件。

stat命令中: “块”--> 物理块(512B)的个数;“IO块”--> 逻辑块的大小

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值