第十五章:存储介质

在前面的章节中,我们研究了在文件级别操纵数据。在本章中,我们将考虑设备级别的数据。Linux在处理存储设备方面具有惊人的能力,无论是物理存储,如硬盘、网络存储,还是虚拟存储设备,如RAID(Redundant Array of Independent Disks,独立磁盘冗余阵列)和LVM(Logical Volume Manager,逻辑卷管理器)。

然而,由于这不是一本关于系统管理的书,我们不会试图深入探讨整个主题。我们将尝试介绍一些用于管理存储设备的概念和关键命令。

要执行本章中的练习,我们将使用USB闪存驱动器、USB硬盘驱动器和CD-RW光盘(适用于配备CD-ROM刻录机的系统)。

我们将查看以下命令:

第十五章:存储介质挂载和卸载存储设备查看已装载文件系统列表为什么卸载很重要确定设备名称创建新文件系统使用 parted 操作分区使用 mkfs 创建新文件系统测试和修复文件系统什么是 fsck将数据直接移入和移出设备创建CD-ROM映像创建CD-ROM的映像副本从文件集合创建图像任何其他名称的程序...写入CD-ROM映像直接挂载ISO映像清空可重写CD-ROM写入映像验证数据总结

挂载和卸载存储设备

Linux桌面的最新进展使桌面用户的存储设备管理变得极其容易。在大多数情况下,我们将一个设备连接到我们的系统上,它“就正常工作了”。在过去(比如2004年),这些事情必须手动完成。在非桌面系统(即服务器)上,这仍然是一个很大程度上手动的过程,因为服务器通常具有极端的(extreme)存储需求和复杂的(complex)配置要求。

管理存储设备的第一步是将设备连接到文件系统树。这个过程称为挂载(mounting),允许设备与操作系统交互。正如我们在【第2章】中回忆的那样,类Unix操作系统,如Linux,维护着一个文件系统树,其中设备连接在不同的点上。这与MS-DOS和Windows等其他操作系统形成鲜明对比,这些操作系统为每个设备维护单独的文件系统树(例如 C:\D:\ 等)。

名为 /etc/fstab (“file system table,文件系统表”的缩写)的文件列出了在启动时要挂载的设备(通常是硬盘分区)。以下是早期Fedora系统中的 /etc/fstab 文件示例:

此示例文件中列出的大多数文件系统都是虚拟的,不适用于我们的讨论。就我们的目的而言,有趣的是前三个:

这些是硬盘分区。文件的每一行由六个字段组成,如下表所示:

字段内容解释
1设备传统上,此字段包含与物理设备关联的设备文件的实际名称,例如 /dev/sda1 (第一个检测到的硬盘的第一个分区)。但是,对于今天的计算机,其中有许多可热插拔的设备(如USB驱动器),许多现代Linux发行版将设备与文本标签(text label)相关联。此标签(在格式化时添加到存储介质中)可以是简单的文本标签,也可以是随机生成的UUID(Universally Unique Identifier,通用唯一标识符)。当设备连接到系统时,操作系统会读取此标签。这样,无论将哪个设备文件分配给实际的物理设备,它仍然可以被正确识别。
2挂载点设备连接到文件系统树的目录。
3文件系统Linux允许挂载多种类型的文件系统。大多数Linux系统使用称为第四扩展文件系统(Fourth Extended File System,ext4)的原生Linux文件系统,但支持许多其他文件系统,包括FAT16(msdos)、FAT32(vfat)、NTFS(NTFS)、CD-ROM(iso9660)等。
4选项文件系统可以通过各种选项进行挂载。例如,可以将文件系统挂载为只读或阻止从中执行任何程序(可移动介质的一个有用的安全功能)。
5频率一个数字,指定是否以及何时使用转储命令备份文件系统。
6顺序一个数字,指定使用fsck命令检查文件系统的顺序。本章稍后将对此进行详细介绍。

查看已装载文件系统列表

mount 命令用于挂载文件系统。输入不带参数的命令将显示当前装载的文件系统列表:

