第四部分 存储管理 文件系统

第十章 文件系统

这部分主要是一些较高层的策略问题,主要是面向上层开发人员,而不涉及太多具体实现。

1. 文件操作

1.1 基本操作集合

文件为抽象数据类型。操作系统提供 6 个系统调用构成操作文件的最小集合,包括

  • 创建 create,首先在文件系统中为文件找到空间,其次,在目录中创建新文件的条目
  • 写入 write,指定文件名称和要写入文件的信息,系统根据文件名称搜索目录已查找文件位置。系统应维护写指针,用于指向需要进行下次写操作的文件位置。写的时候同时更新写指针。
  • 读取 read,指明文件名称和文件的内容应读到哪里。系统根据文件名称定位文件内容,同时需要维护一个读指针,指向要进行下一次读取操作的文件位置。同样,读操作需要同时更新读指针。

读写操作可以使用相同的指针。称为 当前文件位置指针。这个指针的初始化受文件访问模式影响,APPEND 会置于末尾,否则是文件头。

  • 重新定位 seek,移动当前文件位置指针到指定位置,不涉及实际 I/O 操作。
  • 删除 delete, 搜索给定文件名,找到对应的目录条目,释放占用的文件空间,并删除对应条目。
  • 截断 truncate 文件。用户可能想删除文件的内容,但保留它的属性。实际上就是只改动文件长度属性。

1.2 打开文件表

以上操作大多涉及搜索目录,得到文件的相关条目,为了避免这种搜索,OS 一般要求访问文件前需要先 open()。OS 有个打开文件表,维护所有打开文件的信息。如果不用了再 close()。create/delete 操作的是未 open() 的。
open() 函数返回一个文件句柄 (Windows) 或者称为文件描述符 (UNIX-like),后续操作都以这个值作为指针,避免重复搜索。同时,open() 一般也支持访问模式信息,如 CREATE, APPEND 等。OS 会根据文件系统的权限子系统检查 open() 是否合法。

文件系统的设计哲学显然是一种 “有状态” 通信。有状态和无状态的区别主要是是否单次操作需要携带所有必要信息。如果是无状态,那么每次都要指定文件名、访问模式、当前文件指针等等,NFS 就是这么设计的;有状态就得把状态维护起来,放在一个数据结构里,每次操作只需要携带一个指针以让系统知道操作的是哪个项。这两种设计哲学广泛分布于计算机领域,如 TCP 和 UDP,TCP 有状态,每条链接的状态信息由 OS 维护,而 UDP 每次读写数据互不干扰,OS 并没有 UDP 的状态信息(可能需要维护其它信息,如端口信息)

通常,OS 采用两级内部表:单独进程表系统总表

  • 单独进程表跟踪进程打开的所有文件,存储了当前文件位置指针、权限、访问模式等信息。
  • 系统表包含与进程无关的信息,如文件在磁盘上的位置,mtime/ctime/atime,文件大小等。一旦进程打开了一个文件就会产生一个条目,如后续再有进程 open(),只需要在打开计数上加 1 即可。每次 close() 会减 1,OS 会回收计数为 0 的条目。所以 open() 后的文件不用了一定要 close()。

1.3 同步

OS 可以提供强制 (Windows) 或建议(UNIX-like) 的文件锁定机制。强制锁会要求文件操作的所有 API 都检查锁,也即一个进程加了锁,OS 会确保其它进程调用 open() 这类函数的时候会被阻塞。这是一个内核级别的实现。而建议锁是指,一个进程加了锁,其它进程需要主动去检查这个锁的状态,再决定是否操作文件。Linux 文件锁 的实现可以参考这篇文章。
Java 实现文件互斥访问时通过要访问文件的 FileChannel 的 lock() 取得 FileLock 来做得。FileLock 支持共享和非共享,同时支持字节级别的锁定。

public abstract FileLock lock(long position, long size, boolean shared)
        throws IOException;

2. 文件类型与结构

