Skip to main content

第6章 存储结构与管理硬盘

章节简述

Linux 系统中颇具特色的文件存储结构常常搞得新手头昏脑涨,本章将从 Linux 系统中的文件存储结构入手,讲解文件系统层次标准(Filesystem Hierarchy Standard,FHS)、udev 硬件命名规则以及磁盘设备的工作原理。

为了帮助读者更好地理解文件系统的作用,刘遄老师将在本章详细分析 Linux 系统中常见的 Ext3、Ext4 和XFS 文件系统的不同之处,并带领读者重点练习磁盘设备分区、格式化及挂载等常见的磁盘管理操作,从而熟练掌握文件系统的使用方法。

在夯实理论基础后,我们将详细介绍如何部署交换(SWAP)分区、配置磁盘配额服务(quota)以及使用 ln 命令创建软链接和硬链接。通过本章的学习,读者将深入理解 Linux 和 Windows 系统中的磁盘存储与文件系统。

6.1 一切从“/”开始

在 Linux 系统中,目录、字符设备、套接字、磁盘、光驱、打印机等都被抽象成文件形式,即刘遄老师一直强调的“Linux 系统中一切都是文件”。既然平时我们打交道的都是文件, 那么又应该如何找到它们呢?

在Windows 系统中,想要找到一个文件,需要依次进入该文件所在的磁盘分区(也叫盘符),然后再进入该分区下的具体目录(也称为“文件夹”),最终找到这个文件。但是 Linux系统中并不存在 C、D、E、F 等盘符,一切文件都是从“根”目录(/)开始的,并按照文件系统层次标准(FHS)采用倒树状结构来存放文件,并定义了常见目录的用途。

Linux 系统中的文件和目录名称是严格区分大小写的。例如,root、rOOt、Root、rooT 均被视为不同的目录,此外,文件名称中不得包含斜杠(/)。Linux 系统中的文件存储结构如图 6-1 所示。

图 6-1 Linux 系统中的文件存储结构

前文提到的FHS 是根据无数Linux 系统用户和开发者的经验总结出来的,是用户在 Linux 中存储文件时需要遵守的规则,用于指导用户应该把文件保存到什么位置,以及告诉用户应该在何处找到所需的文件。但是,FHS 对于用户来讲只能算是一种道德上的约束,有些用户压根儿懒得遵守,依然会把文件到处乱放,有些用户甚至从来没有听说过它。这里并不是号召各位读者去谴责他们,而是建议灵活运用所学的知识,千万不要认准这个 FHS 只讲死道理, 不然吃亏的可就是自己了。Linux 系统中常见的目录名称以及相应的存放内容如表 6-1 所示。

表 6-1 常见的目录名称以及相应的存放内容

目录名称应放置文件的内容
/boot系统启动文件,如内核和启动菜单
/dev系统中的硬件设备文件
/etc系统和各个服务的配置文件
/root管理员的家目录
/home用户的家目录
/bin基本用户命令,可在单用户模式下使用
/sbin系统管理命令,供管理员使用
/lib系统共享库,供/bin 和/sbin 命令使用
/media挂载点目录,用于可移动设备
/opt第三方应用软件包
/srv服务数据目录,存放网络服务数据
/tmp临时文件目录,所有用户均可访问
/proc虚拟文件系统,提供进程和内核信息
/usr/local本地安装的软件和应用程序
/usr/sbin系统管理员使用的非基本管理命令
/usr/share共享数据,如文档和帮助文件
/var动态数据,如日志文件和临时文件
/lost+found文件系统恢复区,存放丢失的文件碎片

在 Linux 系统中,还有一个重要的概念—路径。路径是指如何定位到某个文件在系统中的位置,分为绝对路径和相对路径。

绝对路径指的是从根目录(/)开始写起的文件或目录名称,而相对路径是相对于当前工作目录而言的路径表示方法。我们来看下面这个例子,以帮助大家更好地理解绝对路径和相对路径。

假如有位外国游客来到北京潘家园旅游,当前内急但是找不到洗手间,特意向你问路, 此时我们有两种正确的指路方法。

绝对路径:首先坐飞机来到中国,到了北京后出首都机场(假设到达的是首都机场),坐机场快轨到三元桥,然后换乘地铁 10 号线到潘家园站,出站后坐 34 路公交车到农光里,下车后路口左转。

相对路径:前面路口左转。

这两种方法都正确。如果你说的是绝对路径,那么任何一位外国游客都能够按照这个提示找到潘家园的洗手间,但是太烦琐了。如果说的是相对路径,虽然表达很简练,但是这位外国游客只能从当前位置出发找到洗手间。由此可见,相对路径不具备普适性。

如果还未完全理解相对路径和绝对路径的区别,也不要担心,随着稍后的实践,肯定能够彻底搞明白这些概念。当前建议大家先记住 FHS 中规定的目录作用,这将在以后派上用场。

6.2 物理设备的命名规则

在 Linux 系统中一切都是文件,硬件设备也不例外。既然是文件,就必须有文件名称。系统内核中的 udev 设备管理器会自动规范硬件名称,目的是让用户通过设备文件的名字能够猜出设备的大致属性和分区信息等,这对于陌生的设备来说特别方便。此外,udev 设备管理器的服务会一直以守护进程的形式运行并侦听内核发出的信号来管理/dev 目录下的设备文件。Linux 系统中常见的硬件设备及其文件名称如表 6-2 所示。

表 6-2 常见的硬件设备及其文件名称

硬件设备文件名称
IDE 设备/dev/hd[a-d]
NVMe 设备/dev/nvme[0-n]
SCSI/SATA/U 盘/dev/sd[a-z]
Virtio 设备/dev/vd[a-z]
软驱/dev/fd[0-1]
打印机/dev/lp[0-15]
光驱/dev/cdrom
鼠标/dev/mouse
磁带机/dev/st0 或/dev/ht0

由于现在的 IDE 设备已经很少见了,所以一般的磁盘设备都是以/dev/sd 开头。而一台主机上可能有多块磁盘,因此系统采用 a~z 来代表 26 块不同的磁盘(默认从 a 开始分配),此外,磁盘的分区编号也有讲究:

主分区或扩展分区的编号从 1 开始,到 4 结束;

逻辑分区从编号 5 开始。

  1. 设备名称的错误解读。

许多培训讲师与 Linux 技术图书常宣称,/dev/sda 代表连接在主板第一个插槽上的存储设备,学员或读者在实操中发现该命名与插槽顺序相符,便对此深信不疑。但事实上,

