xv6文件系统由inode组成,每个inode是单个未命名的文件。整个磁盘读写的最小单元为block (xv6为512字节),其中整个磁盘分布如下图
第0个block为启动区,第1个block为超级块 (也是根目录所在的块),接下来是连续分布的dinode,最后是连续分布的BPB(块位图)
假设块大小为BSIZE, 则
1. 每个块包含的dinode结构体的数量为: IPB = BSIZE/sizeof(dinode)。等价于第i个dinode所在的block为IBLOCK(i) = i/IPB+2
2. 第i个block所在的位图块为: BBLOCK(b, ninodes) = b/BPB+ninodes/IPB+3
一、位图块 (BPB)
xv6文件系统采用位图块来管理磁盘中的块,每个块可以管理的大小为 BPB = BSIZE * 8,若该标志为0,则块空闲,否则已经使用。
获取块时调用balloc,首先读取该dev的superblock,从而获取文件系统的所有块的大小sb.size,对于每个BPB依次检测是否有空闲块,若该块对应的位图块的标志位0,则为说明该块空闲,返回即可。
需要说明的是,每个dev的ninodes、size大小都是固定的。
二、inode文件系统
xv6只将active的dinode保存在内存的inode数组icache中
对于on-disk的dinode结构,它是块列表数据保存在addrs数组中,其中addrs[0...NDIRECT-1]直接存储的块号,而adds[NDIRECT]相当于一个指针,指向了一个块,这个块中保存了间接的块号构成的一个数组。
从程序员的角度来看,文件是一种字节流,程序从0到size进行顺序访问,但是实际文件是分割成多个块存储在磁盘中的,那么文件系统中的bmap就实现从逻辑块到物理块的一个映射。
如果是一个文件,则可以根据inode中的addrs获取文件内容所在的块,但是如果是一个目录呢?其实,目录也是一个文件,文件中包含有多个目录项,其结构为
其中name为文件名,inum为inode号。
在解析路径时,我们可能需要在目录中查找下一个文件,并返回相应的inode结点,基本做法是把inode目录文件的内容逐块导入到内存中,如果目录项的名字dirent->name和查找的名字相同,则查找到了匹配项,返回相应的inode (第inum个inode,若没有in-memory拷贝,则会创建一个:找出一个空闲的inode,并替换元数据)
三、文件路径解析
到现在一切似乎水到渠成了,那么我们可以直面最激动人心的问题了:如果碰到这样/usr/home/zl.txt的路径,我们应该怎样解析呢?
其实方法很简单,逐步的解析路径,得到下层的inode结点。
1. name="usr", path="home/zl.txt", 在根目录中查找并返回名为"usr" 对应的inode
2. name="home", path="zl.txt",在上级inode中查找并返回名为"home"对应的inode
3. name="zl.txt", path="",在上级inode中查找并返回名为"zl.txt"对于的inode
4. path=0, 跳出while循环