文件系统及Fsck设计思路理解

魏星

Fsck是实现对文件系统的修复功能(fs check)。理解fsck需要掌握Linux文件系统设计原理、fsck设计原理和fsck实现的步骤。

 

一、Linux文件系统设计原理

1、文件系统基本概念

基本概念:super blockinode、目录文件、普通文件

a、super block

超级块存储文件系统的相关信息,包括文件系统的格式,inode/block的总数、使用量、剩余量等信息。没有superblock就没有这个filesystem了。

他主要记录的信息有:

.blockinode的总数;

.未使用与已使用的inode/blodk数量;

.blockinode的大小(block1,2,4Kinode128byte或者256byte)

.filessystem的挂载时间、最近一次写入数据的时间、最近一次检查磁盘(fsck)的时间等文件系统的相关信息;

.一个valid bit数值,若此文件系统已经被挂载,则valid bit0,若未被挂载,则valid bit1

格式化就是写super block的内容。Super block对文件系统太重要了,所以是有备份隐藏在系统中的,如果这个块坏了,可以用备份的块来恢复。

恢复办法见:

http://blog.chinaunix.net/uid-26557245-id-3748168.html

b、Inode

Inodes是实现文件系统存储的关键。在Linux系统中,一个文件可以分成几个数据块存储,就好像是分散在各地的龙珠一样。为了顺利的收齐龙珠,我们需要一个“雷达”来指引,这个“雷达”就是inode。每个文件对应一个inode,每个inode中包含多个指针,指向属于该文件各个数据块。当操作系统需要读取文件时,只需要对应inode的“地图”,收集起分散的数据块,就得到文件了。数据块才是正真存储文件的地方。

文件是文件系统对数据的分割单元。文件系统用目录来组织文件,赋予文件以上下分级的结构。在硬盘上实现这一分级结构的关键是使用inode来虚拟普通文件和目录文件对象。

Linux文件管理中除了自身的数据,还有一个附属信息,即文件的元数据(metadata)。这个元数据用于记录文件的许多信息,比如文件大小、拥有人、所属的组、创建日期、修改日期等。元数据并不包含在文件的数据中,而是由操作系统维护的,元数据包含在inode中。

Linux想要打开一个文件时,只需要找到文件对应的inode,然后沿着指针,将所有的数据块收集起来,就可以在内存中组成一个文件的数据。

Inode包含文件的元信息,具体如下:

*文件的字节数

*文件拥有者的User ID

*文件的Group ID

*文件的读、写、执行权限

*文件的时间戳,共有三个:ctimeinode创建时间,mtime指文件内容修改时间,atime指文件访问时间。

*链接数即多少文件名指向该inode

*文件数据block的位置

 

Inode的特色:

每个inode大小是固定的 128字节或者256字节

每个档案都仅会占用一个inode而已

因此文件系统能够建立的档案数量与inode的数量有关

系统读取档案是需要先找到inode,并分析inode所记录的权限与用户是否符合,如符合才能够开始实际读取block的内容

 

                           Inode的结构示意图

上图inode128bytes,这样子inode能够指定多少个block呢?我们以较小的1Kblock来说明吧!

.12个直接指向:12*1K=12K

.间接:1256*1K=256K

每笔block号码的记录会花掉4bytes,因此1K的大小能够记录256笔记录

.双间接:256*256*1K

.三间接:256*256*256*1K

总额:将直接、间接、双间接、三间接相加。最大一个文件16G

 

每个inode节点的大小,一般是128字节或者256字节。Inode节点的总数在格式化时就给定,一般是每1KB或每2KB就设置一个inode。假设在一个块1GB的硬盘中,每个inode节点的大小为128字节,每1KB就设置一个inode,那么inode table的大小就会达到128MB,占整个块硬盘的12.8%

ubuntu@ubuntu:/$ sudo dumpe2fs -h /dev/sdb |grep "Inode size"

[sudo] password for ubuntu: 

dumpe2fs 1.41.14 (22-Dec-2010)

Inode size:          256

 

这就是为什么格式化以后每个盘能够存储的容量只能占整个设备80%的原因

c、目录文件

目录文件存储了一张表,该表就是该目录文件下,所有文件名和inode的映射关系。