提示:Ubuntu用户会发现这个列表中充斥着由系统上安装的snap包创建的“循环(loop)”设备。要查看更清晰的列表,请尝试以下命令: mount | grep -v snap

列表的格式如下:

device on mount_point type file_system_type (options)

例如,第一行显示设备 /dev/sda2 作为根文件系统挂载,类型为 ext4 ,可读写(选项 rw )。此列表底部还有两个有趣的条目。倒数第二个条目显示了挂载在 /media/disk 上的读卡器中的2GB SD存储卡,最后一个条目是挂载在 /misc/musicbox 上的网络驱动器。

在我们的第一个实验中,我们将使用4GB的闪存驱动器。首先,让我们在插入驱动器之前看看Ubuntu 22.04系统:

为了清楚起见,我们通过 grep 将输出管道化,仅在列表中列出 /dev/sd* 设备。我们可以看到这个系统有两个硬盘,/dev/sda/dev/sdb/dev/sda 上有两个分区。它们是 /dev/sda1/dev/sda2 ,而 /dev/sdb 只有一个分区 /dev/sdb1

与许多现代Linux发行版一样,此系统将在插入后尝试自动挂载闪存驱动器。插入驱动器后,我们会看到以下内容:

插入驱动器后,我们看到与之前相同的列表,但有一个额外的条目。在列表末尾,我们看到闪存驱动器(在该系统上为设备 /dev/sdc )已挂载在 /media/me/C911-C314 上,类型为 vfat (也称为FAT32,一种与Windows兼容的文件系统)。为了我们的实验,我们对设备的名称感兴趣。当您自己进行此实验时,设备名称很可能会不同。

警告:在以下示例中,您必须密切关注系统上使用的实际设备名称,不要使用本文中使用的名称

现在我们有了闪存驱动器的设备名称,让我们卸载该驱动器,并在文件系统树中的另一个位置重新装载它。为此,我们成为超级用户(使用适合我们系统的命令),并使用 umount (注意拼写)命令卸载驱动器。

下一步是为磁盘创建一个新的挂载点(mount point)。挂载点只是文件系统树上某个位置的目录。这没什么特别的。它甚至不必是空目录,但如果你在非空目录上挂载设备,在卸载设备之前,你将无法看到目录的先前内容。为了我们的目的,我们将创建一个新目录。

最后,我们将闪存驱动器装载到新的装载点。 -t 选项用于指定文件系统类型。

之后,我们可以通过新的挂载点检查闪存驱动器的内容:

请注意,当我们尝试卸载驱动器时会发生什么:

这是为什么?原因是,如果设备正被某人或某个进程使用,我们就无法卸载该设备。在这种情况下,我们将工作目录更改为闪存驱动器的装载点,这会导致设备繁忙。我们可以通过将工作目录更改为挂载点以外的其他目录来轻松解决这个问题:

现在设备已成功卸载。

为什么卸载很重要

如果您查看显示内存使用统计信息的 free 命令的输出,您将看到一个名为 buffers 的统计信息。计算机系统被设计得尽可能快。系统速度的障碍之一是设备速度慢。打印机就是一个很好的例子。按照计算机标准,即使是最快的打印机也极其缓慢。如果计算机必须停下来等待打印机完成打印,那么它的速度确实会非常慢。在PC的早期(多任务处理之前),这是一个真正的问题。如果你正在处理电子表格或文本文档,每次打印时电脑都会停止运行,无法使用。计算机会以打印机可以接受的最快速度将数据发送到打印机,但由于打印机打印速度不是很快,所以速度非常慢。打印机缓冲区的出现解决了这个问题,这是一种包含一些RAM存储器的设备,可以放置在计算机和打印机之间。有了打印机缓冲区,计算机会将打印机输出发送到缓冲区,并将其快速存储在快速RAM中,这样计算机就可以重新开始工作,而无需等待。同时,打印机缓冲区会以打印机可以接受的速度,将数据从缓冲区的内存缓慢地传送到打印机。

