使用 Linux 系统时,需要作出的决策之一就是为存储设备选用什么文件系统。大多数 Linux 发行版在安装时会非常贴心地提供默认的文件系统,大多数入门级用户想都不想就用了默认的那个。
使用默认文件系统未必就不好,但了解一下可用的选择有时也会有所帮助。本章将探讨 Linux 世界里可选用的不同文件系统,并向你演示如何在命令行上进行创建和管理。
之前讨论了 Linux 如何通过文件系统来在存储设备上存储文件和目录。Linux 的文件系统为我们在硬盘中存储的 0 和 1 和应用中使用的文件与目录之间搭建起了一座桥梁。Linux 支持多种类型的文件系统管理文件和目录。每种文件系统都在存储设备上实现了虚拟目录结构,仅特性有所不同。本章将带你逐步了解 Linux 环境中较常用的文件系统的优点和缺陷。
Linux 最初采用的是一种简单的文件系统,它模仿了 Unix 文件系统的功能。本节将讨论这种文件系统的演进过程。
Linux 操作系统中引入的最早的文件系统叫作扩展文件系统(extended filesystem,简记为 ext)。它为 Linux 提供了一个基本的类 Unix 文件系统:使用虚拟目录来操作硬件设备,在物理设备上按定长的块来存储数据。
ext 文件系统采用名为索引节点的系统来存放虚拟目录中所存储文件的信息。索引节点系统在每个物理设备中创建一个单独的表(称为索引节点表)来存储这些文件的信息。存储在虚拟目录中的每一个文件在索引节点表中都有一个条目。ext 文件系统名称中的 extended 部分来自其跟踪的每个文件的额外数据,包括:
Linux 通过唯一的数值(称作索引节点号)来引用索引节点表中的每个索引节点,这个值是创建文件时由文件系统分配的。文件系统通过索引节点号而不是文件全名及路径来标识文件。
最早的 ext 文件系统有不少限制,比如文件大小不得超过 2 GB。在 Linux 出现后不久,ext 文件系统就升级到了第二代扩展文件系统,叫作 ext2。
如你所猜测的,ext2 文件系统是 ext 文件系统基本功能的一个扩展,但保持了同样的结构。ext2 文件系统扩展了索引节点表的格式来保存系统上每个文件的更多信息。
ext2 的索引节点表为文件添加了创建时间值、修改时间值和最后访问时间值来帮助系统管理员追踪文件的访问情况。ext2 文件系统还将允许的最大文件大小增加到了 2 TB(在 ext2 的后期版本中增加到了 32 TB),以容纳数据库服务器中常见的大文件。
除了扩展索引节点表外,ext2 文件系统还改变了文件在数据块中存储的方式。ext 文件系统常见的问题是在文件写入到物理设备时,存储数据用的块很容易分散在整个设备中(称作碎片化,fragmentation)。数据块的碎片化会降低文件系统的性能,因为需要更长的时间在存储设备中查找特定文件的所有块。
保存文件时,ext2 文件系统通过按组分配磁盘块来减轻碎片化。通过将数据块分组,文件系统在读取文件时不需要为了数据块查找整个物理设备。
多年来,ext 文件系统一直都是 Linux 发行版采用的默认文件系统。但它也有一些限制。索引节点表虽然支持文件系统保存有关文件的更多信息,但会对系统造成致命的问题。文件系统每次存储或更新文件,它都要用新信息来更新索引节点表。问题在于这种操作并非总是一气呵成的。
如果计算机系统在存储文件和更新索引节点表之间发生了什么,这二者的内容就不同步了。ext2 文件系统由于容易在系统崩溃或断电时损坏而臭名昭著。即使文件数据正常保存到了物理设备上,如果索引节点表记录没完成更新的话,ext2 文件系统甚至都不知道那个文件存在!很快开发人员就开始尝试开发不同的 Linux 文件系统了。
日志文件系统为 Linux 系统增加了一层安全性。它不再使用之前先将数据直接写入存储设备再更新索引节点表的做法,而是先将文件的更改写入到临时文件(称作日志,journal)中。在数据成功写到存储设备和索引节点表之后,再删除对应的日志条目。
如果系统在数据被写入存储设备之前崩溃或断电了,日志文件系统下次会读取日志文件并处理上次留下的未写入的数据。
Linux 中有 3 种广泛使用的日志方法,每种的保护等级都不相同
数据模式日志方法是目前为止最安全的数据保护方法,但同时也是最慢的。所有写到存储设备上的数据都必须写两次:第一次写入日志,第二次写入真正的存储设备。这样会导致性能很差,尤其是对要做大量数据写入的系统而言。
这些年来,在 Linux 上还出现了一些其他日志文件系统。下面将会讲述常见的 Linux 日志文件系统。
2001 年,ext3 文件系统被引入 Linux 内核中。它采用和 ext2 文件系统相同的索引节点表结构,但给每个存储设备增加了一个日志文件,以将准备写入存储设备的数据先记入日志。
默认情况下,ext3 文件系统用有序模式的日志功能——只将索引节点信息写入日志文件,直到数据块都被成功写入存储设备才删除。你可以在创建文件系统时用简单的一个命令行选项将 ext3 文件系统的日志方法改成数据模式或回写模式。
虽然 ext3 文件系统为 Linux 文件系统添加了基本的日志功能,但它仍然缺少一些功能。例如 ext3 文件系统无法恢复误删的文件,它没有任何内建的数据压缩功能(虽然有个需单独安装的补丁支持这个功能),ext3 文件系统也不支持加密文件。鉴于这些原因,Linux 项目的开发人员选择再接再厉,继续改进 ext3 文件系统。
扩展 ext3 文件系统功能的结果是 ext4 文件系统(你可能也猜出来了)。ext4 文件系统在 2008 年受到 Linux 内核官方支持,现在已是大多数流行的 Linux 发行版采用的默认文件系统。
除了支持数据压缩和加密,ext4 文件系统还支持一个称作区段(extent)的特性。区段在存储设备上按块分配空间,但在索引节点表中只保存起始块的位置。由于无需列出所有用来存储文件中数据的数据块,它可以在索引节点表中节省一些空间。
ext4 还引入了块预分配技术(block preallocation)。如果你想在存储设备上给一个你知道要变大的文件预留空间,ext4 文件系统可以为文件分配所有需要用到的块,而不仅仅是那些现在已经用到的块。ext4 文件系统用 0 填满预留的数据块,不会将它们分配给其他文件。
2001 年,Hans Reiser 为 Linux 创建了第一个称为 ReiserFS 的日志文件系统。ReiserFS 文件系统只支持回写日志模式——只把索引节点表数据写到日志文件。ReiserFS 文件系统也因此成为 Linux 上最快的日志文件系统之一。
有两个有意思的特性被引入了 ReiserFS 文件系统:一个是你可以在线调整已有文件系统的大小;另一个是被称作尾部压缩(tailpacking)的技术,该技术能将一个文件的数据填进另一个文件的数据块中的空白空间。如果你必须为已有文件系统扩容来容纳更多的数据,在线调整文件系统大小功能非常好用。
作为可能依然在用的最老的日志文件系统之一,JFS(Journaled File System)是 IBM 在 1990 年为其 Unix 衍生版 AIX 开发的。然而直到第 2 版,它才被移植到 Linux 环境中。
IBM 官方称 JFS 文件系统的第 2 版为 JFS2,但大多数 Linux 系统提到它时都只用 JFS。
JFS 文件系统采用的是有序日志方法,即只在日志中保存索引节点表数据,直到真正的文件数据被写进存储设备时才删除它。这个方法在 ReiserFS 的速度和数据模式日志方法的完整性之间的采取的一种折中。
JFS 文件系统采用基于区段的文件分配,即为每个写入存储设备的文件分配一组块。这样可以减少存储设备上的碎片。
除了用在 IBM Linux 上外,JFS 文件系统并没有流行起来,但你有可能在同 Linux 打交道的日子中碰到它。
XFS 日志文件系统是另一种最初用于商业 Unix 系统而如今走进 Linux 世界的文件系统。美国硅图公司(SGI)最初在 1994 年为其商业化的 IRIX Unix 系统开发了 XFS。2002 年,它被发布到了适用于 Linux 环境的版本。
XFS 文件系统采用回写模式的日志,在提供了高性能的同时也引入了一定的风险,因为实际数据并未存进日志文件。XFS 文件系统还允许在线调整文件系统的大小,这点类似于 ReiserFS 文件系统,除了 XFS 文件系统只能扩大不能缩小。
采用了日志式技术,你就必须在安全性和性能之间做出选择。尽管数据模式日志提供了最高的安全性,但是会对性能带来影响,因为索引节点和数据都需要被日志化。如果是回写模式日志,性能倒是可以接受,但安全性就会受到损害。
就文件系统而言,日志式的另一种选择是一种叫作写时复制(copy-on-write,COW)的技术。COW 利用快照兼顾了安全性和性能。如果要修改数据,会使用克隆或可写快照。修改过的数据并不会直接覆盖当前数据,而是被放入文件系统中的另一个位置上。即便是数据修改已经完成,之前的旧数据也不会被重写。COW 文件系统已日渐流行,接下来会简要概览其中最流行的两种(Btrf 和 ZFS)。
COW 文件系统 ZFS 是由 Sun 公司于 2005 年研发的,用于 OpenSolaris 操作系统,从 2008 年起开始向 Linux 移植,最终在 2012 年投入 Linux 产品的使用。
ZFS 是一个稳定的文件系统,与 Resier4、Btrfs 和 ext4 势均力敌。它最大的弱项就是没有使用 GPL 许可。自 2013 年发起的 OpenZFS 项目有可能改变这种局面。但是,在获得 GPL 许可之前,ZFS 有可能终无法成为 Linux 默认的文件系统。
Btrfs 文件系统是 COW 的新人,也被称为 B 树文件系统。它是由 Oracle 公司于 2007 年开始研发的。Btrfs 在 Reiser4 的诸多特性的基础上改进了可靠性。另一些开发人员最终也加入了开发过程,帮助 Btrfs 快速成为了最流行的文件系统。究其原因,则要归于它的稳定性、易用性以及能够动态调整已挂载文件系统的大小。OpenSUSE Linux 发行版将 Btrfs 作为其默认文件系统。除此之外,该文件系统也出现在了其他 Linux 发行版中(如 RHEL),Fedora 在 2020 年将 Btrfs 作为其默认文件系统。
Linux 提供了一些不同的工具,我们可以利用它们轻松地在命令行中进行文件系统操作。可使用键盘随心所欲地创建新的文件系统或者修改已有的文件系统。本节将会带你逐步了解命令行下的文件系统交互的命令。
一开始,你必须在存储设备上创建分区来容纳文件系统。分区可以是整个硬盘,也可以是部分硬盘,以容纳虚拟目录的一部分。此部分推荐使用的终端中好用的图形化 cfdisk 工具,除此之外,fdisk 也是一个使用广泛的传统工具,不过使用较为麻烦,不推荐使用。
要启动 cfdisk 命令,你必须指定要分区的存储设备的设备名,另外还得有超级用户权限。如果在没有对应权限的情况下使用该命令,你会得到类似于下面这种错误提示。
$ cfdisk /dev/sdb Unable to open /dev/sdb
有时候,创建新磁盘分区最麻烦的事情就是找出安装在 Linux 系统中的物理磁盘。Linux 采用了一种标准格式来为硬盘分配设备名称,但是你得熟悉这种格式。对于老式的 IDE 驱动器,Linux 使用的是/dev/hdx。其中 x 表示一个字母,具体是什么要根据驱动器的检测顺序(第一个驱动器是 a,第二个驱动器是 b,以此类推)。对于较新的 SATA 驱动器和 SCSI 驱动器,Linux 使用/dev/sdx。其中的 x 具体是什么也要根据驱动器的检测顺序(和之前一样,第一个驱动器是 a,第二个驱动器是 b,以此类推)。最新的 SSD 固态硬盘一般以/dev/nvme0nx 来标识。在格式化分区之前,最好再检查一下是否正确指定了驱动器。
如果你拥有超级用户权限并指定了正确的驱动器,那就可以进入 cfdisk 工具的操作界面了。
cfdisk 可以看到目前磁盘的详情,在界面下方有各类操作,可用方向键和回车进行选择,非常方便。一般的步骤是新建分区,输入大小,选择类型,最后写入退出即可。
在将数据存储到分区之前,你必须用某种文件系统对其进行格式化,这样 Linux 才能使用它。每种文件系统类型都用自己的命令行程序来格式化分区。如下列出了本章中讨论的不同文件系统所对应的工具。
并非所有文件系统工具都已经默认安装了。要想知道某个文件系统工具是否可用,可以使用 type 命令。
$ type mkfs.ext4 mkfs.ext4 是 /usr/bin/mkfs.ext4 $ type mkfs.btrfs -bash: type: mkfs.btrfs: not found
据上面这个取自 Ubuntu 系统的例子显示,mkfs.ext4 工具是可用的。而 Btrfs 工具则不可用。
不可用的工具请按发行版自行安装。
每个文件系统命令都有很多命令行选项,允许你定制如何在分区上创建文件系统。要查看所有可用的命令行选项,可用 man 命令来显示该文件系统命令的手册页面。所有的文件系统命令都允许通过不带选项的简单命令来创建一个默认的文件系统。
$ sudo mkfs.ext4 /dev/sdb1 mke2fs 1.45.6 (20-Mar-2020) 创建含有 3891192 个块(每块 4k)和 972944 个inode的文件系统 文件系统UUID:3f916991-2368-4d43-8b10-90b6a7c13445 超级块的备份存储于下列块: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208 正在分配组表: 完成 正在写入inode表: 完成 *创建日志*(16384 个块)完成 写入超级块和文件系统账户统计信息: 已完成
这个新的文件系统采用 ext4 文件系统类型,这是 Linux 上的日志文件系统。注意,创建过程中有一步是创建新的日志。
为分区创建了文件系统之后,下一步是将它挂载到虚拟目录下的某个挂载点,这样就可以将数据存储在新文件系统中了。你可以将新文件系统挂载到虚拟目录中需要额外空间的任何位置。
$ ls /mnt $ sudo mkdir /mnt/my_partition $ ls -al /mnt/my_partition/ $ #啥也没有 $ sudo mount -t ext4 /dev/sdb1 /mnt/my_partition $ ls -al /mnt/my_partition/ total 24 drwxr-xr-x. 3 root root 4096 Jun 11 09:53 . drwxr-xr-x. 3 root root 4096 Jun 11 09:58 .. drwx------. 2 root root 16384 Jun 11 09:53 lost+found
mkdir 命令在虚拟目录中创建了挂载点,mount 命令将新的硬盘分区添加到挂载点。mount 命令的-t 选项指明了要挂载的文件系统类型(ext4)。现在你可以在新分区中保存新文件和目录了!
这种挂载文件系统的方法只能临时挂载文件系统。当重启 Linux 系统时,文件系统并不会自动挂载。要强制 Linux 在启动时自动挂载新的文件系统,可以将其添加到/etc/fstab 文件。
现在文件系统已经被挂载了到虚拟目录中,可以投入日常使用了。遗憾的是,在日常使用过程中有可能会出现一些严重的问题,例如文件系统损坏。下一节将演示如何应对这种问题。
就算是现代文件系统,碰上突然断电或者某个不规矩的程序在访问文件时锁定了系统,也会出现错误。幸而有一些命令行工具可以帮你将文件系统恢复正常
每个文件系统都有各自可以和文件系统交互的恢复命令。这可能会让局面变得不太舒服,随着 Linux 环境中可用的文件系统变多,你也不得不去掌握大量对应的命令。好在有个通用的前端程序,可以决定存储设备上的文件系统并根据要恢复的文件系统调用适合的文件系统恢复命令。
fsck 命令能够检查和修复大部分类型的 Linux 文件系统,包括本章早些时候讨论过的 ext、ext2、ext3、ext4、ReiserFS、JFS、XFS、ZFS 以及 Btrfs。该命令的格式是:
fsck options /dev/sdX
你可以在命令行上列出多个要检查的文件系统。文件系统可以通过设备名、在虚拟目录中的挂载点以及分配给文件系统的唯一 UUID 值来引用。
fsck 命令使用/etc/fstab 文件来自动检查文件系统类型。如果存储设备从未被挂载(比如你刚刚在新的存储设备上创建了个文件系统,/etc/fstab 并无其信息),你需要用-t 命令行选项来指定文件系统类型。使用 man 或 tldr 查看其他可用的命令行选项。在使用 fsck 时,被检查的文件系统应该处在未挂载状态。
你可能注意到了,有些命令行选项是重复的。这是为多个命令实现通用的前端带来的部分问题。有些文件系统修复命令有一些额外的可用选项。如果要做更高级的错误检查,就需要查看这个文件系统修复工具的手册页面来确定是不是有该文件系统专用的扩展选项。
只能在未挂载的文件系统上运行 fsck 命令。对大多数文件系统来说,你只需卸载文件系统来进行检查,检查完成之后重新挂载就好了。但因为根文件系统含有所有核心的 Linux 命令和日志文件,所以你无法在处于运行状态的系统上卸载它。这正是亲手体验 Linux LiveCD 的好时机!只需用 LiveCD 启动系统即可,然后在根文件系统上运行 fsck 命令。
到目前为止,本章讲解了如何处理物理存储设备中的文件系统。Linux 还有另一些方法可以为文件系统创建逻辑存储设备。下一节将告诉你如何使用逻辑存储设备。