16.7 ext3 file system恢复过程

为了简化重启时恢复软件的工作,当决定释放某段log空间时,文件系统会更新super block中的指针将其指向当前最早的transaction的起始位置。

之后如果crash并重启,恢复软件会读取super block,并找到log的起始位置。所以如果crash了,内存中的所有数据都会消失,例如文件系统中记录的哪些block被写入到了磁盘中这些信息都会丢失,所以可以假设这时内存中没有可用的数据,唯一可用的数据存在于磁盘中。当然我们这里的讨论都是基于磁盘还是完好的,所以你可以认为只是一次电力故障,系统突然停止了运行过程,在电力恢复时,断电那一瞬间磁盘中的数据还存在。我们并没有考虑磁盘被损坏或者被摧毁的情况。

crash或许会打断任何在进行中的transaction,或许transaction正在commit,或许transaction正在向文件系统写block。让我重新画一个例子,我们在log中有一个super block,之后是transaction T6,T7,T8,在T8之后是一个已近被释放了log空间的T5,假设T8已经用了T5的一部分空间。并且现在super block指向的是T6的起始位置,因为T6是最早的transaction。

现在crash并重启,恢复软件读取super block就可以知道log的起始位置,之后恢复软件会在log中一直扫描并尝试找到log的结束位置,现在我们需要有一种方式确定log的结束位置。我们知道每个transaction包含了一个descriptor block,里面记录了该transaction中包含了多少个data block,假设descriptor block记录了17个block,那么恢复软件会扫描17个data block,最后是commit block。这样可以一直扫描到T8。

在扫描T8时有两种可能,一种可能是T8完成了commit,并且包含了commit block。这时恢复软件并不知道T8就是最后一个transaction,所以它会接着看T8的commit block的下一个block,来看看这是不是一个有效的descriptor block。我们知道这不是一个descriptor block,而是一个包含在T5内的随机block。现在的问题是恢复软件如何可靠的区分出来呢?是的,每个descriptor和commit block都以某个魔法数字作为起始,这是一个32bit的数字。所以如果扫描完了T8,下一个block以魔法数字作为起始,那么恢复软件就会认为这是一个descriptor block。(注,也有可能T5正好完美的跟在T8后面,也就是说T8的commit block之后就是T5的descriptor block,同时T5的commit block也存在,所以这里必然还需要一些其他的机制,我猜是用到了transaction的序列号)

但是,现在我们看到的block可能是包含了任意数据的data block,所以它可能是文件中的一个data block并且也是以魔法数字作为起始。所以这里的最后一个细节是,logging系统需要能区分一个以魔法数字作为起始的descriptor block和一个以魔法数字作为起始的data block。你可以想到各种方法来实现这种区分,ext3是这样做的,当它向log写一个block时,如果这个block既不是descriptor block也不是commit block,但是又以魔法数字作为起始,文件系统会以0替换前32bit,并在transaction的descriptor block中为该data block设置一个bit。这个bit表示,对应的data block本来是以魔法数字作为起始,但是现在我们将其替换成了0。而恢复软件会检查这个bit位,在将block写回到文件系统之前,会用魔法数字替换0。

因此,在log中,除了descriptor和commit block,不会有其他的block以这32bit的魔法数字作为起始。所以我们不会有模棱两可的判断,如果一个commit block之后的block以魔法数字作为起始,那么它必然是一个descriptor block。所以恢复软件会从super block指向的位置开始一直扫描,直到:

  • 某个commit block之后的一个block并不是descriptor block

  • 或者某个commit block之后是descriptor block,但是根据descriptor block找到的并不是一个commit block

这时,恢复软件会停止扫描,并认为最后一个有效的commit block是log的结束位置。或许在最后一个commit block之后会跟一个并没有commit完成的transaction(注,上面的第二种情况),但是恢复软件会忽略未完成的transaction,因为这个transaction并没有包含所有的写操作,所以它并不能原子性的恢复。之后恢复软件会回到log的最开始位置,并将每个log block写入到文件系统的实际位置,直到走到最后一个有效的commit block。之后才是启动剩下的操作系统,并且运行普通的程序。在恢复完成之前,是不能运行任何程序的,因为这个时候文件系统并不是有效的。

学生提问:XV6相比这里的log机制,缺少了什么呢?

Robert教授:XV6主要缺失的是在log中包含多个transaction的能力,在XV6的log中最多只会有一个transaction,所以在XV6中缺少了并发的能力。比如说当我在执行transaction T7的系统调用时,ext3可以同时向磁盘提交T6,而这在XV6中这是不可能的,因为log只保存了一个transaction。所以我们必须先完成一个transaction的所有工作,之后才能开始下一个transaction。所以XV6是简单且正确的,但是缺少了并发的能力。

学生提问:但是在XV6我还是可以有多个transaction,只是说不能异步的执行它们,对吗?

Robert教授:这里其实有点模糊,XV6实际上允许在一个transaction中包含多个系统调用(注,详见15.8),所以XV6有一些并发和batching的能力,但是当XV6决定要commit一个transaction时,在完全完成这个transaction之前,是不能执行任何新的系统调用的。因为直到前一个transaction完全完成,并没有log空间来存放新的系统调用。所以XV6要么是在运行一些系统调用,要么是在commit transaction,但是它不能同时干这两件事情,而ext3可以同时干这两件事情。

Last updated