Linux 文件系统简介

805 位读者喜欢这篇文章。
Penguins on beach

原始照片由 Rikki Endsley 拍摄。 CC BY-SA 4.0

本文旨在对 Linux 文件系统概念进行非常概括的讨论。它并非旨在对特定文件系统类型(如 EXT4)的工作原理进行低级别描述,也并非旨在作为文件系统命令的教程。

每台通用计算机都需要在硬盘驱动器 (HDD) 或某些等效设备(例如 USB 记忆棒)上存储各种类型的数据。这有两个原因。首先,RAM 在计算机关闭时会丢失其内容。存在非易失性 RAM 类型,可以在断电后维护存储在那里的数据(例如 USB 记忆棒和固态驱动器中使用的闪存 RAM),但闪存 RAM 比标准易失性 RAM(如 DDR3 和其他类似类型)贵得多。

数据需要存储在硬盘上的第二个原因是,即使是标准 RAM 也比磁盘空间更昂贵。RAM 和磁盘成本都在迅速下降,但 RAM 在每字节成本方面仍然领先。根据 16GB RAM 与 2TB 硬盘的成本进行的快速计算表明,RAM 的单位成本大约是硬盘的 71 倍。如今,RAM 的典型成本约为每字节 0.0000000043743750 美元。

为了快速回顾历史,以便了解当前的 RAM 成本,在计算机的早期,一种内存类型是基于 CRT 屏幕上的点。这非常昂贵,大约每比特 1.00 美元!

定义

您可能会听到人们以多种不同且令人困惑的方式谈论文件系统。“文件系统”这个词本身可以有多种含义,您可能需要从讨论或文档的上下文中辨别正确的含义。

我将尝试根据我观察到的“文件系统”一词在不同情况下的使用方式来定义其各种含义。请注意,虽然我试图符合标准的“官方”含义,但我的目的是根据其各种用法来定义该术语。这些含义将在本文的后续章节中更详细地探讨。

  1. 整个 Linux 目录结构从顶部 (/) 根目录开始。
  2. 一种特定的数据存储格式,例如 EXT3、EXT4、BTRFS、XFS 等。Linux 支持近 100 种文件系统类型,包括一些非常旧的以及一些最新的。每种文件系统类型都使用自己的元数据结构来定义数据的存储和访问方式。
  3. 使用特定类型的文件系统格式化的分区或逻辑卷,可以挂载到 Linux 文件系统上的指定挂载点。

基本文件系统功能

磁盘存储是一种必需品,它带来了一些有趣且不可避免的细节。显然,文件系统旨在为数据的非易失性存储提供空间;这是它的最终功能。但是,还有许多其他重要功能由此需求衍生而来。

所有文件系统都需要提供命名空间——即命名和组织方法。这定义了如何命名文件,特别是文件名的长度以及可用于文件名的字符子集(从可用字符的总集中)。它还定义了磁盘上数据的逻辑结构,例如使用目录来组织文件,而不是将它们全部堆积在一个庞大的文件集合中。

一旦定义了命名空间,就需要元数据结构来为该命名空间提供逻辑基础。这包括支持分层目录结构所需的数据结构;确定磁盘上哪些空间块已使用,哪些可用的结构;允许维护文件名和目录名的结构;有关文件的信息,例如其大小以及创建、修改或上次访问的时间;以及文件数据在磁盘上的位置。其他元数据用于存储有关磁盘细分的高级信息,例如逻辑卷和分区。这种更高级别的元数据及其表示的结构包含描述存储在驱动器或分区上的文件系统的信息,但与文件系统元数据是分开且独立的。

文件系统还需要应用程序编程接口 (API),该接口提供对系统功能调用的访问,这些调用操作文件系统对象(如文件和目录)。API 提供诸如创建、移动和删除文件等任务。它还提供算法,用于确定文件在文件系统上的位置等。此类算法可能考虑速度或最大限度地减少磁盘碎片等目标。

现代文件系统还提供安全模型,这是一种用于定义文件和目录访问权限的方案。Linux 文件系统安全模型有助于确保用户只能访问自己的文件,而不能访问其他用户或操作系统本身的文件。

最后一个构建块是实现所有这些功能所需的软件。Linux 使用两部分软件实现来提高系统和程序员的效率。