/dev/sda 中的字母 a 并非由物理插槽位置决定,而是取决于系统内核识别存储设备的先后顺序。多数情况下,主板设备接入顺序与内核识别顺序一致,才导致这一误解。以 iSCSI 网络存储设备为例,即便主板第二个插槽空置,系统仍可能识别出/dev/sdb 设备,正是因为内核根据自身扫描逻辑而非物理插槽赋予其名称。

  1. 分区名称的认知偏差。

很多 Linux 培训讲师会向学员传授“分区编号等同于分区数量”的观点,例如将 sda3解释为设备上的第 3 个分区,且学员在实验中常观察到类似的规律。然而,这一理论存在根本性错误,因为分区的数字编码不一定是强制顺延下来的,用户完全可通过手动配置来指定编号。因此,sda3 仅代表编号为 3 的分区,无法作为判断 sda 设备已存在 3 个分区的依据。

在填了这两个“坑”之后,再来分析一下/dev/sda5 这个设备文件名称包含哪些信息, 如图 6-2 所示。

图6-2 设备文件名称

首先,/dev 目录中保存的应当是硬件设备文件;其次,sd 表示的是存储设备;然后, a 表示系统中同类接口中第一个被识别到的设备;最后,5 表示这个设备是一个逻辑分区。一言以蔽之,/dev/sda5 表示的是“这是系统中第一块被识别到的硬件设备中分区编号为 5 的逻辑分区的设备文件”。

此外,现在越来越多的服务器使用了 NVMe 传输协议,这种能够充分利用固态磁盘性能的技术,比传统串行的 SATA 和 SCSI 接口的数据吞吐效率快了很多,很有可能本书的下一版本就以 NVMe 磁盘为实验对象啦。SATA/SCSI 与 NVMe 磁盘名称的对照如图 6-3 所示。

图6-3 NVMe硬盘名称对照示意

考虑到很多读者没有 Linux 基础,不太容易理解前面所说的主分区、扩展分区和逻辑分区的概念,因此接下来简单科普一下磁盘相关的知识。

正是因为计算机有了磁盘设备,我们才能够在玩游戏的过程中或游戏通关之后随时存档, 而不用每次从头开始。磁盘设备是由大量的扇区组成的,每个扇区的容量为 512 字节。其中第一个扇区最重要,它里面保存着主引导记录与分区表信息。就第一个扇区来讲,主引导记录需要占用 446 字节,分区表占用 64 字节,结束符占用 2 字节;其中分区表中每记录一个分区信息就需要 16 字节,这样一来最多只有 4 个分区信息可以写到第一个扇区中,这 4 个分区就是 4 个主分区。第一个扇区中的数据信息如图 6-4 所示。

图6-4 第一个扇区中的数据信息

现在,问题来了:每块磁盘最多只能创建出 4 个分区?这明显不合情理也不够用。

为了解决分区数量不够的问题,可以将第一个扇区的分区表中 16 字节(原本要写入主分区信息)的空间作为扩展分区,指向另外一个分区。扩展分区实际上并不是一个真正 的分区,而是一个指向其他分区的指针。这样,用户通常会选择使用 3 个主分区和 1 个扩展分区的方法,然后在扩展分区中创建多个逻辑分区,从而满足多分区的需求。只要理解 为什么主分区不能超过 4 个就足够了。主分区、扩展分区、逻辑分区可以像图 6-5 那样来规划。

Tips :
严格来讲,扩展分区不是一个有实际意义的分区,而仅仅是一个指向其他分区的指针, 这种指针结构将形成一个单向链表。因此扩展分区自身不能存储数据,用户需要在其指向的对应分区(称为逻辑分区)上进行操作。

图6-5 硬盘分区的规划

请大家试着解读一下/dev/hdc8 代表什么?

答案:这是第 3 块 IDE 设备(现在比较少见)中编号为 8 的逻辑分区。

对了!如果大家参加红帽 RHCE 考试或购买了一台云主机,还会看到类似于/dev/vda、/dev/vdb 这样的设备。这种以 vd 开头的设备叫作 Virtio 设备,简单来说就是一种虚拟化设备。像 KVM、Xen 这种虚拟机监控程序(Hypervisor)就是默认使用这种设备进行数据交互, 等大家步入工作岗位后可能会见到更多。

6.3 文件系统与数据资料

同学们可以拿出一张 A4 纸,然后横过来在上面随便写上几行字,在书写过程中慢慢就会发现字写得越来越歪,最终整行文字都会向上或向下倾斜。为了能让字写得更工整,让人阅读得更舒服一些,文具店里提供了各种不同的本本—单线本、双线本、田格本、五线谱本等。这也说明,离开了格式约束后的内容,完全不受我们的主观控制。而用户在硬件存储设备中执行的文件建立、写入、读取、修改、转存与控制等操作,都是依靠文件系统来完成的。文件系统的作用是有效管理和优化磁盘空间的使用,以保证用户正常的使用需求。

Linux 系统支持数十种文件系统,最常见的文件系统如下所示。

Ext2:最早可追溯到 1993 年,是 Linux 系统的第一个商业级文件系统,它基本沿袭了 UNIX 文件系统的设计标准。由于不包含日志功能,Ext2 在系统崩溃后很难恢复数据,数据丢失的可能性较大。因此,建议大家能不用就不用,或者顶多用于 SD 存储卡或 U 盘。

Ext3:是一款日志文件系统,它会预先记录每个写入动作的细节,然后再进行实际写入操作,以便在异常宕机后能回溯追踪到被中断的部分。Ext3 能够在系统异常宕机时避免文件系统资料丢失,并能自动修复数据的不一致与错误。然而,当磁盘容量较大时,修复时间会很长,而且也不能 100%地保证资料不会丢失。

Ext4:Ext3 的改进版本,作为 RHEL 6 系统中的默认文件系统,它支持的存储容量高达 1EB(1EB=1073741824GB),且支持大量的子目录。Ext4 文件系统能够批量分配块,从而极大地提高了读写效率。现在很多主流服务器使用的就是 Ext4 文件系统。

XFS:是一种高性能的日志文件系统,从 RHEL 7 开始成为 RHEL 的默认文件系统。它在发生意外宕机后能够快速恢复被破坏的文件,且强大的日志功能只需消耗很低的计算和存储性能。它支持的最大存储容量为 18EB,几乎满足了所有需求。

RHEL 10 系统的一个重大变化就是使用了 XFS 作为文件系统。虽然红帽公司官方发布的说明认为这是一个巨大的进步,但刘遄老师经实测后发现情况并非全然如此。测试一款文件系统的“读取”性能涉及许多变量,包括读取文件的数量和大小、CPU 和内存等系统资源的占用率以及不同硬件配置的影响,因此不能盲目采信官方介绍。尽管 XFS 在性能方面比 Ext4 有所提升,但绝不是压倒性的,XFS 文件系统最卓越的亮点应该是其支持高达 18EB 的存储容量。

