目录
buffer cache(块缓存) VS icache(inode缓存)
文件系统
文件系统层次
从宏观上而言,文件系统的分布如下图所示,最底层是实际的物理disk以及其驱动程序,上方是buf cache,缓存区缓存,用于对物理块的缓存,再上方是日志logging,之后是icache,将最近使用的inode信息缓存到内存中,提升文件系统的效率,也方便对同一物理块的不同inode节点统一写回,在上方就是inode数据结构,和文件一一对应,在上方就是应用层的文件名和文件描述符。

底层物理层的实现
如下图所示,底层存储设备包括SSD(机械硬盘)和HDD(固态硬盘),这些设备连接在主板上,通过总线和CPU,内存等联通,通过PCI或PCIe协议进行通信。在物理设备上的最小单位通常称为扇区,常见的扇区大小为512B,但在操作系统或文件系统中最小使用单位为块,一个块通常为几个扇区(例如XV6中块大小为1024B,为2个扇区)。CPU和磁盘的通信也是根据块编号进行读写通信的。

buffer cache(块缓存) VS icache(inode缓存)
日志记录不必多说,接下来是两个缓存,块缓存是对物理硬盘上的块(无论是数据块还是inode所在的索引块)进行缓存,inode缓存是对实实在在的inode进行缓存。两者位于不同的层次,inode节点重点在于提供文件信息以及提供文件数据所在的位置,而块缓存实际上更多的是物理的扇区到操作系统的块之间的一种抽象。两者都能极大的提升文件系统的效率,但所在的层次不同。
块的分布情况
块的分布情况如下图所示,如XV6这种简单的操作系统就是一个巨大的块的数组,在其他操作系统中可能有更加复杂的结构(树结构等)。一般而言第一块都是boot块,也就是操作系统的启动块,每次开机后都会执行该块中的内容。第二块称为“super block”,他主要存储关于文件系统的信息,比如文件系统采用的架构,大小,结构等。之后的2-31块称为log日志块,存储日志信息。接下来的32-44,存放所有的inode节点,这里每个inode是64B,则每个块包含16个inode节点。随后的45块表示bitmap块(位图块),其中每一位仅用0/1表示数据块/inode节点的占用信息。46块之后的都是数据块,即实际存储文件数据的地方。

inode
inode(Index Node)也叫索引节点,其主要作用用于存储文件的元数据而不是文件本身的数据。元数据含义是存储数据的数据,例如文件类型(目录/文件)、文件大小,存储该文件的数据块的指针等信息。在文件系统中,inode和真正的文件(本质不同)一一对应,也就是当inode用完时,文件系统不可再创建新的文件了。
在xv6中inode节点的信息如下,包括类型type,nlink链接个数,size文件大小,以及bn0-bn11这12个直接块编号分别指向该文件的数据块,以及一个间接索引块,其指向了一个索引块,索引块中包含了256个快编号,所以一个inode节点最大的文件大小是(256+12)*1024B=268KB。

目录
在Unix操作系统中有一个“一切皆文件”的概念,大概意思是说操作系统把所有输入/输出资源都抽象成”文件“接口,这样同一的抽象处理使得程序员大大方便了很多,这里目录也不例外。
目录也是有inode节点存储,其中type类型为目录,其数据块中存储的是一个个目录项,在xv6中目录项如下图所示,一个目录项有16字节,前2个字节存储对应的inode编号,后14个字节存储文件名称,所以一个数据块中最多包含1024/16=64个目录项。

这里举一个查找文件的例子,比如要抄找“/y/x”文件,则首先先寻找根目录inode编号(一般固定在inode块的第二个,第一个通常保存文件系统的坏块列表),这个是提前固定好的,之后根据此inode节点中找到其数据块,其是目录,数据块中存放的全是目录项,朝朝filename为‘y’的,找到之后返回其inode编号,之后再根据此inode编号找到其inode节点,根据数据块找到filename为‘x’的inode编号,此时就找到了x的inode节点编号。(相对路径查询则直接从当前目录出发查找,流程类似)。
XV6文件系统的实践
首先在启动qemu后,可以看到文件系统的初始化,如下图所示,白色的是提前创建好的文件,下方则是对文件系统的说明,46个块包含1个boot块,一个super块,30个log块,13个inode 块以及1个bitmap块,最后的是954个数据块,一共1000个块,是一个很小的文件系统了。

接下来,看一下执行echo hi > x指令,涉及到的块来体会文件系统具体的工作流程,如下图所示。
首先是创建文件x,第一次到块33是找一个空闲的inode编号,之后第二个33是在inode节点中修改信息,之后的块46是根目录的数据块,要增加一个目录项,随后回到块32,修改根目录inode的size属性,最后块33暂且不提。之后是写“hi”到数据块中,首先在bitmap块中将inode节点编号和块编号都改为1,表示已用,随后找到空闲数据块595,先后写下‘h’和‘i’,最后回到块33也就是文件x所在inode节点修改size。最后写'\n'为文件结束符,同样先后经过595和33.

之后我们结合xv6中的代码来看一下他具体的流程,以下是echo的用户程序:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
int i;
for(i = 1; i < a

最低0.47元/天 解锁文章
1757

被折叠的 条评论
为什么被折叠?