图 1:Linux 两部分文件系统软件实现。

此两部分实现的第一部分是 Linux 虚拟文件系统。此虚拟文件系统为内核和开发人员提供了一组用于访问所有类型文件系统的命令。虚拟文件系统软件调用特定的设备驱动程序,该驱动程序是与各种类型的文件系统接口所必需的。特定于文件系统的设备驱动程序是实现的第二部分。设备驱动程序将标准的文件系统命令解释为特定于分区或逻辑卷上的文件系统类型的命令。

目录结构

作为一个通常非常有条理的处女座,我喜欢将东西存储在较小的、有组织的组中,而不是在一个大桶中。目录的使用帮助我能够存储文件,然后在查找文件时找到我想要的文件。目录也称为文件夹,因为可以将它们视为文件夹,文件保存在其中,类似于物理桌面类比。

在 Linux 和许多其他操作系统中,目录可以构建成树状层次结构。Linux 目录结构在Linux 文件系统层次标准 (FHS) 中得到了很好的定义和记录。当访问这些目录时,通过使用由正斜杠 (/) 连接的顺序更深的目录名称(例如 /var/log 和 /var/spool/mail)来引用它们。这些称为路径。

下表简要列出了标准的、众所周知的和已定义的顶级 Linux 目录及其用途。

目录 描述
/ (根文件系统) 根文件系统是文件系统的顶层目录。它必须包含引导 Linux 系统所需的所有文件,然后才能挂载其他文件系统。它必须包含引导其余文件系统所需的所有必需的可执行文件和库。系统启动后,所有其他文件系统都作为根文件系统的子目录挂载在标准的、明确定义的挂载点上。
/bin /bin 目录包含用户可执行文件。
/boot 包含引导 Linux 计算机所需的静态引导加载程序和内核可执行文件以及配置文件。
/dev 此目录包含连接到系统的每个硬件设备的设备文件。这些不是设备驱动程序,而是表示计算机上每个设备并方便访问这些设备的文件。
/etc 包含主机计算机的本地系统配置文件。
/home 用于用户文件的主目录存储。每个用户在 /home 中都有一个子目录。
/lib 包含引导系统所需的共享库文件。
/media 用于挂载外部可移动媒体设备(例如可能连接到主机的 USB 拇指驱动器)的位置。
/mnt 用于常规文件系统(即非可移动媒体)的临时挂载点,管理员可以在修复或处理文件系统时使用。
/opt 可选文件(例如供应商提供的应用程序)应位于此处。
/root 这不是根 (/) 文件系统。它是 root 用户的主目录。
/sbin 系统二进制文件。这些是用于系统管理的可执行文件。
/tmp 临时目录。操作系统和许多程序使用它来存储临时文件。用户也可以在此处临时存储文件。请注意,存储在此处的文件可能会在没有任何事先通知的情况下随时删除。
/usr 这些是可共享的只读文件,包括可执行二进制文件和库、man 文件以及其他类型的文档。
/var 可变数据文件存储在此处。这可以包括日志文件、MySQL 和其他数据库文件、Web 服务器数据文件、电子邮件收件箱等等。

表 1:Linux 文件系统层次结构的顶层。

表 1 中显示的目录及其子目录,以及具有青色背景的子目录,被认为是根文件系统的组成部分。也就是说,它们不能作为单独的文件系统创建并在启动时挂载。这是因为它们(特别是它们的内容)必须在启动时存在,系统才能正常启动。

/media 和 /mnt 目录是根文件系统的一部分,但它们永远不应包含任何数据。相反,它们只是临时挂载点。

其余目录(表 1 中没有背景颜色的目录)在启动序列期间不需要存在,但会在稍后启动序列期间挂载,启动序列准备主机以执行有用的工作。

请务必参考官方Linux 文件系统层次标准 (FHS) 网页,了解有关这些目录及其许多子目录的详细信息。维基百科也对 FHS 进行了很好的描述。应尽可能严格地遵守此标准,以确保操作和功能的一致性。无论主机上使用何种文件系统类型,此分层目录结构都是相同的。

Linux 统一目录结构