这种缓冲的想法在计算机中被广泛使用,以使它们更快。不要让偶尔向慢速设备读写数据的需要阻碍系统的速度。操作系统在实际必须与较慢的设备交互之前,尽可能长时间地将已从存储设备读取和将要写入存储设备的数据存储在内存中。例如,在Linux系统上,您会注意到,使用时间越长,系统似乎就会填满内存。这并不意味着Linux正在“使用”所有内存;这意味着Linux正在利用所有可用内存进行尽可能多的缓冲。

这种缓冲允许非常快速地完成对存储设备的写入,因为对物理设备的写入被推迟到未来的时间。与此同时,发往该设备的数据正在内存中堆积。操作系统会不时地将此数据写入物理设备。

卸载设备需要将所有剩余数据写入设备,以便安全删除。如果未先卸载设备就将其删除,则可能并非所有发往该设备的数据都已传输。在某些情况下,这些数据可能包括重要的目录更新,这将导致文件系统损坏,这是计算机上可能发生的最糟糕的事情之一。

确定设备名称

有时很难确定设备的名称。在过去,这并不难。设备总是在同一个地方,它不会改变。类Unix系统就是这样。当Unix被开发出来时,“更换磁盘驱动器”涉及使用叉车从计算机房中取出洗衣机大小的设备。近年来,典型的桌面硬件配置变得相当动态,Linux已经进化到比其祖先更灵活。

在上面的例子中,我们利用了现代Linux桌面的“自动”(automagically)挂载设备的能力,然后在事后确定名称。但是,如果我们正在管理一个服务器或其他没有发生这种情况的环境呢?我们怎样才能弄清楚?

首先,让我们看看系统是如何命名设备的。如果我们列出 /dev 目录(所有设备所在的目录)的内容,我们可以看到有很多很多设备。

此列表的内容揭示了设备命名的一些模式。下表概述了其中一些模式:

范式设备
/dev/fd*软盘驱动器
/dev/hd*旧系统上的IDE(PATA)磁盘。这些系统上的主板包含两个IDE连接器或通道(channels),每个都有一根带有两个驱动器连接点的电缆。电缆上的第一个驱动器称为主(master)设备,第二个驱动器称为从(slave)设备。设备名称按顺序排列,/dev/hda 指第一个通道上的主设备,/dev/hdb 指第一个信道上的从设备;/dev/hdc 是第二个通道上的主设备,以此类推。尾随数字表示设备上的分区号。例如,/dev/hda1 表示系统上第一个硬盘驱动器上的第一个分区,而 /dev/hda 表示整个驱动器。
/dev/lp*打印机
/dev/sd*SCSI磁盘。在现代Linux系统上,内核将所有类似磁盘的设备(包括PATA/SATA硬盘、闪存驱动器和USB大容量存储设备,如便携式音乐播放器和数码相机)视为SCSI磁盘。命名系统的其余部分与上述旧的 /dev/hd* 命名方案相似。
/dev/sr*光驱(CD/DVD读取器和刻录机)

此外,我们经常看到符号链接,如 /dev/cdrom/dev/dvd/dev/floppy ,它们指向实际的设备文件,这是为了方便而提供的。

如果我们在一个不能自动挂载可移动设备的系统上工作,我们可以使用以下技术来确定可移动设备在连接时的命名方式。首先,启动 /var/log/messages/var/log/syslog 文件的实时视图(您可能需要超级用户权限):

在基于systemd的现代系统上,使用此命令跟踪systemd日志:

将显示列表的最后几行,然后暂停。接下来,插入可拆卸设备。在这个例子中,我们将卸载并移除闪存驱动器,然后重新插入。内核几乎会立即注意到该设备并对其进行探测。

显示再次暂停后,按 Ctrl-c 返回提示。输出中有趣的部分是对 [sdc] 的重复引用,这与我们对SCSI磁盘设备名称的期望相匹配。知道这一点,这两行变得特别有启发性:

提示:使用 tail -f /var/log/syslogjournalctl -f 技术是近实时查看系统运行情况的好方法。

