聊聊文件系统那些事

Catalogue
  1. 1. 前言
  2. 2. 磁盘
    1. 2.1. 磁盘分区
  3. 3. 文件系统
    1. 3.1. 文件系统与块
    2. 3.2. 文件系统与文件
      1. 3.2.1. inode
      2. 3.2.2. 目录项
  4. 4. 虚拟文件系统(VFS)
  5. 5. 文件系统组件的体系结构
  6. 6. 参考资料 & 鸣谢

前言

本文探究的主题是文件系统,学过操作系统的同学应该都有了解。个人觉得文件系统是操作系统比较重要的一部分内容,作为后端开发人员,肯定会有与文件打交道的时候,通过相关文件I/O函数读写文件,而学习文件系统可以让我们编写代码时做到心中有数,明白背后的逻辑

磁盘

磁盘是一种块设备,用于存储,这种块设备是在系统中能够随机(不需要按顺序)访问固定大小数据片的硬件设备

disk

图片来源:https://time.geekbang.org/column/article/98440

磁盘就是上图左边的样子,中间圆的部分是磁盘的盘片,右边的图是抽象出来的图。每一层里分多个磁道,每个磁道分多个扇区,每个扇区是 512 个字节。

磁盘分区

对于大型硬盘,可以将可用空间划分或分区为多个不同的分区,比如在windows系统上,将一块磁盘分区成C、D、E盘,这就叫做分区。

分区信息存储在磁盘上的分区表上,该表列出了每个分区的起点和终点信息、它的类型信息等,这些信息都存储在分区表中,而磁盘分区表主要有两种:MBR和GPT。前者是传统格式,兼容性好;后者更现代,功能更强大。

文件系统

文件系统实际上就是文件的存储方式,它存放在磁盘上的,磁盘被分成多个分区之后,每个分区都可以有一个独立的文件系统。而为硬盘安装文件系统的操作就被称为”格式化”,格式化就是将一块盘使用命令组织成一定格式的文件系统的过程,在Windows下,我们常格式化的格式是NTFS,而在Linux下面,常用的是ext2、ext3ext4

对硬盘完成分区和格式化以后,还需要将分区挂载 (mount) 到操作系统的某个目录下面,这样才能作为普通文件系统进行访问。被挂载的目录可以是根目录,也可以是其他二级、三级目录,任何目录都可以是挂载点,但是根目录是所有Linux的文件和目录所在的地方,需要挂载上一个磁盘分区

文件系统与块

操作系统在读取磁盘时,不会一个个扇区地读取,因为这样的效率太低了,而是一次性连续读取多个扇区,也就是一次性读取一个”块”。块的大小是扇区大小的2的整数倍,通常是4KB.

文件系统创建在磁盘之上,它将磁盘空间以为单位进行划分,也就是说,块是文件系统的最小寻址的单元,有时会被称作”文件块”或者”I/O”块。

sector_to_disk

文件系统与文件

在文件系统中,一个文件大体上可以由目录项inode数据块组成:

  • inode: 索引节点,存放数据块的指针
  • 目录项:包含文件名和inode节点号
  • 数据块:包含具体的文件内容

还有一个关注点是超级块,它会记录整个文件系统的整体信息,包括 inode 与 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等。

inode

inode,全称是index node,中文含义就是索引节点,它用来记录文件的元数据,比如 inode 编号、文件大小、访问权限、修改日期以及文件数据块的地址索引等,通过数据块的索引就可以找到具体的数据块。

inode

在ext3文件系统中inode有15个索引,其中前12个索引直接记录数据块的地址,第13个索引记录索引地址。也就是说,索引块指向的硬盘数据块并不直接记录文件数据,而是记录文件数据块的索引表,依次的,第 14 个索引记录二级索引地址,第 15 个索引记录三级索引地址,下面是示意图:

inode_ext3

图片来源:https://time.geekbang.org/column/article/169533

还有一点需要注意,索引节点和文件一一对应,它跟文件内容一样,需要持久化到磁盘,是占磁盘空间的。

目录项

在Linux系统中,目录(directory)也是一种文件,打开目录,也就是打开目录文件,目录文件的结构非常简单,就是一系列目录项(dirent)的列表。每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的inode号码。下面是示意图

inode_and_directory_entry

图片来源:http://www.pc-freak.net/blog/find-filesystem-directory-eating-filesystem-inodes-linux/

不同于索引节点,目录项是由内核维护的一个内存数据结构,所以通常也被叫做目录项缓存

虚拟文件系统(VFS)

一个磁盘可以被划分为多个分区,每个分区可以有不同的文件系统,也就是说,在操作系统中,可能会面临对不同文件系统的读写问题,那么如何去管理这些文件系统呢?

在Linux系统中,提供了一种虚拟文件系统(VFS),它是一种内核子系统,为用户空间程序提供了文件和具体文件系统相关的接口。换句话说,向上,对应用层提供一个标准的文件操作接口;对下,对具体的文件系统提供一个标准的接口。

为了支持多种文件系统,抽象一层,以衔接各种各样的文件系统。而这抽象层(也就是VFS),直接屏蔽掉具体的文件系统,从而使用户可以直接使用open()、read()和write()这样的函数而无须考虑具体文件系统和实际物理介质,如下图所示:

vfs

当计算机系统启动时,磁盘各分区上的文件系统需要向VFS注册,注册的时候,文件系统将提供一个包含VFS所需函数地址的列表,通过函数地址,VFS知道如何从文件系统中读取数据块。同时,VFS有一个超级块对象,各种文件系统都必须实现超级块对象,该对象用于存储特定文件系统的信息,通常对应于存放在磁盘特定扇区中的文件系统超级块

文件系统组件的体系结构

接下来,我们来梳理一下体系结构,从应用层到VFS,再到磁盘的一个结构图,从这个架构图中我们可以对文件系统有一个更加清晰的认识,如下图所示:

file system

从图中可以看到上文未提及的Page Cache与直接IO,实际上根据是否利用操作系统的页缓存,可以将文件I/O分为直接IO和非直接IO。

  • 直接IO: 不经过页缓存,直接访问磁盘数据
  • 非直接IO: 文件读写时,先要经过系统的页缓存,如果缓存中有数据中,直接读取;如果没有,再从磁盘中读取

Page Cache主要用来减少对磁盘的I/O操作,通过将磁盘中的数据缓存到物理内存中,把对磁盘的访问变为对物理内存的访问。

其实,还有一个Buffer Cache,它主要用来缓存磁盘块,用于块I/O,也就是对磁盘块数据的缓存,而Page Cache是文件数据的缓存,在Linux 2.4内核以前,两者是独立的,2.4之后就统一了,只有Page Cache,而Buffer是页映射块的,它实际上就是在Page Cache中。

参考资料 & 鸣谢

Bagikan Komentar