实现文件类型的常见技术是将类型作为文件名的一部分,即放在扩展名里。UNIX 系统采用位于某些文件开始部分的魔数(magic number)大致表明文件类型,但不是所有文件都有魔数。Linux 的可执行文件是依赖于其执行权限而不是拓展名。所以综上,文件类型的区分方法千奇百怪。
文件类型决定文件结构。OS 必须支持至少一种结构,即可执行文件的结构,以便系统能加载和运行程序。但是,OS 一般也不应该规定太多文件结构,谁支持谁就得负责,这个让 OS 来做 OS 就很亏。

Linux 大致有这些文件类型:普通文件、目录、字符设备、块设备、套接字、符号链接

3. 访问方法

  • 顺序访问
    文件信息按顺序加以处理,编辑器和编译器通常以这种方式访问文件。适合磁带
  • 直接访问
    文件由固定长度的逻辑记录组成,以允许程序按任意顺序进行随机访问。数据库通常是这种类型的。直接访问可以由顺序访问进行模拟,但是效率低下。适合磁盘等。
  • 其它访问方法
    其它访问方法通常建立在直接访问之上,并涉及建立文件索引。现代通用 OS 都是这种。

4. 目录与磁盘的结构

文件系统底层是磁盘,向上提供前面提到的 API,那么必须维护目录来组织这些文件。

4.1 一些概念

  1. 磁盘 磁盘是一块单独的物理设备
  2. 分区 磁盘格式化后才能使用,格式化实际上就是对磁盘进行分区,分为不同的部分,每个部分有些元数据表明物理存储的一些信息,也就是文件系统的元数据。按传统分区技术,分区一般分为主分区和扩展分区;分区表格式有主引导分区(Master Boot Record, MBR,已逐渐淘汰) 和 GPT(GUID Partition Table) 分区。比如 Windows 的 C 盘、D 盘就是分完区后的结果。详见鸟哥的 Linux 私房菜磁盘部分
  3. 文件系统 文件系统和分区不是一个概念,分区一般说的是物理存储设备,文件系统是描述存储设备的内容格式。
  4. LVM Logical Volume Manager Linux 下的逻辑卷管理器,向上屏蔽掉底层物理磁盘的细节。实际上就是让 OS 能操作多块磁盘以及支持扩容、缩容等操作。传统分区有很多限制。
LVM

PV(Physical Volume):物理卷,处于LVM最底层,可以是物理硬盘或者分区。
PE(Physical Extend):物理区域,PV中可以用于分配的最小存储单元,可以在创建PV的时候制定(默认为4MB),如1M, 2M, 4M, 8M, 32M, 64M…组成同一VG中所有PV的PE大小应该相同。
VG(Volume Group):卷组,建立在PV之上,可以含有一个到多个PV。
LV(Logical Volume):逻辑卷,建立在VG之上,相当于原来分区的概念。不过大小可以动态改变。

  1. VFS Linux 支持多种文件系统,为了屏蔽底层细节,VFS 扮演了中间层的角色

4.2 目录

目录(directory)可以理解为一个字典,记录的是文件名到磁盘存储位置的映射。目录可以分为单级目录、两级目录、树形目录(主流目录结构)、无环图目录(为了共享子目录)。

UNIX-Like 既支持基于软链接的共享,这个时候文件系统并不把软连解当作实际节点,删了之后也依然保留,需要程序员自己意识到被删了;也支持基于硬链接的共享,后者修改了 inode 的内容,会由文件系统管理节点。详见相关博客。

4.3 文件系统挂载

文件系统在使用前得先挂在到某个目录,挂载位置称为挂载点,被挂载的称为设备。比如, Linux 中,/home 一般是个单独的分区,内核会在启动的时候将其挂载到根目录下的 /home 处。然后我们才可以通过 /home/test.c 直接访问 test.c 文件。

Linux 默认只有一个分区,即 /,这个分区上运行着发行版默认的文件系统。这个 / 里面可以装文件,也可以挂载其它文件系统。这里首先得认识到 OS 目录树和文件系统不是一个概念。你可以在 /test1 挂载一个 ext3 文件系统,可以在 /test2 挂载一个 xfs 文件系统,可以在 /test3 放一个普通文件。挂载可以看作根目录的某个节点被另外一颗树替代。Windows 会在启动时自动安装所有文件系统(卷 C, D...),如果我们插入 U 盘,Windows 会识别并把 U 盘挂载到目录树上,只不过这个目录树是两级的。Linux 的挂载点一般可以是任何位置,Windows 的新版本似乎也可以,但不清楚。