18EB 等于 18874368TB。假设每块磁盘的容量是 100TB,那么大概需要 19 万块磁盘才能装下 18EB 的数据。总之,使用 XFS 后,文件的存储上限不再取决于技术,而是取决于钱包。曾经有个技术圈的经典玩笑:“如果有 18EB 的数据在上海机房,想以最快的方式传送到北京,最好的办法是什么?”答案是“乘坐京沪高铁”。

拿到一块新的磁盘存储设备后,首先需要分区,然后再格式化文件系统,最后才能挂载并正常使用。磁盘的分区操作取决于你的需求和磁盘大小;也可以选择不进行分区,但必须对磁盘进行格式化处理。

Tips :
就像拿到了一张未裁切的全开纸那样,首先要进行裁切以方便使用(分区),接下来在裁切后的纸张上画格以便能工整书写(格式化),最后是正式使用(挂载)。

接下来向大家简单科普一下磁盘在格式化后发生的事情。再次强调,大家不用刻意去记住,只要能看懂就行了。

日常需要保存在磁盘中的数据实在太多了,因此Linux 系统中有一个名为super block 的“磁盘地图”。Linux 并不是把文件内容直接写入这个“磁盘地图”中,而是记录整个文件系统的信息。如果把所有文件内容都写入这里,它的体积将变得非常大,查询与写入速度也会变慢。Linux 只是把每个文件的权限与属性记录在 inode 中,每个文件占用一个独立的inode 表格,该表格的大小默认为 128 字节,记录的信息包括:

该文件的访问权限(read、write、execute);

该文件的所有者与所属组(owner、group);

该文件的大小(size);

该文件的创建或内容修改时间(Ctime);

该文件的最后一次访问时间(Atime);

该文件的修改时间(Mtime);

该文件的特殊权限(SUID、SGID、SBIT);

该文件的真实数据地址(point)。

文件的实际内容则保存在 block 中(大小一般是 1KB、2KB 或 4KB),一个 inode 的默认大小仅为 128 字节,记录一个 block 则消耗 4 字节。当文件的 inode 被写满后,Linux 系统会自动分配出一个 block,专门用于像 inode 那样记录其他 block 块的信息,这样把各个 block 的内容串联在一起,就能让用户读到完整的文件内容了。对于存储文件内容的block,有下面两种常见的情况(以 4KB 大小的block 为例进行说明)。

情况 1:文件很小(1KB),但依然会占用一个 block,因此会潜在地浪费 3KB。

情况 2:文件很大(5KB),那么会占用两个 block(5KB−4KB 后剩下的 1KB 也要占用一个 block)。

大家看到这里,是不是觉得 Linux 系统好浪费啊?为什么最后一个 block 的容量总不能被完全使用呢?其实每个系统都是一样的,只不过大家此前没有留意过罢了。同学们可以随手查看一个电脑中已有的文件,看看文件的实际大小与占用空间是否一致,如图 6-6 所示。

图6-6 文件的实际大小与占用空间

inode 与 block 搭配使用才最终实现了用户读写文件内容的操作,但有点太抽象了, 为了更好地理解它们,请看图 6-7 所示的关系图。

图6-7 inode与block关系示意图

计算机系统在发展过程中产生了众多的文件系统,为了使用户在读取或写入文件时不用关心底层的磁盘结构,Linux 内核中的软件层为用户程序提供了一个虚拟文件系统(Virtual File System,VFS)接口,这样用户实际上在操作文件时就是统一对这个虚拟文件系统进行操作了。图 6-8 所示为 VFS 的架构示意图。从中可见,实际文件系统在 VFS 下隐藏了自己的特性和细节,这样用户在日常使用时会觉得“文件系统都是一样的”,也就可以随意使用各种命令在任何文件系统中进行各种操作了(比如使用 cp 命令复制文件)。

图6-8 VFS的架构示意图

VFS 也有点像一个翻译官。我们不需要知道对方的情况,只要告诉 VFS 想进行的操作是什么,它就会自动判断对方能够听得懂什么命令,然后翻译并交代下去。这样一来,用户不用操心这些“小事情”,只需专注于自己的操作即可。

Tips :
在医学圈里有这样一句话:“当开始关注身体某个器官的时候,大概率是它最近不舒服了。”由于 VFS 太好用了,而且几乎不会出现任何问题,所以如果不在这里讲一下它的理论,相信很多同学很可能在多年后都不知道自己用过它。

6.4 挂载硬件设备

我们在用惯了 Windows 系统后,总觉得一切都是理所当然的,平时把 U 盘插入电脑后也从来没有考虑过 Windows 系统做了哪些事情,才使得我们可以访问 U 盘的数据。接下来我们会逐一学习在 Linux 系统中挂载和卸载存储设备的方法,以便大家更好地了解在 Linux 系统 中添加硬件设备的工作原理和流程。前面讲到,在拿到一块全新的磁盘存储设备后要先分区, 然后格式化,最后才能挂载并正常使用。“分区”和“格式化”大家以前经常听到,但“挂载” 又是什么呢?

刘遄老师在这里给你一个最简单、最贴切的解释:当用户需要使用磁盘设备或分区中的数据时,需要先将其与一个已存在的目录文件进行关联,这个关联动作就是“挂载”。下文将向读者逐步讲解如何使用磁盘设备,但是鉴于与挂载相关的理论知识比较复杂且重要,因此决定再拿出一个小节单独讲解,这次希望大家不仅要看懂,还要记住。

mount 命令用于挂载文件系统,格式为“mount [文件系统] [挂载目录]”。mount命令中可用的参数及作用如表 6-3 所示。挂载是在使用硬件设备前执行的最后一步操作。只需使用 mount 命令把磁盘设备或分区与一个目录文件进行关联,然后就能在这个目录中看到硬件设备中的数据了。对于比较新的Linux 系统来说,一般不需要使用-t 参数指定文件系统的类型,Linux 系统会自动进行判断。而 mount 中的-a 参数则会自动检查/etc/fstab 文件中有无被遗漏挂载的设备文件,如果有,则进行自动挂载操作。

表 6-3 mount 命令中的参数及作用

参数作用
-a挂载所有在/etc/fstab 中定义的文件系统
-t指定文件系统的类型

例如,要把设备/dev/sdb2 挂载到/backup 目录,只需要在 mount 命令中填写设备与挂载目录参数就行,系统会自动判断要挂载文件的类型,命令如下:

root@linuxprobe:~# mount /dev/sdb2 /backup

