Appearance

Lab 5:文件系统

byml2025-06-05OS

Lab 5:文件系统

完结撒花,感谢陪伴 🌷

存储的抽象

󱜸 我们日常使用的文件系统是一个多叉树状结构,那么它该以何种方式存储呢? Ext 文件系统采用了类似“链表树”的方式存储文件关系:每一个文件名对应树上的一个节点,文件夹间的嵌套关系对应一条边。而数据则是以块的方式存储,每个文件名都会维护指向其数据块的指针。 󱜸 设备、程序、文件夹和普通文件有什么区别? 在 Linux "Every thing is a file" 的设计理念下,用户只需要看到万物皆文件,而操作系统要考虑的事就很多了。虽然都是抽象成文件,实际处理时却需要根据其类型、权限等信息采用不同的处理逻辑。 󱜸 在存储设备中,文件系统以什么形式存在?

以一块使用 Ext2 文件系统的硬盘为例,在格式化后,整体结构如上。可以看到,磁盘的第一个分区是我们熟悉的主引导扇区,然后会被分为若干组。每组里面包括:

  • 一个超级块:用来记录 block 和 inode 的总量、已使用和未使用量、最后一次写入数据的时间、是否挂载等一系列基本信息。
  • 一个组描述区:用来标记本组开始和结束的 block 号、每个区段(Super Blcok、bitmap等)分别的开始和结束 block 号
  • 一个数据块使用标记:用来在创建块时快速找到未使用块号
  • 一个节点使用标记:用来在创建节点时快速找到未使用节点号
  • 若干节点表:表格的数量是在格式化时确定好的,每个节点占 128 位(16字节),包含节点修改时间、大小、指向的数据块等信息。记录每个块需要 4 位,就算使用了间接记录,单一节点能维护的数据块数量也是有限的,从而文件系统的单文件大小有上限。
  • 若干数据块:数据块的数量和大小也是在格式化时确定好的,Ext2 支持 1K、2K 和 4K 三种大小,越大的 block 对应越大的单文件大小,最大支持 2TB 单文件,16TB 文件系统总大小。Ext4 则升级inode 到 256 位,使得其支持 16 TB 单文件和 1EB 文件系统总大小。

󱜸 在 Ext 的文件系统下,文件夹是怎么维护的?如何知道一个文件夹里有哪些文件呢? 首先,文件夹是特殊的文件,因此按照规则,其也是由一个 inode 存储的。而文件夹中的文件信息,则被维护在文件夹的数据块中,存储其 inode 和名称,这就构成了我们常见的树状结构。

文件系统 API

内核控制

文件是静态的数据,要想对数据进行操作,就需要操作系统将文件的数据加载到内存中,再进行一系列的读写操作。为此,操作系统向应用程序提供了“文件描述符”对文件进行操作。 文件描述符对应着 FCB(File Control Block,文件控制块)。FCB 中维护有当前打开的所有文件的相关信息(打开方式、读写偏移量等)。所有对文件的读写,都有如下流程:

  • 程序发起 open 系统调用,请求打开文件
  • 操作系统根据文件路径,在文件系统中找到(或创建)相应的文件,创建 FCB,返回其索引作为文件描述符
  • 程序获取文件描述符,发起 readwritelseek 等系统调用,对文件进行操作
  • 操作系统根据文件描述符,找到对应的 FCB,并在文件系统中执行对应操作

使用文件描述符,相比于用路径描述文件,更加方便处理(文件描述符只是一个索引数),也更加安全(文件打开过程中可能有其他操作使得路径发生改变)。

并发冲突

󱜸 不同进程如果请求对相同文件的操作,会不会出现冲突? 操作系统需要处理这种冲突,一般会维护全局的 FCB 引用计数,这样就可以知道文件是否处于编辑状态,从而避免读写冲突;也可以及时关闭没有用的文件。 󱜸 子进程可以继承父进程打开的文件吗? 对于 fork 系统调用,需要对父进程的 FCB 进行浅拷贝,同时让全局 FCB 对应文件的引用计数加一,这样就可以做到父子进程间偏移量的共享。 对于 exec 系统调用,可以直接将进程的 FCB 保留,全局 FCB 也无需修改,因为这时程序运行等价于在 exec 下面直接执行另一个程序,原来打开的文件没有关上,全局引用计数也不变。

重定向的实现

if((pid = fork()) == 0) {
	// child
	close(STDOUT_FILENO);
	open("a.txt");
	exec("ls");
} else {
	// father
	waitpid(pid);
}

在子进程中,先关闭 STDOUT_FILENO,然后调用 open,此时,操作系统会将最小的未被占用文件描述符分配给 a.txt,恰好为 STDOUT_FILENO(标准输入输出的文件描述符是 01)。执行 exec 后,由于 ls 默认是向标准输出对应的描述符写入数据,这就实现了重定向。