还有一种方法可以确定设备名称(在Linux中总是有多种方法!)。我们可以使用 lsblk 命令。此命令列出了连接到系统的所有块设备,无论它们是否已安装。

假设我们已经卸载并删除了闪存驱动器,我们可以查看连接的块设备列表:

接下来,我们将重新插入闪存驱动器并再次运行 lsblk

我们现在看到一个新设备(sdc)已添加到列表中。只要设备仍物理连接到计算机并且计算机未重新启动,设备名称将保持不变。

有了我们的设备名称,我们就可以挂载闪存驱动器了。

创建新文件系统

假设我们有一个带有单个FAT32文件系统的外部USB硬盘,并希望将驱动器分为两个分区,一个是Linux本机文件系统(ext4),另一个是格式化为NTFS的分区,用于Windows系统。这涉及两个步骤:

  1. 创建新的分区布局。
  2. 在驱动器上创建新的空文件系统。

警告!在下面的练习中,我们将格式化外部硬盘。使用不包含任何您关心的内容的驱动器,因为它将被擦除!同样,请务必为您的系统指定正确的设备名称,而不是文本中显示的名称。不注意此警告可能会导致您格式化(即擦除)错误的驱动器!

使用 parted 操作分区

parted 是一系列程序(包括命令行和图形)之一,它允许我们在非常低的级别上直接与类磁盘设备(如硬盘驱动器和闪存驱动器)进行交互。我们将连接驱动器并使用 lsblk 获取其名称:

如我们所见,外部USB硬盘已连接,名为 /dev/sdd ,其中包含一个名为 /dev/sdd1 的分区。

使用 parted ,我们可以在设备上编辑、删除和创建分区。要使用我们的硬盘,我们必须首先卸载它(如果需要),然后按如下方式调用 parted 程序:

请注意,我们必须根据整个设备来指定设备,而不是通过分区号。程序启动后,我们将看到以下提示:

输入 help 将显示可用命令的列表:

我们要做的第一件事是检查现有的分区布局。我们通过输入 print 命令来打印设备的分区表:

我们可以看到,我们的磁盘在单个FAT32分区中有250 GB的空间。

要创建新分区,我们必须首先删除当前分区。这很容易用 rm 命令完成:

我们指定要删除的分区号,然后再次查看分区表,查看分区是否已消失。

接下来,我们将创建新的分区。我们使用 mkpart 命令执行此操作。

在这个磁盘上创建分区时(它有一个MBR,主引导记录样式的分区表),我们指定一个主分区或扩展分区,然后以默认的一兆字节增量指定分区的开始和结束。使用120000 MB的最终值会消耗驱动器上大约一半的可用空间。

接下来,我们将使用相同的技术创建第二个分区。

最后,我们查看分区表以查看结果:

现在我们的分区已经完成,我们可以退出 parted 程序了:

如果我们再次运行 lsblk,我们可以看到我们的驱动器及其两个分区。

使用 mkfs 创建新文件系统

完成分区编辑后,是时候在驱动器上创建(即格式化)新的文件系统了。为此,我们将使用 mkfs (“make file system”的缩写),它可以创建各种格式的文件系统。要在驱动器上创建 ext4 文件系统,我们使用-t选项指定 ext4 文件系类型,后面是描述性卷标,以及包含要格式化的分区的设备名称。

接下来,我们将进行NTFS分区。

我们再次指定文件系统类型、描述性卷标和设备。我们包含 --quick 选项来跳过坏块检查,因为这需要很长时间才能执行完。

请注意,不同的文件系统类型支持不同的选项。有关详细信息,请参阅 mkfs 手册页。

工作完成后,让我们拔下驱动器并重新连接,使系统自动装载驱动器。再次运行 lsblk 可以显示结果。

正如我们所看到的,卷标用于在可移动存储设备自动挂载的 /media 目录中创建挂载点名称。

测试和修复文件系统

