实验:文件系统

在本实验中,你将为 xv6 文件系统添加大文件和符号链接。

在编写代码之前,你应该阅读xv6手册中的"第8章:文件系统"并研究相应的代码。

获取实验的 xv6 源代码并切换到 util 分支:

  $ git fetch
  $ git checkout fs
  $ make clean

大文件

在本作业中,你将增加 xv6 文件的最大大小。目前 xv6 文件限制为 268 个块,或 268*BSIZE 字节(在 xv6 中 BSIZE 为 1024)。这个限制来自于 xv6 inode 包含 12 个"直接"块号和一个"单次间接"块号的事实,后者引用一个最多容纳 256 个块号的块,总共 12+256=268 个块。

bigfile 命令创建它能创建的最长文件,并报告该大小:

$ bigfile
..
wrote 268 blocks
bigfile: file is too small
$
测试失败是因为 bigfile 期望能够创建一个有 65803 个块的文件,但未修改的 xv6 将文件限制为 268 个块。

你将修改 xv6 文件系统代码以支持每个 inode 中的"双重间接"块,包含 256 个单次间接块的地址,每个地址又可以包含最多 256 个数据块的地址。结果是文件将能够由最多 65803 个块组成,或 256*256+256+11 个块(11 而不是 12,因为我们将牺牲一个直接块号用于双重间接块)。

预备知识

mkfs 程序创建 xv6 文件系统磁盘映像并确定文件系统的总块数;这个大小由 kernel/param.h 中的 FSSIZE 控制。 你会看到本实验仓库中的 FSSIZE 设置为 200,000 个块。你应该在 make 输出中看到 mkfs/mkfs 的以下输出:
nmeta 70 (boot, super, log blocks 30 inode blocks 13, bitmap blocks 25) blocks 199930 total 200000
这一行描述了 mkfs/mkfs 构建的文件系统:它有 70 个元数据块(用于描述文件系统的块)和 199,930 个数据块,总共 200,000 个块。
如果在实验过程中你发现需要从重建文件系统开始,你可以运行 make clean,这会强制 make 重建 fs.img。

需要关注的内容

磁盘上 inode 的格式由 fs.h 中的 struct dinode 定义。你特别需要关注 NDIRECTNINDIRECTMAXFILE 以及 struct dinodeaddrs[] 元素。请查看 xv6 文本中的图 8.3 以获取标准 xv6 inode 的图示。

在磁盘上查找文件数据的代码在 fs.c 中的 bmap() 中。请查看它并确保你理解它在做什么。bmap() 在读取和写入文件时都会被调用。写入时,bmap() 根据需要分配新块来保存文件内容,以及分配间接块来保存块地址(如果需要的话)。

bmap() 处理两种块号。bn 参数是"逻辑块号"——文件内的块号,相对于文件的起始位置。ip->addrs[] 中的块号和 bread() 的参数是磁盘块号。你可以将 bmap() 视为将文件的逻辑块号映射到磁盘块号。

你的任务

修改 bmap() 使其实现双重间接块,除了直接块和单次间接块之外。你只需要有 11 个直接块,而不是 12 个,以便为你的新双重间接块腾出空间;你不允许更改磁盘上 inode 的大小。ip->addrs[] 的前 11 个元素应该是直接块;第 12 个应该是单次间接块(就像当前的);第 13 个应该是你的新双重间接块。当 bigfile 写入 65803 个块且 usertests 成功运行时,你就完成了本练习:
$ bigfile
..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
wrote 65803 blocks
done; ok
$ usertests
...
ALL TESTS PASSED
$ 

bigfile 至少需要一分半钟来运行。

提示:

符号链接

在本练习中,你将为 xv6 添加符号链接。符号链接(或软链接)通过路径名引用一个链接文件;当打开符号链接时,内核跟随链接到被引用的文件。符号链接类似于硬链接,但硬链接被限制为指向同一磁盘上的文件,而符号链接可以跨越磁盘设备。虽然 xv6 不支持多个设备,但实现这个系统调用是理解路径名查找如何工作的一个很好的练习。

你的任务

你将实现 symlink(char *target, char *path) 系统调用,它在 path 处创建一个新的符号链接,引用 target 命名的文件。更多信息请参见 man page symlink。要测试,将 symlinktest 添加到 Makefile 并运行它。当测试产生以下输出(包括 usertests 成功)时,你的解决方案就完成了。

$ symlinktest
Start: test symlinks
test symlinks: ok
Start: test concurrent symlinks
test concurrent symlinks: ok
$ usertests
...
ALL TESTS PASSED
$ 

提示:

提交实验

实验到此完成。确保你通过了所有 make grade 测试。如果本实验有问题,不要忘记将你的答案写入 answers-lab-name.txt。提交你的更改(包括添加 answers-lab-name.txt)并在实验目录中输入 make handin 来提交你的实验。

花费时间

创建一个新文件 time.txt,在其中放入一个整数,表示你在本实验上花费的小时数。不要忘记 git addgit commit 该文件。

提交

你将使用
提交网站提交你的作业。在提交任何作业或实验之前,你需要从提交网站申请一次 API 密钥。

在提交你对实验的最终更改后,输入 make handin 来提交你的实验。

$ git commit -am "ready to submit my lab"
[util c2e3c8b] ready to submit my lab
 2 files changed, 18 insertions(+), 2 deletions(-)

$ make handin
tar: Removing leading `/' from member names
Get an API key for yourself by visiting https://6828.scripts.mit.edu/2020/handin.py/
Please enter your API key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 79258  100   239  100 79019    853   275k --:--:-- --:--:-- --:--:--  276k
$
make handin 会将你的 API 密钥存储在 myapi.key 中。如果你需要更改 API 密钥,只需删除此文件并让 make handin 重新生成(myapi.key 不能包含换行符)。

如果你运行 make handin 时有未提交的更改或未跟踪的文件,你将看到类似以下的输出:

 M hello.c
?? bar.c
?? foo.pyc
Untracked files will not be handed in.  Continue? [y/N]
检查上述行,确保你的实验解决方案所需的所有文件都已跟踪,即不在以 ?? 开头的行中列出。 你可以使用 git add filenamegit 跟踪你创建的新文件。

如果 make handin 无法正常工作, 尝试修复 curl 或 Git 命令的问题。 或者你可以运行 make tarball。 这将为你生成一个 tar 文件,然后你可以通过我们的网页界面上传。

可选挑战练习

支持三重间接块。

致谢

感谢华盛顿大学 CSEP551(2019年秋季)的团队提供符号链接练习。