从父亲目录中获得本文件的inode--->找到inode-table表中找到这个inode号对应的数据域中的起点以及其他信息--->去这个数据域中读取该文件的内容(普通文件的内容是字符串,目录文件的内容是一张表)

Linux系统文件名最多127byte,那就是说这里定义的是128byte

d、普通文件

普通文件存储的是用户存储的数据内容啦!搞了半天就是为了存它嘛

2、文件系统的访问模型

文件text.txt的访问模型

 

在设备中实际存储为:

二、FSCK设计原理

1、Super block checking

在一个文件系统中最经常corrupt掉的是super block中的汇总信息。原因是这些信息在文件系统的block或者inode的每项改动,都需要在汇总信息中做相应的修改。因此,经常会corrupt(汇总信息与实际的文件系统信息不一致)。

Super block的一致性检查包括文件系统大小,inode数量,空闲的block块,空闲的inode数量等。文件系统的大小必须大于super blockinode使用的block数的和。文件系统的大小和布局信息是对fsck而言至关重要的信息。但并没有一种可以实际检查这些大小,因为他们是由newfs静态决定的,fsck可以检查这些大小在一个合理的范围之内。如果fsck在默认的super block中的静态的参数中检查到corrupt,它就会要求提供备用的super block所存放的地址。

2、Free block checking

Fsck会检查所有在cylinder group blocks maps(注:cylinder group即对应于fspartions)中标记为free的块,即没有被文件占用的块。Fsck会检查free的块的数量与inode中声明使用的块的数量的和是否与整个文件系统的所有块数相等。

如果在block allocation maps中有任何错误,fsck将根据其计算的allocated blocks进行重新组建block allocation maps

Super block中冶存有所有free块的数量信息,fsck会把自己检查的结果与super block中的信息进行比较,如果这两个数不等,则fsck会将检查得到的结果更新到super block中。

对文件系统中free inode的处理同上

3、Checking the inode state

当文件系统中有很多inode存在的时候(即很多文件),有可能会有几个inode corrupt。文件系统中的inode链表是从inode2开始顺序检查的(inode0标记没有用过的inodeinode1用来将来的扩展),直到文件系统中的最后一个inodeInode的状态检查包括:format and typelink countduplicated blocks,bad blocks,and inode size

每个inode都有一个mode word,它描述了inodetypestateInode必须处于六种类型之一:普通inode,目录inodesymbollink inodespecial block inodespecial character inode,或者是socket inode

Inode有三种allocation状态:unallocated,allocated和不属于前两种情况的情况。在第三种状态的inode就是不正确的inode,当inodes链表被写入坏的数据的时候,inode有可能进入这种状态。唯一可能修复的方法是fsck晴空这个inode(在链表中删除之)

4、inode Links

连接数是计算每一个inode与其相连的目录项的数目。Fsck从文件系统的root目录开始检查每一个inode的连接数,并沿着目录树依次查找。每个inode的实际link count在遍历的时候计算得到。如果存储的link count0,而计算的link count0,则此inode没有对应的目录项。这种情况下,fsck将把这个对应的文件放入lost+found目录中。如果存储的link count与实际计算所得的值非0且不相等,那么可能是inodelink count在有一个目录加入或者删除的时候没有被响应更新。这种情况下,fsck会用计算得到的值更新存储的值。

每个inode都包含一个列表或者是列表的指针,上面记录着这个inode所使用的数据块。因为inode是这些列表,因此,当这些列表存在不一致的情况时,就直接影响到拥有它的inode

Fsck会将一个inode声明的block number与列表中已经分配的block number比较。如果另一个inode已经声明了一个block number,那么这个block number就被加入到一个duplicate block链表中。否则,已分配的block list中会将这个block number加入。

对任何duplicate blocksfsck将会遍历inode list找到拥有duplicated blockinode。一般而言,拥有最早修改时间的inode坏掉的可能性比较大,需要被clear。如果是这种情况,fsck将执行操作,clear这两个inodes。操作必须决定,哪个该留,哪个该clear

Fsck检查每个inode声明的block number的范围,如果block number比文件系统中第一个数据块的块号低,或者比文件系统中的最后一个数据块的块号大,则称为bad block number。一个inode中许多的bad blocks经常是由于一个indirect block没有被写入到文件系统中,发生这种情况的前提是由于硬件异常的产生。如果一个inode含有bad block numbersfsck会将其clear