在我们之前对 /etc/fstab 文件的讨论中,我们在每行末尾看到了一些神秘的数字。每次系统启动时,它都会在挂载文件系统之前定期检查文件系统的完整性。这是由 fsck 程序(“file system check,文件系统检查”的缩写)完成的。每个 fstab 条目中的最后一个数字指定了检查设备的顺序。在前面的示例中,我们看到首先检查根文件系统,然后检查 home 文件系统和 boot 文件系统。最后一位数字为零的设备不会进行常规检查。

除了检查文件系统的完整性外,fsck 还可以根据损坏程度修复损坏的文件系统,成功程度各不相同。在类Unix文件系统中,恢复的文件部分被放置在 lost+found 目录中,该目录位于每个文件系统的根目录中。

要检查我们的 EXT4_Disk 分区(应该先卸载),我们可以执行以下操作:

如今,除非出现硬件问题,如磁盘驱动器故障,否则文件系统损坏的情况非常罕见。在大多数系统上,启动时检测到的文件系统损坏将导致系统停止,并指示您在继续之前运行 fsck

什么是 fsck

在Unix文化中, fsck 这个词经常被用来代替一个流行词,它与该词共享三个字母。这尤其合适,因为如果你发现自己处于被迫运行 fsck 的情况下,你可能会说出上述单词。

将数据直接移入和移出设备

虽然我们通常认为计算机上的数据是组织成文件的,但也可以将数据视为“原始”(row)形式。例如,如果我们查看磁盘驱动器,我们会看到它由大量“块”(blocks)数据组成,操作系统将其视为目录和文件。然而,如果我们可以将磁盘驱动器视为一个庞大的数据块集合,我们就可以执行有用的任务,例如克隆设备。

dd 程序执行此任务。它将数据块从一个地方复制到另一个地方。它使用了一种独特的语法(出于历史原因),通常是这样使用的:

dd if=input_file of=output_file [bs=block_size [count=blocks]]


警告! dd 命令非常强大。虽然它的名字来源于“数据定义”(data definition),但它有时也被称为“销毁磁盘”(destroy disk),因为用户经常误输入 ifof 规范 。在按下enter 键之前,请务必仔细检查您的输入和输出规格!


假设我们有两个大小相同的USB闪存驱动器,我们想将第一个驱动器精确复制到第二个驱动器。如果我们将两个驱动器都连接到计算机,并分别分配给设备 /dev/sdb/dev/sdc ,我们可以通过以下方式将第一个驱动器上的所有内容复制到第二个驱动器:

或者,如果只有第一个设备连接到计算机,我们可以将其内容复制到普通文件中,以便以后还原或复制。

【FreeBSD手册中使用以下命令将操作系统映像文件写入U盘:】

创建CD-ROM映像

写入可记录CD-ROM(CD-R或CD-RW)包括两个步骤:

  1. 构造一个ISO映像文件(ISO image file),即CD-ROM的确切文件系统映像
  2. 将图像文件写入CD-ROM介质

创建CD-ROM的映像副本

如果我们想制作现有CD-ROM的ISO映像,我们可以使用 dd 从CD-ROM中读取所有数据块并将其复制到本地文件。假设我们有一张Ubuntu CD,我们想制作一个ISO文件,以后可以用来制作更多的副本。插入CD并确定其设备名称(我们假设为 /dev/cdrom)后,我们可以这样制作ISO文件:

此技术也适用于数据DVD,但不适用于音频CD,因为它们不使用文件系统进行存储。对于音频CD,请查看 cdrdao 命令。

从文件集合创建图像

要创建包含目录内容的ISO映像文件,我们使用 genisoimage 程序。为此,我们首先创建一个包含要包含在图像中的所有文件的目录,然后执行 genisoimage 命令来创建图像文件。例如,如果我们创建了一个名为 ~/cd-rom-files 的目录,并在其中填充了CD-ROM的文件,我们可以使用以下命令创建一个名称为 cd-rom.iso 的映像文件:

-R 选项为Rock Ridge扩展添(Rock Ridge extensions)加元数据,允许使用长文件名和POSIX样式的文件权限。同样, -J 选项启用Joliet扩展名(Joliet extensions),这允许Windows使用长文件名。