如果在工作中要挂载一块网络存储设备,该设备的名字可能会变来变去,这样再写为 sdb 就不太合适了。这时推荐用UUID(Universally Unique IDentifier,通用唯一识别码)进行挂载操作。UUID 是一串用于标识每块独立磁盘的字符串,具有唯一性及稳定性,特别适合用来挂载网络设备。那么,怎么才能得知独立磁盘的 UUID 呢?答案是使用 blkid 命令。

blkid 命令用于显示设备的属性信息,英文全称为 block device id,语法格式为“blkid [设备名]”。使用 blkid 命令查询设备 UUID 的示例如下:

root@linuxprobe:~# blkid
/dev/sdb1: UUID="1ff63c74-090c-4fa9-a3fb-cfb029572819" TYPE="xfs"
/dev/sdb2: UUID="53f01fa2-2a23-4979-8add-8fe0df5b8947" TYPE="ext4"
………………省略部分输出信息………………

有了设备的 UUID 值之后,就可以用它挂载网络设备了:

root@linuxprobe:~# mount UUID=53f01fa2-2a23-4979-8add-8fe0df5b8947 /backup

虽然按照上面的方法执行 mount 命令后就能立即使用文件系统了,但系统在重启后挂载就会失效,也就是说需要每次开机后都手动挂载一下。这肯定不是我们想要的效果,如果想让硬件设备和目录永久地进行自动关联,就必须把挂载信息按照指定的填写格式“设备文件 挂载目录 格式类型 权限选项 是否备份 是否自检”(各字段的意义见表 6-4)写入/etc/fstab 文件中。这个文件中包含着挂载所需的诸多信息,一旦配置好之后就能一劳永逸了。

表 6-4 用于挂载信息的指定填写格式中,各字段所表示的意义

字段意义
设备文件一般为设备的路径+设备名称,也可以写 UUID
挂载目录指定要挂载到的目录,需在挂载前创建好
格式类型指定文件系统的格式,比如 Ext3、Ext4、XFS、SWAP、iso9660(此为光盘设备)等
权限选项若设置为 defaults,则默认权限为 rw、suid、dev、exec、auto、nouser、async
是否备份若为 1 则开机后使用 dump 进行磁盘备份,为 0 则不备份
是否自检若为 1 则开机后自动进行磁盘自检,为 0 则不自检

如果想将文件系统为 Ext4 的硬件设备/dev/sdb2 在开机后自动挂载到/backup 目录上,并保持默认权限且无须开机自检,就需要在/etc/fstab 文件中写入下面的信息,这样在系统重启后也会成功挂载。

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/sdb2 /backup ext4 defaults 0 0

由于后面需要使用系统镜像制作 YUM/DNF 软件仓库,我们提前把光盘设备挂载到/media/cdrom 目录中。光盘设备的文件系统格式是 iso9660:

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/sdb2 /backup ext4 defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0

写入/etc/fstab 文件中的设备信息并不会立即生效,需要使用 mount -a 参数进行自动挂载:

root@linuxprobe:~# mount -a

df 命令用于查看已挂载的磁盘空间使用情况,英文全称为 disk free,语法格式为 df -h。如果想查看当前系统中设备的挂载情况,非常推荐大家试试 df 命令。它不仅能够列出

系统中正在使用的设备有哪些,还可以用-h 参数便捷地对存储容量进行“进位”操作。例如, 在遇到 10240K 的时候会自动进位写成 10M,非常方便我们的阅读。

root@linuxprobe:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 17G 3.7G 13G 23% /
devtmpfs 4.0M 0 4.0M 0% /dev
tmpfs 1.9G 84K 1.9G 1% /dev/shm
efivarfs 256K 56K 196K 23% /sys/firmware/efi/efivars
tmpfs 776M 9.7M 767M 2% /run
tmpfs 1.0M 0 1.0M 0% /run/credentials/systemd-journald.service
/dev/sr0 6.5G 6.5G 0 100% /media/cdrom
/dev/sda2 960M 272M 689M 29% /boot
/dev/sda1 599M 8.3M 591M 2% /boot/efi
/dev/sdb2 480M 20M 460M 4% /backup

对了!说到网络存储设备,建议在 fstab 文件挂载信息中加上_netdev 参数。加上后系统会在联网成功后再尝试挂载这块网络存储设备,从而避免了开机时间过长或失败的情况(第 17 章学习 iSCSI 技术时可以用上)。

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/sdb2 /backup ext4 defaults,_netdev 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0

挂载文件系统的目的是使用硬件资源,而卸载文件系统则意味不再使用硬件的设备资源。既然挂载操作就是将硬件设备与目录进行关联的动作,那么卸载操作只需要说明想要取消关联的设备文件或挂载目录的其中一项即可,一般不需要加其他额外的参数。

umount 命令用于卸载设备或文件系统,英文全称为 un mount,语法格式为“umount [设备文件/挂载目录]”。

root@linuxprobe:~# umount /dev/sdb2

如果我们当前就处于设备所挂载的目录,系统会提示该设备繁忙,此时只需要退出到其他目录后再尝试一次就行了。轻松搞定。

root@linuxprobe:~# cd /media/cdrom
root@linuxprobe:/media/cdrom# umount /dev/cdrom
umount: /media/cdrom: target is busy.
root@linuxprobe:/media/cdrom# cd ~
root@linuxprobe:~# umount /dev/cdrom
root@linuxprobe:~#

Tips :
挂载操作就像两人去民政局登记结婚,双方需要同时到场,信息一旦登记到民政局的系统中,再想重婚(重复挂载某设备)可就不行喽。

最后再教给同学们一个小技巧。如果系统中磁盘特别多,分区特别多,时间一长都不知道它们是否处于使用状态,又或者是做了些什么。此时,就可以用 lsblk 命令以树状图的形式列举一下了。

lsblk 命令用于查看系统中如磁盘、分区、逻辑卷等块设备信息,英文全称为 list block devices,输入该命令后按回车键执行即可。

root@linuxprobe:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 20G 0 disk
├─sda1 8:1 0 600M 0 part /boot/efi
├─sda2 8:2 0 1G 0 part /boot
└─sda3 8:3 0 18.4G 0 part
├─rhel-root 253:0 0 16.4G 0 lvm /
└─rhel-swap 253:1 0 2G 0 lvm [SWAP]
sdb 8:16 0 20G 0 disk
├─sdb1 8:17 0 1G 0 part
└─sdb2 8:18 0 500M 0 part
sr0 11:0 1 6.5G 0 rom

6.5 添加硬盘设备

根据前文讲解的与管理硬件设备相关的理论知识,我们先来理一下添加磁盘设备的操作思路:首先需要在虚拟机中模拟添加一块新的磁盘存储设备;然后进行分区、格式化、挂载等操作;最后通过检查系统的挂载状态并真实地使用磁盘来验证磁盘设备是否成功添加。