在某些非 Linux PC 操作系统中,如果有多个物理硬盘驱动器或多个分区,则每个磁盘或分区都分配一个驱动器号。有必要知道文件或程序位于哪个硬盘驱动器上,例如 C: 或 D:。然后,您发出驱动器号作为命令,例如 D:,以更改为 D: 驱动器,然后使用 cd 命令更改到正确的目录以找到所需的文件。每个硬盘驱动器都有自己单独且完整的目录树。

Linux 文件系统将所有物理硬盘驱动器和分区统一到一个目录结构中。一切都从顶部开始——根 (/) 目录。所有其他目录及其子目录都位于单个 Linux 根目录下。这意味着只有一个目录树可用于搜索文件和程序。

这之所以可行,只是因为文件系统(例如 /home、/tmp、/var、/opt 或 /usr)可以在单独的物理硬盘驱动器、不同的分区或与 / (根) 文件系统不同的逻辑卷上创建,然后作为根文件系统树的一部分挂载到挂载点(目录)上。即使是可移动驱动器(例如 USB 拇指驱动器或外部 USB 或 ESATA 硬盘驱动器)也将挂载到根文件系统上,并成为该目录树的组成部分。

这样做的一个好处在从一个版本的 Linux 发行版升级到另一个版本或从一个发行版更改为另一个发行版时很明显。一般来说,除了 Fedora 中的 dnf-upgrade 等任何升级实用程序之外,明智的做法是在升级期间偶尔重新格式化包含操作系统的硬盘驱动器,以彻底清除随着时间推移积累的任何垃圾。如果 /home 是根文件系统的一部分,它也将被重新格式化,然后必须从备份中恢复。通过将 /home 作为单独的文件系统,安装程序会将其识别为单独的文件系统,并且可以跳过对其进行格式化。这也适用于 /var,其中存储了数据库、电子邮件收件箱、网站以及其他可变用户和系统数据。

将 Linux 目录树的某些部分维护为单独的文件系统还有其他原因。例如,很久以前,当我还不了解将所有必需的 Linux 目录作为 / (根) 文件系统的一部分可能存在潜在问题时,我设法用大量非常大的文件填满了我的主目录。由于 /home 目录和 /tmp 目录都不是单独的文件系统,而只是根文件系统的子目录,因此整个根文件系统都满了。操作系统没有剩余空间来创建临时文件或扩展现有数据文件。起初,应用程序开始抱怨没有空间保存文件,然后操作系统本身开始表现得非常奇怪。启动到单用户模式并清除我的主目录中的违规文件让我能够重新启动。然后,我使用相当标准的 多文件系统设置重新安装了 Linux,并且能够防止再次发生完全系统崩溃。

我曾经遇到过这样一种情况:Linux 主机继续运行,但阻止用户使用 GUI 桌面登录。我能够使用命令行界面 (CLI) 在本地使用虚拟控制台之一登录,并使用 SSH 远程登录。问题是 /tmp 文件系统已满,GUI 桌面所需的某些临时文件在登录时无法创建。由于 CLI 登录不需要在 /tmp 中创建文件,因此那里的空间不足并没有阻止我使用 CLI 登录。在这种情况下,/tmp 目录是一个单独的文件系统,并且 /tmp 逻辑卷所属的卷组中有足够的可用空间。我只是扩展了 /tmp 逻辑卷,使其大小足以满足我对该主机上所需临时文件空间量的全新理解,问题就解决了。请注意,此解决方案不需要重新启动,并且一旦 /tmp 文件系统扩大,用户就可以登录桌面。

另一种情况发生在我曾在一家大型科技公司担任实验室管理员期间。我们的一位开发人员将应用程序安装在错误的位置 (/var)。该应用程序崩溃了,因为 /var 文件系统已满,并且由于缺少空间,无法将存储在 /var/log 文件系统中的日志文件附加新消息。但是,系统仍然保持运行,因为关键的 / (根) 和 /tmp 文件系统没有满。删除违规应用程序并将其重新安装到 /opt 文件系统中解决了该问题。

文件系统类型