4.4 保护

UNIX-like 文件系统的一般权限 和 SUID, SGID, SBIT等

第十一章 文件系统实现

1. 文件系统的结构

文件系统一般分层实现,从上往下:

  • 逻辑文件系统。管理元数据信息,包括文件系统的所有结构,但不包括实际数据。通过文件控制块(File Control Block, FCB) 包含文件的信息,如权限、位置等
  • 文件组织模块。负责映射文件的逻辑块到物理块地址。每个文件的逻辑块是连续编号的,但是物理块不是。
  • 基本文件系统。负责向设备驱动程序发送命令,读写物理块,维护缓存等。
  • I/O 控制。负责底层硬件通信

内存和磁盘之间的 I/O 以块 (block) 为单位,块的大小与磁盘扇区大小无关。同时,上述模块在实际实现中可能揉在一起。

2. 文件系统的实现

2.1 元数据

首先考虑一下文件系统需要维护哪些信息。分别从磁盘上和内存中来考虑(下述不区分卷和分区的概念,因为卷实际上就是个逻辑分区):

2.1.1 磁盘上
  • 每个分区的引导控制块 (boot control block)。如果分区不包含 OS,则这块为空,也即一个 OS 有多个分区。它通常为卷的第一块,有自己的格式。因为在引导式系统没有加载文件系统代码,不能解释文件系统的格式。每个分区都可以有引导控制块,这是多重引导,即多系统的基础。个人感觉这部分不属于文件系统的一部分

BIOS/UEFI 是启动检测程序。他们运行后,会去读 MBR/GPT 分区,然后 MBR/GPT 分区可以直接加载内核文件来启动 OS,也可以将控制流转到其它引导控制块。

  • 分区控制块。存储了分区内的详细信息,如分区内的块的数量、大小、空闲块和指针、空闲的 FCB 数量和指针等。也即 UNIX-like 中的超级块 (superblock)
  • 目录结构。在 Linux 中,包括文件名和 inode 号码。
  • 每个文件的 FCB 包括该文件的许多详细信息。也即 Linux 中的 inode。
2.1.2 内存中
  • 挂载表。包含设备的挂载信息,条目包括一个指向该设备的文件系统超级块的指针。
  • 目录结构缓存。
  • 系统打开文件表。
  • 进程打开文件表。
  • 缓冲区。保存文件系统的块。

2.2 操作函数

2.2.1 创建文件/文件夹

创建文件时,应用程序调用逻辑文件系统,由其分配一个新的 FCB。如果文件系统的实现在文件系统创建时(格式化的时候)已经创建了所有 FCB,如 ext 文件系统,则可从空闲的 FCB 集合中分配一个可用的 FCB。然后逻辑文件系统用文件名和新的 FCB 去更新其对应的目录文件,并写回磁盘,这个过程会调用下面的文件组织模块。
UNIX 不区分文件和文件目录的处理,而 Windows 提供两套系统调用。

2.2.2 打开文件

文件使用前需要先打开。open() 首先需要搜索系统打开文件表查询是否已经打开,如是,直接在进程打开文件表中新建条目并指向系统打开表中的条目,同时更新计数;否则,需要搜索文件所在目录,这个通常缓存在内存中,找到文件后,将其 FCB 复制到系统打开文件表,并在进程打开文件表中重复前面相同的动作。
进程打开文件表中的条目一般包含一个指针指向系统表,所有文件操作通过这个指针进行,所以文件表不需要包含文件名,因为可以通过指针访问 FCB。这个在 UNIX 中称为 文件描述符(file descriptor),在 Windows 中称为 文件句柄 (file handle)。

2.2.3 读写文件

