Skip to content

日志设计

日志位于一个已知的固定位置,在超级块中指定。它由一个头部块和一系列更新的块副本(“日志块”)组成。头部块包含一个扇区号数组,每个日志块对应一个,以及日志块的数量。磁盘上头部块中的计数要么是零,表示日志中没有事务,要么是非零,表示日志包含一个完整的已提交事务,其中包含指定数量的日志块。Xv6 在事务提交时写入头部块,但在此之前不写入,并在将日志块复制到文件系统后将计数设置为零。因此,在事务中途崩溃将导致日志头部块中的计数为零;提交后崩溃将导致非零计数。

每个系统调用的代码都指明了必须相对于崩溃是原子的写入序列的开始和结束。为了允许不同进程并发执行文件系统操作,日志系统可以将多个系统调用的写入累积到一个事务中。因此,单个提交可能涉及多个完整系统调用的写入。为了避免跨事务拆分系统调用,日志系统仅在没有文件系统系统调用正在进行时才提交。

将多个事务一起提交的想法被称为组提交。组提交减少了磁盘操作的数量,因为它将一次提交的固定成本分摊到多个操作上。组提交还同时向磁盘系统提交了更多的并发写入,也许允许磁盘在一次磁盘旋转期间写入所有这些写入。Xv6 的 virtio 驱动程序不支持这种批处理,但 xv6 的文件系统设计允许这样做。

Xv6 在磁盘上专门分配了固定数量的空间来保存日志。一个事务中系统调用写入的块总数必须能容纳在该空间中。这有两个后果。任何单个系统调用都不允许写入比日志空间中更多的不同块。这对于大多数系统调用来说不是问题,但其中有两个可能会写入许多块:writeunlink。一个大的文件写入可能会写入许多数据块和许多位图块以及一个 inode 块;取消链接一个大文件可能会写入许多位图块和一个 inode。Xv6 的写入系统调用将大的写入分解为多个较小的写入,这些写入适合日志,而 unlink 不会引起问题,因为实际上 xv6 文件系统只使用一个位图块。有限日志空间的另一个后果是日志系统不能允许系统调用开始,除非它确定该系统调用的写入将适合日志中剩余的空间。