Linux 支持读取大约 100 种分区类型;它只能创建和写入其中的少数几种。但是,可以将不同类型的文件系统挂载在同一个根文件系统上,这是可能且非常常见的。在这种情况下,我们谈论的文件系统是指存储和管理硬盘分区或逻辑卷上的用户数据所需的结构和元数据。此处提供了 Linux fdisk 命令识别的文件系统分区类型的完整列表,以便您可以了解 Linux 与多种系统的高度兼容性。

 0  Empty           24  NEC DOS         81  Minix / old Lin bf  Solaris
 1  FAT12           27  Hidden NTFS Win 82  Linux swap / So c1  DRDOS/sec (FAT-
 2  XENIX root      39  Plan 9          83  Linux           c4  DRDOS/sec (FAT-
 3  XENIX usr       3c  PartitionMagic  84  OS/2 hidden or  c6  DRDOS/sec (FAT-
 4  FAT16 <32M      40  Venix 80286     85  Linux extended  c7  Syrinx
 5  Extended        41  PPC PReP Boot   86  NTFS volume set da  Non-FS data
 6  FAT16           42  SFS             87  NTFS volume set db  CP/M / CTOS / .
 7  HPFS/NTFS/exFAT 4d  QNX4.x          88  Linux plaintext de  Dell Utility
 8  AIX             4e  QNX4.x 2nd part 8e  Linux LVM       df  BootIt
 9  AIX bootable    4f  QNX4.x 3rd part 93  Amoeba          e1  DOS access
 a  OS/2 Boot Manag 50  OnTrack DM      94  Amoeba BBT      e3  DOS R/O
 b  W95 FAT32       51  OnTrack DM6 Aux 9f  BSD/OS          e4  SpeedStor
 c  W95 FAT32 (LBA) 52  CP/M            a0  IBM Thinkpad hi ea  Rufus alignment
 e  W95 FAT16 (LBA) 53  OnTrack DM6 Aux a5  FreeBSD         eb  BeOS fs
 f  W95 Ext'd (LBA) 54  OnTrackDM6      a6  OpenBSD         ee  GPT
10  OPUS            55  EZ-Drive        a7  NeXTSTEP        ef  EFI (FAT-12/16/
11  Hidden FAT12    56  Golden Bow      a8  Darwin UFS      f0  Linux/PA-RISC b
12  Compaq diagnost 5c  Priam Edisk     a9  NetBSD          f1  SpeedStor
14  Hidden FAT16 <3 61  SpeedStor       ab  Darwin boot     f4  SpeedStor
16  Hidden FAT16    63  GNU HURD or Sys af  HFS / HFS+      f2  DOS secondary
17  Hidden HPFS/NTF 64  Novell Netware  b7  BSDI fs         fb  VMware VMFS
18  AST SmartSleep  65  Novell Netware  b8  BSDI swap       fc  VMware VMKCORE
1b  Hidden W95 FAT3 70  DiskSecure Mult bb  Boot Wizard hid fd  Linux raid auto
1c  Hidden W95 FAT3 75  PC/IX           bc  Acronis FAT32 L fe  LANstep
1e  Hidden W95 FAT1 80  Old Minix       be  Solaris boot    ff  BBT

支持读取如此多种分区类型的主要目的是为了与其他计算机系统的文件系统兼容,并至少实现一定的互操作性。使用 Fedora 创建新文件系统时可用的选项如下列表所示。

  • btrfs
  • cramfs
  • ext2
  • ext3
  • ext4
  • fat
  • gfs2
  • hfsplus
  • minix
  • msdos
  • ntfs
  • reiserfs
  • vfat
  • xfs

其他发行版支持创建不同的文件系统类型。例如,CentOS 6 仅支持创建上面列表中以粗体突出显示的文件系统。

挂载

在 Linux 中,“挂载”文件系统这一术语可以追溯到计算机的早期,当时磁带或可移动磁盘包需要物理挂载到适当的驱动器设备上。在物理放置到驱动器上之后,磁盘包上的文件系统将由操作系统逻辑挂载,以使操作系统、应用程序和用户可以访问其内容。

挂载点只是一个目录,与任何其他目录一样,它是作为根文件系统的一部分创建的。例如,主文件系统挂载在 /home 目录上。文件系统可以挂载在非根文件系统上的挂载点上,但这不太常见。

Linux 根文件系统在启动序列的早期挂载在根目录 (/) 上。其他文件系统稍后由 Linux 启动程序挂载,在 SystemV 下由 rc 挂载,或在较新的 Linux 版本中由 systemd 挂载。启动过程中文件系统的挂载由 /etc/fstab 配置文件管理。记住这一点的一个简单方法是 fstab 代表“文件系统表”,它是一个要挂载的文件系统列表、其指定的挂载点以及特定文件系统可能需要的任何选项。

文件系统使用 mount 命令挂载到现有目录/挂载点上。一般来说,用作挂载点的任何目录都应该是空的,并且不应包含任何其他文件。Linux 不会阻止用户将一个文件系统挂载到已有的文件系统之上,或者挂载到包含文件的目录之上。如果您将文件系统挂载到现有目录或文件系统上,则原始内容将被隐藏,并且仅新挂载的文件系统的内容可见。

结论

我希望本文已经澄清了围绕“文件系统”一词的一些可能存在的困惑。我花了很长时间,并且一位非常有帮助的导师帮助我真正理解和欣赏 Linux 文件系统在其所有含义中的复杂性、优雅性和功能性。

如果您有任何问题,请将其添加到下面的评论中,我会尽力回答。

下个月

另一个重要的概念是,对于 Linux 来说,一切皆文件。这个概念对于用户和系统管理员来说有一些有趣且重要的实际应用。我之所以提到这一点,是因为您可能想在阅读我计划在下个月发表的关于 /dev 目录的文章之前,先阅读我的“一切皆文件”文章。

David Both
David Both 是一位开源软件和 GNU/Linux 倡导者、培训师、作家和演讲者。自 1996 年以来,他一直从事 Linux 和开源软件方面的工作,自 1969 年以来一直从事计算机方面的工作。他是“系统管理员 Linux 哲学”的坚定拥护者和传播者。

11 条评论

要查看系统上挂载的内容,请键入

mount | column -t

有关详细信息,请参阅“man mount”和“man column”。

我最近发现了 lsblk 命令,发现 lsblk -f 为我提供了主机上挂载的文件系统的清晰概览。

感谢您的评论。

回复 ,作者:Shawn H Corey

lsblk 非常适合获取系统上挂载的物理设备的概览,但它会遗漏任何虚拟文件系统挂载——最常见的是挂载为“tmpfs”类型的内存文件系统,现代 Linux 系统通常包含多个这种文件系统。

/tmp 和 /dev/shm 将出于性能原因保留在大多数系统的内存中(这就是为什么 /var/tmp 应该始终用于代替 /tmp 用于大型临时文件),并且 systemd 安装将 /run 和一个或多个 /run/user/$UID 也挂载在内存中。

df 或 df -h 将提供所有挂载(包括虚拟文件系统)的格式良好的列表,或者在提供它的发行版上,我更喜欢 di 的输出。

回复 ,作者:dboth

有很多方法可以做到这一点
cat /etc/mtab 或 column -t /etc/mtab
cat /proc/mounts
findmnt
sudo disk -l

我认为还有更多其他方法...

回复 ,作者:Shawn H Corey

非常有价值。谢谢,David。

David,这是一篇多么精彩的文章啊!

非常有用,非常感谢。

嗨,David,

很棒的概述!

前段时间,我曾致力于将嵌入式文件系统移植到 Linux 并进行基准测试,那时学习过程是非常自下而上的。我最初的大部分时间都花在了探索 VFS 数据结构和内核辅助函数的可怕细节上。花了一段时间才掌握从 posix 调用接口到块驱动程序的所有子系统是如何连贯地结合在一起的。

在某种程度上,最初的研究和基准测试是针对相对简单的 JFFS2、然后是 UBIFS,最后是带有块驱动程序的 EXT4 完成的,这有所帮助。这绝对是以复杂性递增的顺序进行的。探索 Linux 文件系统框架绝对是最苛刻的学习体验之一。

此外,还曾在我的网站上撰写了一些相关的帖子,说明这些发现 (https://msreekan.com/2015/04/24/linux-storage-cache/)。这有点是从嵌入式系统工程的角度来看的。现在我的工作已经从 Linux 转移了,但是看到这篇文章让我想起了整个经历。

Creative Commons License本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.