鉴于我们不需要为了做这个实验而特意买一块真实的磁盘,而是通过虚拟机软件进行硬件模拟,因此这再次体现出了使用虚拟机软件的好处。具体的操作步骤如下。

首先把虚拟机系统关机,稍等几分钟会自动返回到虚拟机管理主界面,然后单击“编辑虚拟机设置”选项,在弹出的界面中单击“添加”按钮,新增一块硬件设备,如图 6-9 所示。

图6-9 在虚拟机系统中添加硬件设备

选择想要添加的硬件类型为“磁盘”,然后单击“下一步”按钮就可以了,如图6-10 所示。这确实没有什么需要进一步解释的。

图6-10 选择添加硬件类型

选择虚拟硬盘的类型为SATA,并单击“下一步”按钮,如图6-11所示。这样虚拟机中的设备名称过一会儿后应该为/dev/sdb。

图6-11 选择硬盘设备类型

选中“创建新虚拟磁盘”单选按钮(而不是其他选项),再次单击“下一步”按钮,如图 6-12 所示。

图6-12 选择“创建新虚拟磁盘”选项

将“最大磁盘大小”设置为默认的 20GB。这个数值是限制这台虚拟机所使用的最大磁盘空间,而不是立即将其填满,因此默认 20GB 就很合适了。单击“下一步”按钮,如图 6-13 所示。

图6-13 设置硬盘的最大使用空间

设置磁盘文件的文件名和保存位置(这里采用默认设置即可,无须修改),直接单击“完成”按钮,如图 6-14 所示。

图6-14 设置磁盘文件的文件名和保存位置

将新磁盘添加好后就能看到设备信息了。这里不需要做任何修改,直接单击“确定”按钮启动虚拟机,如图 6-15 所示。

图6-15 查看虚拟机硬件设置信息

在虚拟机中模拟添加了磁盘设备后,我们应该能看到抽象后的磁盘设备文件。按照前文讲解的 udev 服务命名规则,第二个被识别的 SATA 设备应该会被保存为/dev/sdb,这就是磁盘设备文件了。但在开始使用该磁盘之前,还需要进行分区操作,例如从中取出一个 2GB 的分区以供后面的操作使用。

fdisk 命令用于新建、修改及删除磁盘的分区表信息,英文全称为 format diskette,语法格式为“fdisk 磁盘名称”。

在Linux 系统中,管理磁盘设备最常用的方法就当属 fdisk 命令了。它提供了集添加、删除、转换分区等功能于一身的“一站式分区服务”。与此前介绍的将参数直接书写于命令后的形式不同,这条命令采用交互式的一问一答的形式接收参数(见表 6-5),因此在管理磁盘设备时特别方便,可以根据需求动态调整。

表 6-5 fdisk 命令中的参数以及作用

参数作用
m查看全部可用的参数
n添加新的分区
d删除某个分区信息
l列出所有可用的分区类型
t改变某个分区的类型
p查看分区表信息
w保存并退出
q不保存直接退出

首先使用 fdisk 命令尝试管理/dev/sdb 磁盘设备。在看到提示信息后输入参数 p,查看磁盘设备内已有的分区信息,其中包括磁盘的容量大小、扇区个数等信息:

root@linuxprobe:~# fdisk /dev/sdb

Welcome to fdisk (util-linux 2.40.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS (MBR) disklabel with disk identifier 0x186f3f5e.

Command (m for help): p
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x186f3f5e

输入参数 n 尝试添加新的分区。系统会要求用户是选择继续输入参数 p 来创建主分区, 还是输入参数 e 来创建扩展分区。这里输入参数 p 来创建一个主分区:

Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p

在确认创建一个主分区后,系统要求用户先输入主分区的编号。从前文得知,主分区的编号范围是 1~4,因此这里输入默认的 1 就可以了。接下来系统会提示定义起始的扇区位置, 这不需要改动,敲击回车键保留默认设置即可,系统会自动计算出最靠前的空闲扇区的位置。最后,系统会要求定义分区的结束扇区位置,这其实就是定义整个分区的大小是多少。我们不用去计算扇区的个数,只需要输入+2G 即可创建出一个容量为 2GB 的磁盘分区。

Partition number (1-4, default 1): 1
First sector (2048-41943039, default 2048): 此处敲击回车即可
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-41943039, default 41943039): +2G
Created a new partition 1 of type 'Linux' and of size 2 GiB.

再次使用参数 p 查看磁盘设备中的分区信息。果然就能看到一个名称为/dev/sdb1、起始扇区位置为 2048、结束扇区位置为 4196351 的主分区了。这时千万不要直接关闭窗口, 而应该敲击参数 w 后按回车键,这样分区信息才是真正地写入成功啦。

Command (m for help): p
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x186f3f5e

Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 4196351 4194304 2G 83 Linux

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

分区信息中第 6 个字段的 Id 值是一个编码,用于标识该分区的作用,可帮助用户快速了解该分区的作用,一般没必要修改。使用 l 参数查看一下磁盘编码都有哪些,然后在 6.6 节进行 SWAP 操作时再修改吧:

Command (m for help): l

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

Aliases:
linux - 83
swap - 82
extended - 05
uefi - EF
raid - FD
lvm - 8E
linuxex - 85

在上述步骤执行完毕之后,Linux 系统会自动把这个磁盘主分区抽象成/dev/sdb1 设备文件。可以使用 file 命令查看该文件的属性,但我在讲课和工作中发现,有时系统并没有自动把分区信息同步给 Linux 内核,而且这种情况似乎还比较常见(但不能算作严重的 bug)。此时需要输入 partprobe 命令手动将分区信息同步到内核,而且一般推荐连续两次执行该命令,效果会更好。如果使用这个命令都无法解决问题,那么就重启计算机吧,这个“杀手锏”百试百灵,一定会有用的。