读文件需要指定文件描述符,然后内核访问进程的打开文件表,获取系统打开文件表的索引,再根据系统文件表中存储的 FCB(可能在内存中也可能是一个指向磁盘的指针),然后获取文件的元数据,包括数据存储位置、当前位置指针等。然后向下发送读取指令,最后由 I/O 设备完成读取。读到的内容放入指定的缓冲中。
写文件类似,只不过一般都是写缓冲,落盘的策略一般由文件系统自行安排或者应用程序手动调用 fsync。

2.2.4 关闭文件

关闭文件需要删除进程打开文件表中的条目,并递减系统打开文件表中的计数。当所有打开该文件的用户关闭它时,任何更新的元数据落盘,并且删除系统表中的条目。

2.3 分区与挂载

分区并不一定得有文件系统,没有格式化的分区也可以使用,称为裸盘,原始磁盘 (raw disk)。例如,UNIX 的交换空间就是使用的裸盘,数据库也经常使用。
根分区,包括 OS 内核和其它系统文件在启动时挂载。其它卷可以在引导时自动挂载或在启动后手动挂载,取决于 OS。
挂载的实现一般时标记某个 FCB 为挂载点,同时在其里写入安装表中条目的指针,即完成挂载。

2.4 虚拟文件系统

VFS 实际上就是 OOP 技术的一种体现,通过中间层来屏蔽底层多种实现。

3. 目录实现

  • 线性表。主要是复杂度偏高
  • 哈希表。主要是扩容,可能需要借助一致性哈希算法
  • 平衡树。

4. 分配方法

4.1 连续分配

连续分配的好处是,简单,支持顺序访问和直接访问,对于磁盘结构,读取效率高。缺点是,本质上是一个动态存储分配问题,也就存在这类型问题的所有问题,如外部碎片,如何快速找到一个最好的可用分配,文件增大怎么做。
外部碎片可以通过复制-整理算法来做,这个技术在垃圾回收算法中常用。存在 STW 问题,而且需要额外存储空间来做整理。文件增大一般通过扩展来解决,即一开始先分配一块,如果增大,再分配一块,第一块链接到后一块上。

4.2 链接分配

链接分配解决了上述所有问题,但是不能有效支持文件的随机访问。顺序访问的情况下,与索引分配一样,对于磁盘结构,可能效率低下,因为要不停旋转磁盘头。同时,因为链接指针需要空间,所以有效存储率变低了。
链接分配的一个重要变种就是文件分配表(File Allocation Table, FAT),广泛用于 MS-DOS。每个卷的开头部分的磁盘存储一张表,表里存储了卷上的所有块的指针,从而解决随机访问的问题。

4.3 索引分配

索引分配将所有指针放在一起形成索引块,解决随机访问的问题。每个 FCB 里存储了各自的索引块。
UNIX 文件系统使用一种组合策略来优化索引的存储,inode 的前12 个指针是直接索引,直接指向文件的数据块的地址;接下来的 3 个指针指向间接块,分别是一级间接块、二级间接块、三级间接块,对应二级、三级、四级索引。

5. 空闲空间管理

为了跟踪空闲磁盘空间,需要维护一个空闲空间列表。创建和删除文件块都需要修改这个空闲空间列表。一般通过位图来实现,例如 UNIX;也可以通过链表等。

后面还包括对效率、性能、恢复、一致性、NFS 的讨论,这里不再总结。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • Linux系统一般有4个主要部分:内核、shell、文件系统和应用程序。 内核、shell和文件系统一起形成了基本...
    请爱护小动物阅读 2,538评论 0 22
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 4,970评论 0 9
  • 1、文件和文件系统 文件管理:把所管理的程序和数据组织成一系列的文件,并能进行合理的存储、使用等操作。 1 )基本...
    盆栽木只阅读 1,291评论 0 0
  • 一、文件与文件系统 1.1 文件是什么 文件是对磁盘的抽象 所谓文件是指一组带标识(标识即为文件名)的、在逻辑上有...
    yjaal阅读 2,644评论 0 3
  • 21.1文件系统的概念 21.1.1文件系统和文件 ■文件系统是操作系统中管理持久性数据的子系统,提供数据存储和访...
    龟龟51阅读 716评论 0 4