14.3 How file system uses disk

接下来,我将简单的介绍最底层,也即是存储设备。实际中有非常非常多不同类型的存储设备,这些设备的区别在于性能,容量,数据保存的期限等。其中两种最常见,并且你们应该也挺熟悉的是SSD和HDD。这两类存储虽然有着不同的性能,但是都在合理的成本上提供了大量的存储空间。SSD通常是0.1到1毫秒的访问时间,而HDD通常是在10毫秒量级完成读写一个disk block。

这里有些术语有点让人困惑,它们是sectors和blocks。

  • sector通常是磁盘驱动可以读写的最小单元,它过去通常是512字节。

  • block通常是操作系统或者文件系统视角的数据。它由文件系统定义,在XV6中它是1024字节。所以XV6中一个block对应两个sector。通常来说一个block对应了一个或者多个sector。

有的时候,人们也将磁盘上的sector称为block。所以这里的术语也不是很精确。

这些存储设备连接到了电脑总线之上,总线也连接了CPU和内存。一个文件系统运行在CPU上,将内部的数据存储在内存,同时也会以读写block的形式存储在SSD或者HDD。这里的接口还是挺简单的,包括了read/write,然后以block编号作为参数。虽然我们这里描述的过于简单了,但是实际的接口大概就是这样。

在内部,SSD和HDD工作方式完全不一样,但是对于硬件的抽象屏蔽了这些差异。磁盘驱动通常会使用一些标准的协议,例如PCIE,与磁盘交互。从上向下看磁盘驱动的接口,大部分的磁盘看起来都一样,你可以提供block编号,在驱动中通过写设备的控制寄存器,然后设备就会完成相应的工作。这是从一个文件系统的角度的描述。尽管不同的存储设备有着非常不一样的属性,从驱动的角度来看,你可以以大致相同的方式对它们进行编程。

有关存储设备我们就说这么多。

学生提问:对于read/write的接口,是不是提供了同步/异步的选项?

Frans教授:你可以认为一个磁盘的驱动与console的驱动是基本一样的。驱动向设备发送一个命令表明开始读或者写,过了一会当设备完成了操作,会产生一个中断表明完成了相应的命令。但是因为磁盘本身比console复杂的多,所以磁盘的驱动也会比我们之前看过的console的驱动复杂的多。不过驱动中的代码结构还是类似的,也有bottom部分和top部分,中断和读写控制寄存器(注,详见lec09)。

从文件系统的角度来看磁盘还是很直观的。因为对于磁盘就是读写block或者sector,我们可以将磁盘看作是一个巨大的block的数组,数组从0开始,一直增长到磁盘的最后。

而文件系统的工作就是将所有的数据结构以一种能够在重启之后重新构建文件系统的方式,存放在磁盘上。虽然有不同的方式,但是XV6使用了一种非常简单,但是还挺常见的布局结构。

通常来说:

  • block0要么没有用,要么被用作boot sector来启动操作系统。

  • block1通常被称为super block,它描述了文件系统。它可能包含磁盘上有多少个block共同构成了文件系统这样的信息。我们之后会看到XV6在里面会存更多的信息,你可以通过block1构造出大部分的文件系统信息。

  • 在XV6中,log从block2开始,到block32结束。实际上log的大小可能不同,这里在super block中会定义log就是30个block。

  • 接下来在block32到block45之间,XV6存储了inode。我之前说过多个inode会打包存在一个block中,一个inode是64字节。

  • 之后是bitmap block,这是我们构建文件系统的默认方法,它只占据一个block。它记录了数据block是否空闲。

  • 之后就全是数据block了,数据block存储了文件的内容和目录的内容。

通常来说,bitmap block,inode blocks和log blocks被统称为metadata block。它们虽然不存储实际的数据,但是它们存储了能帮助文件系统完成工作的元数据。

学生提问:boot block是不是包含了操作系统启动的代码?

Frans教授:完全正确,它里面通常包含了足够启动操作系统的代码。之后再从文件系统中加载操作系统的更多内容。

学生提问:所以XV6是存储在虚拟磁盘上?

Frans教授:在QEMU中,我们实际上走了捷径。QEMU中有个标志位-kernel,它指向了内核的镜像文件,QEMU会将这个镜像的内容加载到了物理内存的0x80000000。所以当我们使用QEMU时,我们不需要考虑boot sector。

学生提问:所以当你运行QEMU时,你就是将程序通过命令行传入,然后直接就运行传入的程序,然后就不需要从虚拟磁盘上读取数据了?

Frans教授:完全正确。

假设inode是64字节,如果你想要读取inode10,那么你应该按照下面的公式去对应的block读取inode。

所以inode0在block32,inode17会在block33。只要有inode的编号,我们总是可以找到inode在磁盘上存储的位置。

Last updated