一、Ext2的一般特征
但在一些情况下,已经在Ext2的索引节点中为这些特性引入新的字段。最重要的一些特点如下:
块片(block fragmentation):系统管理员对磁盘的访问通常选择较大的块,因为计算机应用程序常常处理大文件。因此,在大块上存放小文件就会浪费很多磁盘空间。这个问题可以通过把几个文件存放在同一块的不同片上来解决。
透明地处理压缩和加密文件:这些新的选项(创建一个文件时必须指定)将允许用户透明地在磁盘上存放压缩和(或)加密的文件版本。
逻辑删除:一个undelet选项将允许用户在必要时很容易恢复以前已删除的文件内容。
日志:日志避免文件系统在突然卸载(例如,作为系统崩溃的后果)时对其自动进行的耗时检查。
二、Ext2磁盘数据结构
任何Ext2分区中的第一个块从不受Ext2文件系统的管理,因为这一块是为分区的引导扇区所保留的。Ext2分区的其余部分分成块组(block group)。一些数据结构正好可以放在一块中,而另一些可能需要很多的块。在Ext2文件系统中的所有块组大小相同并被顺序存放,因此,内核可以从块组的整数索引很容易地得到磁盘中一个块组的位置。
由于内核尽可能地把属于一个文件的数据块存放在同一块组中,所以块组减少了文件的碎片。块组中的每个块包含下列信息之一:
* 文件系统的超级块的一个拷贝。
* 一组块组描述符的拷贝。
* 一个数据块位图。
* 一个索引节点位图。
* 一个索引节表。
* 属于文件的一大块数据,即数据块。
如果一个块中不包含任何有意义的信息,就说这个块是空闲的。
举例说明,让我们考虑一下32GB的Ext2分区,块的大小为4KB。在这种情况下,每个4KB的块位图描述32K个数据块,即128MB。因此,最多需要256个块组。显然,块的大小越小,块组数越大。
2.1、超级块
2.2、组描述符和位图
每个块组都有自己的组描述符,它是一个ext2_group_desc结构。
2.3、索引节点表
2.4、索引节点的增强属性
2.5、访问控制列表
很早以前访问控制列表就被建议用来改善Unix文件系统的保护机制。不是将文件的用户分成三类:拥有者、组和其他,访问控制列表(access control list,ACL)可以与每个文件关联。有了这种列表,用户可以为他的文件限定可以访问的用户(或用户组)名称以及相应的权限。
2.6、各种文件类型如何使用磁盘块
2.6.1、普通文件
普通文件是最常见的情况,本章主要关注它。但普通文件只有在开始有数据时才需要数据块。普通文件在刚创建时是空的,并不需要数据块;也可以用truncate()或open()系统调用清空它。这两种情况是相同的,例如,当你发出一个包含字符串>filename的shell命令时,shell创建一个空文件或截断一个现有文件。
2.6.2、目录
Ext2以一种特殊的文件实现了目录,这种文件的数据块把文件名和相应的索引节点号存放在一起。特别说明的是,这样的数据块包含了类型为ext2_dir_entry_2的结构。
2.6.3、符号链接
如前所述,如果符号链接的路径名小于等于60个字符,就把它存放在索引节点的i_blocks字段,该字段是由15个4字节整数组成的数组,因此无需数据块。但是,如果路径名大于60个字符,就需要一个单独的数据块。
2.6.4、设备文件、管道和套接字
这些类型的文件不需要数据块。所有必要的信息都存放在索引节点中。
三、Ext2的内存数据结构
为了提高效率,当安装Ext2文件系统时,存放在Ext2分区的磁盘数据结构中的大部分信息被拷贝到RAM中,从而使内核避免了后来的很多读操作。那么一些数据结构如何经常更新呢?让我们考虑一些基本的操作:
* 当一个新文件被创建时,必须减少Ext2超级块中s_free_inodes_count字段的值和相应的组描述符中bg_free_inodes_count字段的值。
* 如何内核给一个现有的文件追加一些数据,以使分配给它的数据块数因此也增加,那么就必须修改Ext2超级块中s_free_blocks_count字段的值和组描述符中bg_free_blocks_count字段的值。
* 即使仅仅重写一个现有文件的部分内容,也要对Ext2超级块的s_wtime字段进行更新。
因为所有的Ext2磁盘数据结构都存放在Ext2分区的块中,因此,内核利用页高速缓存来保持它们最新。
频繁更新的数据总是存放在高速缓存,也就是说,这些数据一直存放在内存并包含在页高速缓存中,直到相应的Ext2分区被卸载。内核通过让缓冲区的引用计数器一直大于0来达到此目的。
在任何高速缓存中不保存“从不缓存”的数据,因为这种数据表示无意义的信息。相反,“总是缓存”的数据也总在RAM中,这样就不必从磁盘读数据了(但是,数据必须周期性地写回磁盘)。除了这两种极端模式外,还有一种动态模式。在动态模式下,只要相应的对象(索引节点、数据块或位图)还在使用,它就保存在高速缓存中;而当文件关闭或数据块被删除后,页框回收算法会从高速缓存中删除有关数据。
有意思的是,索引节点与块位图并不永久保存在内存里,而是需要时从磁盘读。有了页高速缓存,最近使用的磁盘块保存在内存里,这样可以避免很多磁盘读。
3.1、Ext2的超级块对象
很显然,ext2_fill_super()函数返回后,分配的所有数据结构都保存在内存里,只有当Ext2文件系统卸载时才会被释放。当内核必须修改Ext2超级块的字段时,它只要把新值写入相应缓冲区内的相应位置然后将该缓冲区标记为脏即可。
3.2、Ext2的索引节点对象
四、创建Ext2文件系统
Ext2文件系统是由实用程序mke2fs创建的。mke2fs采用下列缺省选项,用户可以用命令行的标志修改这些选项:
* 块大小:1024字节(小文件系统的缺省值)。
* 片大小:块的大小(块的分片还没有实现)。
* 所分配的索引节点个数:每8192字节的组分配一个索引节点。
* 保留块的百分比:5%。
mke2fs程序执行下列操作:
1、初始化超级块和组描述符。
2、作为选择,检查分区是否包含有缺陷的块;如果有,就创建一个有缺陷块的链表。
3、对于每个块组,保留存放超级块、组描述符、索引节点表及两个位图所需要的所有磁盘块。
4、把索引节点位图和每个块组的数据映射位图都初始化为0。
5、初始化每个块组的索引节点表。
6、创建/root目录。
7、创建lost + found目录,由e2fsck使用这个目录把丢失和找到的缺陷块连接起来。
8、在前两个已经创建的目录所在的块组中,更新块组中的索引节点位图和数据块位图。
9、把有缺陷的块(如果存在)组织起来放在lost + found目录中。
五、Ext2的方法
5.1、Ext2超级块的操作
5.2、Ext2索引节点的操作
5.3、Ext2的文件操作
六、管理Ext2磁盘空间
在本节,我们将介绍Ext2文件系统如何管理磁盘空间,也就说,如何分配和释放索引节点和数据块。有两个主要的问题必须考虑:
* 空间管理必须尽力避免文件碎片,也就是说,避免文件在物理上存放于几个小的、不相邻的盘块上。文件碎片增加了对文件的连续读操作的平均时间,因为在读操作期间,磁头必须频繁地重新定位。
* 空间管理必须考虑效率,也就是说,内核应该能从文件的偏移量快速地导出Ext2分区上相应的逻辑块号。为了达到此目的,内核应该尽可能地限制对磁盘上寻址表的访问次数,因为对该表的访问会极大地增加文件的平均访问时间。
6.1、创建索引节点
6.2、删除索引节点
6.3、数据块寻址
每个非空的普通文件都由一组数据块组成。这些块或者由文件内的相对位置(它们的文件块号)来标识,或者由磁盘分区内的位置(它们的逻辑块号)来标识。
从文件内的偏移量f导出相应数据块的逻辑块号需要两个步骤:
1、从偏移量f导出文件的块号,即在偏移量f处的字符所在的块索引。
2、把文件的块号转化为相应的逻辑块号。
6.4、文件的洞
文件的洞(file hole)是普通文件的一部分,它是一些空字符但没有存放在磁盘的任何数据块中。洞是Unix文件一直存在的一个特点。
引入文件的洞是为了避免磁盘空间的浪费。它们被广泛地用在数据库应用中,更一般地说,用于在文件上进行散列的所有应用。
6.5、分配数据块
当内核要分配一个数据块来保存Ext2普通文件的数据时,就调用ext2_get_block()函数。如果块不存在,该函数就自动为文件分配块。请记住,每当内核在Ext2普通文件上执行读或写操作时就调用这个函数;显然,这个函数只在页高速缓存内没有相应的块时才被调用。
6.6、释放数据块
七、Ext3文件系统
Ext3文件系统在设计时曾秉持两个简单的概念:
* 成为一个日志文件系统。
* 尽可能与原来的Ext2文件系统兼容。
7.1、日志文件系统
日志文件系统的目标就是避免对整个文件系统进行耗时的一致性检查,这是通过查看一个特殊的磁盘区达到的,因为这种磁盘区包含所谓日志(journal)的最新磁盘写操作。系统出现故障后,安装日志文件系统只不过是几秒钟的事。
7.2、Ext3日志文件系统
Ext3日志所隐含的思想就是对文件系统进行的任何高级修改都分两步进行。首先,把待写块的一个副本存放在日志中;其次,当发往日志的I/O数据传送完成时(简而言之,把数据提交到日志),块就被写入文件系统。当发往文件系统的I/O数据结构终止时(把数据提交给文件系统),日志中的块副本就被丢弃。
当从系统故障中恢复时,e2fsck程序区分下列两种情况:
提交到日志之前系统故障发生。与高级修改相关的块副本或者从日志中丢失,或者是不完整的;在这两种情况下,e2fsck都忽略它们。
提交到日志之后系统故障发生。块的副本是有效的,且e2fsck把它们写入文件系统。
在第一种情况下,对文件系统的高级修改被丢失,但文件系统的状态还是一致的。在第二种情况下,e2fsck应用于整个高级修改,因此,修正由于把未完成的I/O数据传送到文件系统而造成的任何不一致。
7.3、日志块设备层
Ext3与JDB之间的交互本质上基于三个基本单元:
日志记录:描述日志文件系统一个磁盘块的一次更新。
原子操作处理:包括文件系统的一次高级修改对应的日志记录;一般来说,修改文件系统的每个系统调用都引起一次单独的原子操作处理。
事务:包括几个原子操作处理,同时,原子操作处理的日志记录对e2fsck标记为有效。
7.3.1、日志记录
7.3.2、原子操作处理
7.3.3、事务
事务一旦被创建,它就能接受新处理的日志记录。当下列情况之一发生时,事务就停止接受新处理:
* 固定的时间已经过去,典型情况下为5s。
* 日志中没有空闲块留给新处理。
事务是由类型为transaction_t的描述符来表示的。其最重要的字段为t_state,该字段描述事务的当前状态。
从本质上说,事务可以是:
完成的:包含在事务中的所有日志记录都已经从物理上写入日志。当从系统故障中恢复时,e2fsck考虑日志中每个完成的事务,并把相应的块写入文件系统。在这种情况下,t_state字段存放值T_FINISHED。
未完成的:包含在事务中的日志记录至少还有一个没有从物理上写入日志,或者新的日志记录还正在追加到事务中。在系统故障的情况下,存放在日志中的事务映像很可能不是最新的。因此,当从系统故障中恢复时,e2fsck不信任日志中未完成的事务,并跳过它们。在这种情况下,i_state存放下列值之一:
T_RUNNING:还在接受新的原子操作处理。
T_LOCKED:不接受新的原子操作处理,但其中的一些还没有完成。
T_FLUSH:所有的原子操作处理都已完成,但一些日志记录还正在写入日志。
T_COMMIT:原子操作处理的所有日志记录都已经写入磁盘,但在日志中,事务仍然被标记为完成。
在任何时刻,日志可能包含多个事务,但其中只有一个处于T_RUNNING状态,即它是活动事务(active transaction)。所谓活动事务就是正在接受由Ext3文件系统发出的新原子操作处理的请求。
7.4、日志如何工作
当然,除非发生系统故障,否则日志中的日志记录根本就没有什么积极作用。事实上,只有在系统发生故障时,e2fsck实用程序才扫描存放在文件系统中的日志,并重新安排完成的事务中的日志记录所描述的所有写操作。
阅读(822) | 评论(0) | 转发(0) |