root@linuxprobe:~# file /dev/sdb1
/dev/sdb1: cannot open `/dev/sdb1' (No such file or directory)
root@linuxprobe:~# partprobe
root@linuxprobe:~# partprobe
root@linuxprobe:~# file /dev/sdb1
/dev/sdb1: block special (8/17)

如果硬件存储设备没有进行格式化,则 Linux 系统无法得知怎么在其上写入数据。因此, 在对存储设备进行分区后还需要进行格式化操作。在 Linux 系统中用于格式化操作的命令是mkfs。这条命令很有意思,因为在 Shell 终端中输入 mkfs 后再敲击两下用于补齐命令的 Tab 键,会有如下所示的效果:

root@linuxprobe:~# mkfs
mkfs mkfs.exfat mkfs.ext3 mkfs.fat mkfs.msdos mkfs.xfs
mkfs.cramfs mkfs.ext2 mkfs.ext4 mkfs.minix mkfs.vfat

对了!这个 mkfs 命令通过不同的参数来调用相应的文件系统格式化工具,实现对不同文件系统的格式化操作,用起来也非常简单—mkfs.文件类型名称。例如要将分区格式化成 XFS,则命令应为 mkfs.xfs /dev/sdb1。

root@linuxprobe:~# mkfs.xfs /dev/sdb1
meta-data=/dev/sdb1 isize=512 agcount=4, agsize=131072 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=1
= reflink=1 bigtime=1 inobtcount=1 nrext64=1
data = bsize=4096 blocks=524288, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=16384, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0

终于完成了存储设备的分区和格式化操作,接下来就是挂载并使用存储设备了。与之相关的步骤也非常简单:首先创建一个用于挂载设备的挂载点目录;然后使用 mount 命令将存储设备与挂载点进行关联;最后使用 df -h 命令查看挂载状态和磁盘使用量信息。

root@linuxprobe:~# mkdir /newFS
root@linuxprobe:~# mount /dev/sdb1 /newFS
root@linuxprobe:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 17G 3.7G 13G 23% /
devtmpfs 4.0M 0 4.0M 0% /dev
tmpfs 1.9G 84K 1.9G 1% /dev/shm
efivarfs 256K 56K 196K 23% /sys/firmware/efi/efivars
tmpfs 776M 9.7M 767M 2% /run
tmpfs 1.0M 0 1.0M 0% /run/credentials/systemd-journald.service
/dev/sda2 960M 272M 689M 29% /boot
/dev/sr0 6.5G 6.5G 0 100% /media/cdrom
/dev/sda1 599M 8.3M 591M 2% /boot/efi
tmpfs 388M 120K 388M 1% /run/user/0
/dev/sdb1 2.0G 71M 1.9G 4% /newFS

既然存储设备已经顺利挂载,接下来就可以尝试通过挂载点目录向存储设备中写入文件了。在写入文件之前,先来看一个用于查看文件数据占用量的 du 命令。du 命令用来查看分区或目录所占用的磁盘容量大小,英文全称为 disk usage,语法格式为“du –sh 目录名称”。简单来说,该命令就是用来查看一个或多个文件占用了多大的磁盘空间。

在使用 Windows 系统时,我们总会遇到“C 盘容量不足,清理垃圾后又很快被占满”的情况。在 Linux 系统中可以使用 du –sh /*命令查看根目录下所有一级目录分别占用的空间大小,在 1s 之内就能找到哪个目录占用的空间最多:

root@linuxprobe:~# du -sh /*
0 /afs
0 /bin
229M /boot
84K /dev
29M /etc
12K /home
0 /lib
0 /lib64
6.5G /media
0 /mnt
0 /newFS
0 /opt
0 /proc
4.2M /root
9.8M /run
0 /sbin
0 /srv
0 /sys
20K /tmp
3.2G /usr
69M /var

先从某些目录中复制过来一批文件,然后查看这些文件总共占用了多大的容量:

root@linuxprobe:~# cp -rf /etc/* /newFS
root@linuxprobe:~# ls /newFS
adjtime gshadow profile
aliases gshadow- profile.d
alsa gss protocols
alternatives host.conf pulse
anacrontab hostname qemu-ga
asound.conf hosts ras
………………省略部分输出信息………………
root@linuxprobe:~# du -sh /newFS
29M /newFS/

细心的读者一定还记得,前面在讲解 mount 命令时提到,使用 mount 命令挂载的设备文件会在系统下一次重启时失效。如果想让这个设备文件的挂载永久有效,则需要把挂载的信息写入配置文件中:

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb1 /newFS xfs defaults 0 0

6.6 添加交换分区

SWAP

交换(SWAP)分区是一种通过在磁盘中预先划分一定的空间,把内存中暂时不常用的数据临时存放到磁盘中,以便腾出物理内存空间让更活跃的程序使用的技术,其设计目的是解决真实物理内存不足的问题。简单来说,就是让磁盘帮内存分担压力。由于交换分区通过磁盘设备读写数据,速度比物理内存慢,所以只有当真实的物理内存耗尽后才会调用交换分区的资源。

交换分区的创建过程与前文讲到的挂载并使用存储设备的过程非常相似。在对

/dev/sdb 存储设备进行分区操作前,有必要先说明交换分区的划分建议:在生产环境中, 通常建议交换分区的大小一般为真实物理内存的 1.5~2 倍。为了让大家更明显地感受交换分区空间的变化,这里取出一个大小为 5GB 的主分区作为交换分区资源。

root@linuxprobe:~# fdisk /dev/sdb
Welcome to fdisk (util-linux 2.40.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): n
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 敲击回车即可
First sector (4196352-41943039, default 4196352): 敲击回车即可
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4196352-41943039, default 41943039): +5G

Created a new partition 2 of type 'Linux' and of size 5 GiB.

在上面的操作结束后,我们就得到了一个容量为 5GB 的新分区。然后尝试修改磁盘的标识码,这里将其改成 82(Linux swap)以方便以后知道它的作用:

Command (m for help): t
Partition number (1,2, default 2): 2
Hex code or alias (type L to list all): 82

Changed type of partition 'Linux' to 'Linux swap / Solaris'.

Command (m for help): p
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x186f3f5e

Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 4196351 4194304 2G 83 Linux
/dev/sdb2 4196352 14682111 10485760 5G 82 Linux swap / Solaris

搞定!输入 w 参数退出分区表编辑工具:

Command (m for help): w
The partition table has been altered.
Syncing disks.

下面来看一下两个与交换分区相关的简单命令。

mkswap 命令用于对新设备进行交换分区格式化,英文全称为 make swap,语法格式为“mkswap 设备名称”。

root@linuxprobe:~# mkswap /dev/sdb2
Setting up swapspace version 1, size = 5 GiB (5368705024 bytes)
no label, UUID=cd6c8f9d-0af2-4020-96bc-02509c118b5c

swapon 命令用于激活新的交换分区设备,英文全称为 swap on,语法格式为“swapon 设备名称”。

使用 swapon 命令把准备好的交换分区设备正式挂载到系统中。可以使用 free -m 命令查看交换分区的大小变化(由 2047MB 增加到 7167MB):

root@linuxprobe:~# free -m
total used free shared buff/cache available
Mem: 3879 1535 1563 14 1125 2344
Swap: 2047 0 2047
root@linuxprobe:~# swapon /dev/sdb2
root@linuxprobe:~# free -m
total used free shared buff/cache available
Mem: 3879 1540 1558 14 1126 2339
Swap: 7167 0 7167

为了能够让新的交换分区设备在重启后依然生效,需要按照下面的格式将相关信息写入配置文件中,并记得保存:

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb1 /newFS xfs defaults 0 0
/dev/sdb2 swap swap defaults 0 0

6.7 磁盘容量配额

前面提到,Linux 系统的设计初衷就是让许多人一起使用并执行各自的任务,从而成为多用户、多任务的操作系统。但是,硬件资源是固定且有限的,如果某些用户不断地在 Linux 系统上创建文件或存放大的视频文件,磁盘空间总有一天会被占满。针对这种情况,root 管理员可以使用磁盘容量配额服务来限制某位用户或某个用户组在特定文件夹中能够使用的最大磁盘空间或最大文件个数。一旦达到这个最大值,就不再允许继续使用。可以使用 quota 技术进行磁盘容量配额管理,从而限制用户的磁盘可用容量或所能创建的最大文件个数。quota 技术还有软限制和硬限制的功能。

软限制:当达到软限制时会提示用户,但仍允许用户在限定的额度内继续使用。

硬限制:当达到硬限制时会提示用户,且强制终止用户的操作。

RHEL 10 系统中已经安装了quota 磁盘容量配额服务程序包,但存储设备默认没有开启对 quota 技术的支持。此时需要手动编辑配置文件并重启一次系统,让系统中的启动目录(/boot)支持 quota 磁盘配额技术。

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults,uquota 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb1 /newFS xfs defaults 0 0
/dev/sdb2 swap swap defaults 0 0
root@linuxprobe:~# reboot

Tips :
在实操中发现,VMware Workstation 17 Pro 虚拟机系统有时会错误地混淆两块磁盘, 导致重启后系统开机失败。可将/etc/fstab 文件中/dev/sdb2 设备的挂载信息删除, 或使用 UUID 挂载,再次重启就一切正常了。

另外,对于学习过早期的 Linux 系统,或者具有 RHEL 5/6 系统使用经验的读者来说,这里需要特别注意。早期的 Linux 系统要想让磁盘设备支持 quota 磁盘容量配额服务,使用的是 usrquota 参数,而 RHEL 7 以及以后的版本使用的则是uquota 参数。

在重启系统后使用 mount 命令查看,即可发现/boot 目录已经支持 quota 磁盘配额技术了:

root@linuxprobe:~# mount | grep boot
/dev/sda2 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,usrquota)

接下来创建一个用于检查 quota 磁盘容量配额效果的用户 tom,并针对/boot 目录增加其他人的写权限,保证用户能够正常写入数据:

root@linuxprobe:~# useradd tom
root@linuxprobe:~# chmod -R o+w /boot

xfs_quota 命令用于管理XFS 格式设备的磁盘容量配额,语法格式为“xfs_quota [参数] 配额 挂载点”。

这是一个专为管理 XFS 文件系统磁盘容量配额(quota)而设计的命令。其中,-c 参数用于以参数的形式设置要执行的命令;-x 参数是专家模式,让运维人员能够对 quota 服务进行更多复杂的配置。

接下来使用 xfs_quota 命令设置用户 tom 对/boot 目录的 quota 磁盘容量配额。具体的限额控制包括:磁盘使用量的软限制和硬限制分别为 3MB 和 6MB;创建文件数量的软限制和硬限制分别为 3 个和 6 个。

root@linuxprobe:~# xfs_quota -x -c 'limit bsoft=3m bhard=6m isoft=3 ihard=6 tom' /boot
root@linuxprobe:~# xfs_quota -x -c report /boot
User quota on /boot (/dev/sda2)
Blocks
User ID Used Soft Hard Warn/Grace
---------- --------------------------------------------------
root 225552 0 0 00 [--------]
tom 0 3072 6144 00 [--------]

上面使用的参数分为两组,分别是 isoft/ihard 与 bsoft/bhard,下面深入讲解一下。6.3 节曾经讲过,Linux 系统中的每个文件都会使用一个独立的 inode 信息块来保存属性信息,一个文件对应一个 inode 信息块,所以 isoft 和 ihard 就是通过限制系统最大使用的 inode 个数来限制文件数量。bsoft 和bhard 则是代表文件所占用的block 大小,也就是文件占用的最大容量的总和。

soft 是软限制,超过该限制后系统也只是将操作记录写到日志中,不对用户行为进行限制。而 hard 是硬限制,一旦超过该限制,系统就会马上禁止,用户再也不能创建或新占任何的磁盘容量。

当配置好上述各种软硬限制后,尝试切换到一个普通用户,然后分别尝试创建一个体积为 5MB 和 8MB 的文件。可以发现,在创建 8MB 的文件时受到了系统限制:

root@linuxprobe:~# su - tom
tom@linuxprobe:~$ cd /boot
tom@linuxprobe:/boot$ dd if=/dev/zero of=/boot/tom bs=5M count=1
1+0 records in
1+0 records out
5242880 bytes (5.2 MB, 5.0 MiB) copied, 0.00163334 s, 3.2 GB/s
tom@linuxprobe:/boot$ dd if=/dev/zero of=/boot/tom bs=8M count=1
dd: error writing '/boot/tom': Disk quota exceeded
1+0 records in
0+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.00370067 s, 1.1 GB/s

在为用户设置了 quota 磁盘容量配额限制后,可以使用 edquota 命令按需修改限额的数值。edquota 命令主要用于管理系统的磁盘配额,英文全称为 edit quota,语法格式为“edquota [参数] 用户名”。其中,-u 参数表示要针对哪个用户进行设置;-g 参数表示要针对哪个用户组进行设置。

edquota 命令中可用的参数以及作用如表 6-6 所示。

表 6-6 edquota 命令中可用的参数以及作用

参数作用
-u对某个用户进行设置
-g对某个用户组进行设置
-p复制原有的规则到新的用户/组
-t限制宽限期限

edquota 命令会调用 Vi 或 Vim 编辑器让root 管理员修改要限制的具体细节,记得用 wq 保存退出。下面把用户 tom 的磁盘使用量的硬限额从 5MB 提升到 8MB:

tom@linuxprobe:/boot$ exit
root@linuxprobe:~# edquota -u tom
Disk quotas for user tom (uid 1001):
Filesystem blocks soft hard inodes soft hard
/dev/sda2 4096 3072 8192 1 3 6
root@linuxprobe:~# su - tom
tom@linuxprobe:~$ cd /boot
tom@linuxprobe:/boot$ dd if=/dev/zero of=/boot/tom bs=8M count=1
1+0 records in
1+0 records out
8388608 bytes (8.4 MB, 8.0 MiB) copied, 0.00644861 s, 1.3 GB/s
tom@linuxprobe:/boot$ exit

6.8 软硬方式链接

在引领大家学习完本章所有的磁盘管理知识之后,刘遄老师终于可以放心大胆地讲解Linux 系统中的“快捷方式”了。在 Windows 系统中,快捷方式就是指向原始文件的一个链接文件,能够让用户从不同的位置访问原始的文件;原文件一旦被删除或剪切到其他地方, 会导致链接文件失效。但是,这个看似简单的东西在 Linux 系统中可不太一样。

Linux 系统中存在软链接和硬链接两种不同的类型。

软链接(soft link):也叫符号链接(symbolic link),仅仅包含所链接文件的名称和路径,很像一个记录地址的标签。当原始文件被删除或移动后,新的链接文件也会随之失效,不能被访问。可以针对文件、目录设置软链接,而且跨文件系统进行链接也不是问题。从这一点来看,它与 Windows 系统的“快捷方式”具有一样的性质。用户访问软链接的效果如图 6-16 所示。

图6-16 软链接原理示意图

硬链接(hard link):可以将它理解为一个“指向原始文件 block 的指针”,系统会创建出一个与原来一模一样的 inode 信息块。所以,硬链接文件与原始文件其实是完全一样的,只是名字不同。每添加一个硬链接,该文件的 inode 个数就会增加 1; 而且只有当该文件的 inode 个数为 0 时,才算彻底将它删除。换言之,由于硬链接实际上是指向原文件 block 的指针,因此即便原始文件被删除,依然能够通过硬链接文件来访问。需要注意的是,由于技术的局限性,不能跨分区对目录文件进行硬链接。用户访问硬链接的效果如图 6-17 所示。

图6-17 硬链接原理示意图

Tips :
大家翻开手头这本书的目录页,看一下目录标题和对应的页码就应该能够理解了。 链接文件就是指向实际内容所在位置的一个标签,通过这个标签,可以找到对应的数据。

ln 命令用于创建文件的软硬链接,英文全称为 link,语法格式为“ln [参数] 原始文件名 链接文件名”。

ln 命令的可用参数以及作用如表 6-7 所示。在使用 ln 命令时,是否添加-s 参数,将创建出性质不同的两种“快捷方式”。因此如果没有扎实的理论知识和实践经验做铺垫,尽管能够成功完成实验,但永远不会明白为什么会成功。

表 6-7 ln 命令的可用参数以及作用

参数作用
-s创建“符号链接”(如果不带-s 参数,则默认创建硬链接)
-f强制创建文件或目录的链接
-i覆盖前先询问
-v显示创建链接的过程

为了更好地理解软链接、硬链接的不同性质,我们先创建出一个文件,为其创建一个软链接:

root@linuxprobe:~# echo "Welcome to linuxprobe.com" > old.txt
root@linuxprobe:~# ln -s old.txt new.txt
root@linuxprobe:~# cat old.txt
Welcome to linuxprobe.com
root@linuxprobe:~# cat new.txt
Welcome to linuxprobe.com
root@linuxprobe:~# ls -l old.txt
-rw-r--r--. 1 root root 26 Mar 16 23:16 old.txt

原始文件名为 old,新的软链接文件名为 new。删掉原始文件后,软链接文件立刻就无法读取了:

root@linuxprobe:~# rm -f old.txt 
root@linuxprobe:~# cat new.txt
cat: new.txt: No such file or directory
root@linuxprobe:~# rm -f new.txt

接下来针对原始文件 old 创建一个硬链接,即相当于针对原始文件的磁盘存储位置创建了一个指针。这样一来,新创建的这个硬链接就不再依赖于原始文件的名称等信息,也不会因为原始文件的删除而导致无法读取了。同时可以看到创建出硬链接文件后,原始文件的磁盘链接数量也应声增加到了 2。

root@linuxprobe:~# echo "Welcome to linuxprobe.com" > old.txt
root@linuxprobe:~# ln old.txt new.txt
root@linuxprobe:~# cat old.txt
Welcome to linuxprobe.com
root@linuxprobe:~# cat new.txt
Welcome to linuxprobe.com
root@linuxprobe:~# ls -l old.txt
-rw-r--r--. 2 root root 26 Mar 16 23:18 old.txt

这是一个非常有意思的现象。创建的硬链接文件竟然会让文件属性第二列的数字变成了2,这个数字表示的是文件的 inode 信息块的数量。相信同学们已经非常肯定地知道,即便删除了原始文件,新的文件也会一如既往地可以读取,因为只有当文件 inode 数量被“清零” 后,才真正代表这个文件被删除了。

root@linuxprobe:~# rm -f old.txt 
root@linuxprobe:~# cat new.txt
Welcome to linuxprobe.com

至此,我们就完成了磁盘基础管理知识的学习,但为了更好地满足实际生产工作的需要, 还需要学习一些更高级的磁盘技术,例如将多块磁盘合并成磁盘阵列组的 RAID,以及实现动态分区容量调整的 LVM,赶快翻开第 7 章吧。

复习题

  1. /home 目录与/root 目录内存放的文件有何相同点以及不同点?

    答:这两个目录都是用来存放用户家目录数据的,但是/root 目录存放的是 root 管理员的家目录数据。

  2. 假如一个设备的文件名称为/dev/sdb,可以确认它是主板第二个插槽上的设备吗?

    答:不一定,因为设备的文件名称是由系统的识别顺序决定的。

  3. 如果磁盘中需要 5 个分区,则至少需要几个逻辑分区?

    答:可以选用创建 3 个主分区+1 个扩展分区的方法,然后把扩展分区再分成 2 个逻辑分区,即有了 5 个分区。

  4. /dev/sda5 是主分区还是逻辑分区?

    答:逻辑分区。

  5. 哪个服务决定了设备在/dev 目录中的名称?

    答:udev 设备管理器服务。

  6. 用一句话来描述挂载操作。

    答:当用户需要使用磁盘设备或分区中的数据时,需要先将其与一个已存在的目录文件进行关联,而这个关联动作就是“挂载”。

  7. 在卸载某文件系统时,系统提示“设备繁忙,操作失败”,这一般是什么情况?

    答:这说明该目录正在被使用中,可以切换到其他目录后再尝试一下,例如cd ~。

  8. 在配置quota 磁盘容量配额服务时,软限制数值必须小于硬限制数值么?

    答:不一定,软限制数值可以小于等于硬限制数值。

  9. 若原始文件被改名,那么之前创建的软链接还能访问到这个原始文件么?

    答:不可以。

  10. 若原始文件被删除,那么之前创建的硬链接还能访问到这个原始文件么?

    答:可以。