5、node data size

每个inode包含一定数量的data blocks。实际data block的数量是所有allocated data blocksindirect blocks的总和。Fsck计算实际的data blocks的数量,并与inode 所记录的数值进行比较。如果两者不一致,fsck会进行修正。

每个inode包含了一个32位的size域。这个数是inode对应的文件所包含有的字节数。这个size域的一致性检查是通过计算与inode对应的最大数量的blocks数,与实际inode保存的数值比较。

6、Checking the data with an inode

一个inode可以直接或者间接的reference三种类型的data blocks。所有的referenced blocks必须是同种类型。这三种类型是:plain data blockssymbolic link data blocks和 directory data blocksPlain datablocks包含文件中保存的信息。Symbolic link data blocks包含一个link中包含的路径名。Directory data blocks包含目录项。Fsck只能检查directory data blocks的有效性。

Fsck会检查每个directory data block的几种一致性:directory inode指向unallocated inodes,directory inodes的数量比文件系统中的inode数量大,不正确的.””..directory inode numbers,没有结合在文件系统中的directories。如果一个directory data block中的inode number references一个unallocated inodefsck将移除这个directory entry(目录项)。这种情况只发生在存在硬件异常的情况下。

三、Fsck实现步骤

Fsck5个阶段完成

1、阶段1:检查块和大小消息

此阶段检查inode列表。它会报告在以下情况遇到的错误状态:

.检查inode类型

.设置零链接计数表

.检查坏块或重复块的inode块编号

.检查inode大小

.检查inode格式

2、阶段1B:重新扫描更多DUPS消息

在文件系统中发现重复块时,将重新扫描文件系统,以查找以前请求过该块的inode

3、阶段2:检查路径名消息

此阶段将删除指向阶段11B所找到的坏inode的目录项。它将报告下列原因所导致的错误状态:

.不正确的根inode模式和状态

.目录inode指针超出范围

.目录项指向坏inode

.目录完整性检查

4、阶段3:检查目录链接

此阶段将检查在阶段2中检查的目录,并报告以下原因所导致的错误状态:

.非引用目录

.缺失的或完整的lost+found目录

5、阶段4:检查引用计数消息

此阶段将检查在阶段23中获得的链接计数信息。它将报告下列原因所导致的错误状态:

.非引用文件

.缺失的或完整的lost+found目录

.文件、目录、符号链接或特殊文件的链接计数不正确

.非引用文件、符号链接和目录

.文件和目录中存在坏片段或重复片段

.可用inode总计数不正确

6、阶段5:检查柱面组信息

此阶段将检查可用片段和已用inode图。它将报告下列原因导致的错误状态:

.已用inode图中缺少已分配inode

.可用片段图中缺少可用片段

.已用inode图中有可用inode

.可用片段总计数不正确

.已用inode总计数不正确

四、文件系统破坏的原因

导致一个文件系统corrupt的原因有可能有几种,而最经常的就是非正常关机流程和硬件的错误造成的。

造成corrupt的主要原因就是在停止CPU之前没有同步系统数据。如果非正常的启动没有被检测到,比如没有检查文件系统的一致性,没有恢复不一致的数据,允许使用一个corrupt的文件系统监视一种灾难。另外,一部分硬件有可能在任何时候出错,如在磁盘上的一个坏的块,或者是磁盘控制器没有响应等。

 

对于corrupt文件系统建议马上修护,否则后面修复越来越难阶段1B

五、解决文件系统破坏的办法

1、设备的拔出保护

设备的拔出,必须要先点击,确认才可以拔出

2、从硬件上解决

硬件解决需要提供UPS或者可充电电池,让设备一直处于工作状态;设备电源是带大电容延迟电源+断电侦测。一旦监测到断电,系统马上停止write文件系统,马上flush设备。

3、从系统软件上解决

系统通过测试,如果CPU使用率超过95%则马上降低系统负载或者直接停止部分不重要的写动作

4、从驱动层面解决

硬件增加一个可以写的、高速的耐写设备(容量很小、很贵),每次把修改制定文件map的数据先写入这个文件,然后更新文件系统,文件系统更新完成再清除这个设备的标准。文件系统每次读都要先判断是用那个地方数据是最新的。这种办法有点笨,一般只有芯片厂商修改文件系统来实现。