基础概念
在操作系统中,各式各样的数据信息都已文件的形式进行存储,串口是文件,内存是文件,usb是文件,进程信息是文件,网卡是文件…因此Linux系统中有着“一切皆文件”的说法。而操作系统中负责管理和存储可长期保存数据的软件功能模块称为文件系统。也就是说,对文件进行各式各样的操作(读、写、创建和删除)都需要文件系统的辅助完成。
下面依据Ucore的模型来介绍文件系统及其内容。
Ucore文件系统
ucore的文件系统模型源于Havard的OS161的文件系统和Linux文件系统。但其实这二者都是源于传统的UNIX文件系统设计。Ucore对文件系统抽象成了四部分:通用文件系统访问接口层、文件系统抽象层、Simple FS文件系统层和外设接口层。
层数 | 功能 | 通俗来说 | |
---|---|---|---|
通用文件系统访问接口层 | 第一层 | 该层提供了一个从用户空间到文件系统的标准访问接口。这一层访问接口让应用程序能够通过一个简单的接口获得ucore内核的文件系统服务。 | 提供一系列的库函数供用户使用,以库函数来访问文件 |
文件系统抽象层 | 第二层 | 向上提供一个一致的接口给内核其他部分(文件系统相关的系统调用实现模块和其他内核功能模块)访问。向下提供一个同样的抽象函数指针列表和数据结构屏蔽不同文件系统的实现细节。 | 向上提供库函数的系统调用,向下调用具体文件系统的数据结构 |
Simple FS文件系统层 | 第三层 | 一个基于索引方式的简单文件系统实例。向上通过各种具体函数实现以对应文件系统抽象层提出的抽象函数。向下访问外设接口 | 实际的文件系统部分,包括了具体的数据结构例如inode的实现,向下提供访问外设的接口 |
外设接口层 | 第四层 | 外设接口层:向上提供device访问接口屏蔽不同硬件细节。向下实现访问各种具体设备驱动的接口,比如disk设备接口/串口设备接口/键盘设备接口等。 | 向上提供设备调用的接口,向下实现设备访问接口 |
用一张图可以表示操作文件时,整个文件系统的工作过程:
这里我们不会赘述除第三层外的内容,因为不同的操作系统的文件系统架构可能不相同,但第三层所设计的数据结构则是经典的、值得学习的。
文件系统布局
前面说到,文件系统是用来管理和存储文件的模块,而Ucore中的第三层,也就是具体的文件系统层往往可以看作是狭义的文件系统。这是因为可以忽略掉和用户以及驱动程序的管理,只关注文件系统的构成与布局。
首先先说明磁盘的大致布局。毕竟文件系统是依附于磁盘的。布局如下:
首先是分成了MBR和四个partition。MBR(Master Boot Record)是主引导记录。BIOS初始化后去读取主引导扇区的代码,主引导扇区则包含了主引导记录,主引导记录代码去读取各个活动分区,加载文件系统。
MBR结构如下:图片来源清华大学学堂在线。
不过和MBR相关的内容属于操作系统,BOOT SECTOR也是如此,而本文主要讲述文件系统,故具体细节(例如BIOS的初始化、堆栈寄存器、加载流程细节)这里不赘述。
文件系统会被分成若干的块组(block group),一个块组可以近似的看作Windows下的磁盘分区。每个块组都由以下部分构成:超级块(super block)、GDT(Group Descriptor Table,块组描述符表)、block bitmap、inode bitmap、inode table和data blocks。这里采用的是常用的文件系统的做法,因为ucore的文件系统内容较少,且相同的数据结构所包含项也并不完整(例如超级块内容)。
一、超级块
它包含了关于文件系统的所有关键参数,例如块大小、文件系统版本号、上次mount的时间等等。当计算机被启动或文件系统被首次接触时,超级块的内容就会被装入内存。超级块在每个块组的开头都有一份拷贝。超级块的具体内容如下:
-
Magic Number
对于Ext2和Ext3文件系统来说,这个字段的值应该正好等于0xEF53。如果不等的话,那么这个硬盘分区上肯定不是一个正常的Ext2或Ext3文件系统。从这里,我们也可以估计到,Ext2和Ext3的兼容性一定是很强的,不然的话,Linux内核的开发者应该会为Ext3文件系统另选一个Magic Number才对。
-
Mount Count and Maximum Mount Count
每次mount此文件系统,Mount Count都会加1,当它等于Maximum Mount Count时系统将发出警告:maxumal mount count reached, running e2fsck is recommended。
-
Block Group Number
Block Group的个数。
-
Block Size
该文件系统在创建(格式化)时指定的block大小,如1024 Bytes。
-
Blocks per Group
每个Block Group中block的个数,文件系统在创建时指定。
-
Free Blocks
文件系统中空闲块数。
-
Free Inodes
文件系统中空闲Inode数。
-
First Inode
文件系统中第一个inode号。EXT2根文件系统中第一个inode将是指向’/'目录的目录入口。
GDT(Group Descriptor Table,块组描述符表)
由很多块组描述符组成,整个分区分成多少个块组就对应有多少个块组描述符。每个块组描述符(Group Descriptor)存储一个块组的描述信息,例如在这个块组中从哪里开始是inode表,从哪里开始是数据块,空闲的inode和数据块还有多少个等等。
GDT包含以下重要信息:
-
Blocks Bitmap
对应此数据块组的块分配位图的块号。在块分配和回收时使用。
-
Inode Bitmap
对应此数据块组的inode分配位图的块号。在inode分配和回收时使用。
-
Inode Table
对应数据块组的inode表的起始块号。每个inode用下面5中介绍的ext3_inode结构来表示。
-
Free blocks count, Free Inodes count, Used directory count
分别代表空闲的block数、空闲的inode数和使用的directory数。
block bitmap和inode bitmap
这两种结构放到一起来解释:因为都是基于bitmap(位示图)的结构组织而成的。bitmap则是用来区分哪些块还可以使用,哪些块已经被占用的结构。bitmap的每一个bit代表一个block(对于block bitmap来说,如果对于inode bitmap则是代表一个inode),因此可以快速的通过查找bitmap得知空闲情况,而不需要搜索整个分区。
如下图所示,0代表空闲,1代表已分配,行代表字(一个字16bit),列代表位号,则可以用 (行号,列号) 快速的得出具体位置是否空闲。因此,block bitmap代表磁盘块是否被使用,而inode bitmap则代表inode是否可用。
inode table
文件除去数据内容外,还包括了其他的描述信息,例如文件名、类型、大小、权限等等。这些内容存在inode中,而非存在数据块中。因此一个inode是对应着一个文件(在软、硬链接会进一步叙述:文件描述符表、文件打开表和inode表 硬链接与软连接)。而inode构成的表项则是inode table。通过inode可以得到具体data block中的内容,也就可以访问文件的具体内容。这也是第三层和第四层(磁盘访问)的连接方式。
data block
即数据块,存储文件的数据内容。
参考文档:Linux 磁盘分区和文件系统