# 15.7 Log写磁盘流程

我已经在bwrite函数中加了一个print语句。bwrite函数是block cache中实际写磁盘的函数，所以我们将会看到实际写磁盘的记录。在上节课（Lec 14）我将print语句放在了log\_write中，log\_write只能代表文件系统操作的记录，并不能代表实际写磁盘的记录。我们这里会像上节课一样执行echo "hi" > x，并看一下实际的写磁盘过程。

![](https://1977542228-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MHZoT2b_bcLghjAOPsJ%2F-MSmzTZnlPGPIqpj2mML%2F-MSpExI_mBk7ES2XQvj8%2Fimage.png?alt=media\&token=dc4a94b4-e130-4938-9a23-4ef8df8bdc33)

很明显这里的记录要比只在log\_write中记录要长的多。之前的log\_write只有11条记录（注，详见14.5）但是可以看到实际上背后有很多个磁盘写操作，让我们来分别看一下这里的写磁盘操作：

* 首先是前3行的bwrite 3，4，5。因为block 3是第一个log data block，所以前3行是在log中记录了3个写操作。这3个写操作都保存在log中，并且会写入到磁盘中的log部分。
* 第4行的bwrite 2。因为block 2是log的起始位置，也就是log header，所以这条是commit记录。
* 第5，6，7行的bwrite 33，46，32。这里实际就是将前3行的log data写入到实际的文件系统的block位置，这里实际是install log。
* 第8行的bwrite 2，是清除log（注，也就是将log header中的n设置为0）。到此为止，完成了实际上的写block 33，46，32这一系列的操作。第一部分是log write，第二部分是install log，每一部分后面还跟着一个更新commit记录（注，也就是commit log和clean log）。

> 学生提问：可以从这里的记录找到一次文件操作的begin\_op和end\_op位置吗？
>
> Frans教授：大概可以知道。我们实际上不知道begin\_op的位置，但是所有的文件系统操作都从begin\_op开始。更新commit记录必然在end\_op中，所以我们可以找到文件系统操作的end\_op位置，之后就是begin\_op（注，其实这里所有的操作都在end\_op中，只需要区分每一次end\_op的调用就可以找到begin\_op）。

所以以上就是XV6中文件系统的logging介绍，即使是这么一个简单的logging系统也有一定的复杂度。这里立刻可以想到的一个问题是，通过观察这些记录，这是一个很有效的实现吗？很明显不是的，因为数据被写了两次。如果我写一个大文件，我需要在磁盘中将这个大文件写两次。所以这必然不是一个高性能的实现，为了实现Crash safety我们将原本的性能降低了一倍。当你们去读ext3论文时，你们应该时刻思考如何避免这里的性能降低一倍的问题。
