什么是文件系统?

如果你接触过Linux系统中的文件系统,相信你对下面这些名词肯定不会陌生,例如:ext2, ext3, ext4, FAT, FAT32, tmpfs, rootfs, NTFS, YAFFS, sysfs, procfs 等等。俺滴神啊,怎么会有这么多不同类型的文件系统啊,那么文件系统到底是个什么东西呢?

下面是引用自Wikipedia上关于文件系统的介绍:

在计算机系统中,文件系统(file system)是一种存储和组织数据的一种方法,它使得对数据发访问和查找变得更加容易。

文件系统使用文件树形目录的抽象逻辑概念代替了硬盘和光盘等物理存储设备所用的数据块的概念,用户使用文件系统来保存数据而不必关系数据实际保存在物理存储设备的地址为多少的数据块中,用户只需要记住这个文件的所属目录和文件名即可。在写入数据之前,用户也不必关心硬盘上哪个数据块没有被使用,所有的物理存储设备的存储空间的分配和释放功能都是由文件系统自动完成,用户只需要记住数据被写入到了哪个文件中。

文件系统可以用来在不同的物理存储介质上存储和组织数据,通常最常见的物理存储设备是硬盘,光盘以及Flash,磁带等等。但是,在某些情况下文件系统也可以使用内存(random-access memory,RAM)作为文件的存储介质,例如tmpfs,当文件存储在这种存储介质上时,一旦计算机掉电之后,该介质上面的所有文件就都消失了。甚至有的文件系统可能根本没有对应的文件,例如如proc文件系统。

什么是 ramfs?

Ramfs 是一个空间大小动态可变的基于 RAM 的文件系统,它是Linux 用来实现磁盘缓存(page cache and dentry cache)的文件系统。

ramfs 是一个仅存在与内存中文件系统,它没有后备存储(例如磁盘),也就是说 ramfs 文件系统所管理的文件都是存放在内存中,而不存放在磁盘中,如果计算机掉电关闭,那么 ramfs 文件系统中所有文件也就都没有了。

当普通磁盘中的文件被操作系统加载到内存中时,内核会分配 page 来存储文件中的内容,然后进程通过读写内存中文件对应的 page 实现对文件的读写修改操作,当完成了所有的读写操作之后,文件对应的 page 就会被标记为脏页,然后在合适的时机被操作系统写回到原来的磁盘中对应的文件中,内存中原来存放这些文件的 page 就会被标记为干净,最后被系统回收重新使用。而 ramfs 文件系统中的文件当同样被加载到内存中 page 进行读写操作之后,它对应的 page 并不会被标记为脏页,因为 ramfs 中文件没有下级的后备存储器(例如,磁盘),也就没有了写回后备存储器的操作,所以为它分配的这些 page 也就无法回收了。

什么是 tmpfs?

ramfs 中有一个非常大的缺点就是你可以持续不断地向 ramfs 文件系统中的文件持续不断地写入数据直到填满整个物理内存空间为止。出现这个问题的原因就是前面介绍的 ramfs 文件系统不存在向普通磁盘那样的将内存中的文件内容写回到文件的操作,也就导致了它所占据的那部分内存空间是无法被释放的,正是因为这个原因,通常只有 root 用户才有读写 ramfs 文件系统中文件的权限。

tmpfs 文件系统是从 ramfs 衍生而来的一个文件系统,但是它相对于 ramfs 多了空间容量大小限制,并且还可以将文件系统中一些不必要的的文件内容写到交换空间中(swap space)。并且 tmpfs 文件系统的大小还可以通过 mount -o remount ... 命令来重新调整。

有关 tmpfs 更加详细的内容可以查看内核源码中的文档:Documentation/filesystems/tmpfs.txt

什么是 rootfs?

rootfs(也叫根文件系统) 它本质上就是一个 Linux 系统中基本的文件目录组织结构,也就是 Linux 系统中 / 根目录下的结构,例如,/boot 目录下存放的是启动内核相关的文件,/etc 目录中存放的则是一些系统配置文件,/dev 目录下存放的则是系统的设备文件,/bin 目录下存放的则是一些可执行的二进制文件等等,在我的 Ubuntu 机器上的 / 根目录的结构如下所示:

.
├── bin
├── boot
├── cdrom
├── data
├── dev
├── etc
├── home
├── initrd.img -> boot/initrd.img-3.13.0-107-generic
├── lib
├── lib32
├── lib64
├── libx32
├── lost+found
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin
├── srv
├── sys
├── tmp
├── usr
├── var
└── vmlinuz -> boot/vmlinuz-4.2.0-27-generic

24 directories, 5 files

通常 rootfs 文件系统应该非常简洁,它只包含了它所必须用的文件,并且尽量避免少去修改 rootfs,以免破坏 rootfs,导致整个 Linux 系统无法启动。

Linux 系统的启动过程与 rootfs 也是密切相关,rootfs 可能会存在于存储在 RAM 存储设备中,也可能会存在硬盘设备中,这部分的我会在 Linux 系统的启动过程中作介绍。

什么是 initramfs?

initramfs 是一种以 cpio 格式压缩后的 rootfs 文件系统,它通常和 Linux 内核文件一起被打包成 boot.img 作为启动镜像,BootLoader 加载 boot.img,并启动内核之后,内核接着就对 cpio 格式的 initramfs 进行解压,并将解压后得到的 rootfs 加载进内存,最后内核会检查 rootfs 中是否存在 init 可执行文件(该 init 文件本质上是一个执行的 shell 脚本),如果存在,就开始执行 init 程序并创建 Linux 系统用户空间 PID 为 1 的进程,然后将磁盘中存放根目录内容的分区真正地挂载到 / 根目录上,最后通过 exec chroot . /sbin/init 命令来将 rootfs 中的根目录切换到挂载了实际磁盘分区文件系统中,并执行 /sbin/init 程序来启动系统中的其他进程和服务。

有关更加详细的 Linux Kernel + initramfs 的启动过程可以阅读下面这篇文章:深入理解Linux 2.6 的initramfs 机制

参考文章

  1. wiki-文件系统
  2. Root Filesystem Definition
  3. Kernel-doc:ramfs, rootfs and initramfs
  4. Kernel-doc: tmpfs
  5. 深入理解Linux 2.6 的initramfs 机制
  6. initramfs完全解读
  7. 跟我一步一步制作一个基本的linux启动盘