任何其他名称的程序...

如果你查看创建和刻录光盘和DVD等光学介质的在线教程,你会经常遇到两个名为 mkisofscdrecord 的程序。这些程序是Jörg Schilling编写的一个名为 cdrtools 的流行软件包的一部分。2006年夏天,Schilling先生对 cdrtools 包的一部分进行了许可证更改,在Linux社区的许多人看来,这造成了与GNU GPL的许可证不兼容。因此, cdrtools 项目的一个分支开始了,现在包括分别名为 wodimgenisoimagecdrecordmkisofs 的替换程序。

写入CD-ROM映像

有了ISO映像文件后,我们可以将其刻录到光学介质上。我们将在下面讨论的大多数命令都可以应用于可记录的CD-ROM和DVD介质。

直接挂载ISO映像

有一个技巧,我们可以在ISO映像仍在硬盘上时将其挂载,并将其视为已经在光学介质上。通过添加 -o loop 选项来挂载(以及所需的 -t iso9660 文件系统类型),我们可以像挂载设备一样挂载映像文件,并将其附加到文件系统树中:

在上面的示例中,我们创建了一个名为 /mnt/iso_image 的挂载点,然后在该挂载点挂载了映像文件 image.iso 。挂载映像后,可以将其视为真正的CD-ROM或DVD。记得在不再需要映像时卸载它。

清空可重写CD-ROM

可重写CD-RW介质需要擦除或清空(blanked)才能重新使用。为此,我们可以使用 wodim ,指定CD刻录机的设备名称和要执行的清空类型。wodim计划提供了几种类型。最简单(也是最快)的是“快速”(fast)类型。

写入映像

要写入映像,我们再次使用 wodim ,指定光学介质写入器设备的名称和映像文件的名称:

除了设备名称和图像文件外, wodim 还支持大量选项。两种常见的模式是 -v 用于详细输出, -dao 用于以光盘一次性(disc-at-once)模式写入光盘。如果我们准备光盘进行商业复制,应该使用这种模式。 wodim 的默认模式是 track-at-once ,这对于录制音乐曲目很有用。

验证数据

当我们讨论ISO文件时,让我们看看如何验证我们下载的文件的完整性。通常,当我们下载一个大文件,如新的Linux安装映像时,我们会希望确保我们下载的映像文件是完整的,没有损坏。我们可以使用的一个工具是 sha256sum ,它是早期名为 md5sum 的程序的现代替代品。

有两种常见的方法可以做到这一点。让我们试试。假设我们想下载Linux Mint 22的安装映像。我们访问Linux Mint网站,获取 linuxmint-22-cinnamon-64bit.iso 文件。在那里,我们还下载了一个名为 sha256sum.txt 的校验和文件。当我们查看其内容时,我们会看到以下内容:

三行数据,包含一长串十六进制数字和可供下载的文件名,包括我们下载的ISO文件。十六进制数字字符串是校验和,是ISO文件的精确数学表示。这些数字的特殊之处在于,如果下载的ISO文件与原始文件相差一位,校验和将明显不同。我们将测试ISO文件,看看校验和是否匹配。

-b 选项告诉 sha256sum 我们正在查看二进制文件而不是文本。正如我们所看到的,校验和与我们在 sha256sum.txt 中看到的校验和匹配。然而,以这种方式查看校验和有点乏味。我们检查文件的另一种方法是让 sha256sum 处理 sha256sum.txt 文件,将其校验和与列表中文件生成的校验和进行比较。我们可以这样运行 sha256sum 程序:

-c 选项(“check”的缩写)调用此模式,而 --ignore-missing 选项告诉 sha256sum 不要抱怨我们没有下载的文件,即 linuxmint-22-mate-64bit.isolinuxmint--22-xfce-64bit-iso 不存在。

总结

在本章中,我们介绍了基本的存储管理任务。当然,还有更多。Linux支持大量的存储设备和文件系统方案。它还提供了许多与其他系统互操作的功能。