Ext系列文件系统课堂笔记

本节重点

  • 理解磁盘物理结构

  • 掌握CHS和LBA寻址地址原理及换算

  • 掌握Ext系列文件系统核心原理

  • 理解分区、格式化、路径解析、挂载全流程操作

  • 理解软硬链接区别、使用场景与核心用途

1. 磁盘硬件基础

1-1 磁盘、服务器、机柜、机房基础认知

  • 机械磁盘:计算机整机中唯一机械设备

  • 硬件归属:磁盘属于计算机外设设备

  • 性能特点:读写速度慢、存储容量大、硬件单价低廉

拓展题外话:

  1. 机房:标准化恒温防尘机房,统一管控服务器供电、散热、网络

  2. 磁盘底层原理:依靠盘片磁性物质完成数据读写存储

1-2 磁盘物理结构核心组件

核心组成:盘片、磁头、传动臂、主轴、磁盘固件、控制电路

核心细节:传动臂搭载全部磁头,所有磁头同步进退、同步移动,该特性是柱面概念的核心前提。

1-3 磁盘存储结构 & CHS寻址

基础核心定义

扇区:磁盘读写数据的最小物理单位,标准大小512字节,磁盘属于块设备。

核心逻辑:文件 = 文件内容 + 文件属性,二者本质都是磁盘数据,文件存储本质就是占用指定数量扇区。

四大物理参数详解

  • 磁头Head:单块盘片分为上下两个盘面,一个盘面对应1个磁头,单盘片固定2个磁头,负责读写盘面磁性数据

  • 磁道Track:盘面上的同心圆轨道,外圈编号为0磁道,向内依次递增;靠近主轴的内侧磁道为停泊磁道,仅停靠磁头,不存储业务数据

  • 柱面Cylinder:整机所有盘面、相同半径位置的磁道,逻辑合并为一个柱面;柱面总数 = 单盘面磁道总数

  • 扇区Sector:单条磁道均等切割的扇形存储单元,同一块磁盘内,每条磁道扇区数量一致

  • 盘片Platter:磁盘内部圆形硬质存储圆盘,决定磁盘基础存储层数

磁盘容量计算公式

磁盘总容量=磁头数 × 柱面数 × 每道扇区数 × 单扇区字节数(512B)

📌 CHS寻址方式

寻址逻辑:通过【柱面C + 磁头H + 扇区S】三维坐标,精准定位任意一个物理扇区,适配早期小容量磁盘。

CHS寻址容量限制(硬件位宽限制):

  • 磁头地址:8bit → 最大256个磁头

  • 柱面地址:10bit → 最大1024个柱面

  • 扇区地址:6bit → 最大63个扇区

CHS寻址磁盘最大容量:256 × 1024 × 63 × 512B = 8064MB,换算十进制单位约8.4GB,无法适配现代大容量磁盘,逐步被LBA寻址替代。

1-4 磁盘逻辑结构 & LBA寻址

1-4-1 LBA寻址逻辑类比

磁带为线性一维存储结构,可直接线性读写;物理磁盘为环形多层结构,操作系统将磁盘环形扇区逻辑拉直 ,整合为一维线性空间,每一个扇区分配唯一线性下标,该下标即为LBA逻辑块地址

1-4-2 磁盘数组层级逻辑(结合磁头共进退特性)

  1. 单盘面单磁道:展开为一维扇区数组

  2. 单个柱面(全盘面同半径磁道):展开为二维扇区数组 (磁头+扇区)

  3. 整块磁盘:所有柱面整合,为三维扇区数组(柱面+磁头+扇区)

上层OS屏蔽三维CHS物理寻址,统一使用一维LBA地址访问磁盘。

寻址转换权责:OS仅下发LBA地址,**磁盘固件(伺服硬件电路)**自动完成LBA与CHS双向转换,上层系统无需感知物理CHS参数。

1-5 CHS与LBA双向换算公式(必考)

编号规则(高频易错)

  • 柱面C、磁头H:从0开始编号

  • 物理扇区S:从1开始编号

  • 逻辑LBA地址:从0开始编号

前置参数:单个柱面扇区总数 = 磁头数 × 每磁道扇区数

① CHS 转 LBA

LBA = C × (磁头数×每道扇区数) + H × 每道扇区数 + S - 1

② LBA 转 CHS

  • 柱面号C = LBA // 单个柱面扇区总数 (// 向下取整除法)

  • 磁头号H = (LBA % 单个柱面扇区总数) // 每道扇区数

  • 扇区号S = (LBA % 每道扇区数) + 1

最终结论

对操作系统、运维使用者而言:磁盘等价于以扇区为元素的一维数组,LBA地址就是数组下标,只需一个数字即可读写任意磁盘扇区。

2. 引入文件系统

2-1 引入"块"概念

其实硬盘是典型的"块"设备,操作系统读取硬盘数据的时候,其实是不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。

硬盘的每个分区是被划分为一个个的"块"。一个"块"的大小是由格式化的时候确定的,并且不可以更改,最常见的是4KB,即连续八个扇区组成一个 "块"。"块"是文件存取的最小单位

📌 核心注意:

  • 磁盘就是一个三维数组,我们把它看待成为一个"一维数组",数组下标就是LBA,每个元素都是扇区

  • 每个扇区都有LBA,那么8个扇区一个块,每一个块的地址我们也能算出来

  • 已知LBA求块号:块号 = LBA / 8

  • 已知块号求LBA:LBA = 块号*8 + n (n是块内第几个扇区)

2-2 引入"分区"概念

其实磁盘是可以被分成多个分区(partition)的,以Windows观点来看,你可能会有一块磁盘并且将它分区成C,D,E盘。那个C,D,E就是分区。分区从实质上说就是对硬盘的一种格式化。但是Linux的设备都是以文件形式存在,那是怎么分区的呢?

柱面是分区的最小单位,我们可以利用参考柱面号码的方式来进行分区,其本质就是设置每个区的起始柱面和结束柱面号码。 此时我们可以将硬盘上的柱面(分区)进行平铺,将其想象成一个大的平面。

📌 核心注意:

  • 柱面大小一致,扇区个数一致

  • 只要知道每个分区的起始和结束柱面号,知道每一个柱面多少个扇区,就能算出分区容量、换算对应LBA地址范围

2-3 引入"inode"概念

之前我们说过 文件=数据+属性,我们使用 ls -l 的时候看到的除了看到文件名,还能看到文件元数据(属性)。

bash 复制代码
[root@localhost linux]# ls -l
总用量 12
-rwxr-xr-x. 1 root root 7438 "9月 13 14:56" a.out
-rw-r--r--. 1 root root 654 "9月 13 14:56" test.c

ls -l输出每行包含7列:

  • 模式权限

  • 硬链接数

  • 文件所有者

  • 所属组

  • 文件大小

  • 最后修改时间

  • 文件名

ls -l读取存储在磁盘上的文件属性信息,然后展示输出。除ls -l外,stat命令可以查看文件完整inode属性信息。

bash 复制代码
[root@localhost linux]# stat test.c
File: "test.c"
Size: 654 Blocks: 8 IO Block: 4096 普通文件
Device: 802h/2050d Inode: 263715 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-09-13 14:56:57.059012947 +0800
Modify: 2017-09-13 14:56:40.067012944 +0800
Change: 2017-09-13 14:56:40.069012948 +0800

核心思考:文件数据都储存在"块"中,那么必须单独开辟区域储存文件元信息(创建者、创建日期、权限、大小等),专门存储文件元属性的区域,叫做inode,中文译名为索引节点

每一个文件都有对应的inode,里面绑定该文件全部属性信息。

📌 核心注意:

  • Linux下文件存储规则:属性和内容分离存储

  • inode:保存文件属性的集合,遵循一个文件,一个inode

  • inode内部拥有唯一标识:inode号,文件系统依靠inode号区分文件

ext2磁盘inode内核结构体源码:

复制代码
cpp 复制代码
/*
* Structure of an inode on the disk
*/
struct ext2_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Creation time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
__le32 i_blocks; /* Blocks count */
__le32 i_flags; /* File flags */
union {
struct {
__le32 l_i_reserved1;
} linux1;
struct {
__le32 h_i_translator;
} hurd1;
struct {
__le32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
__le32 i_generation; /* File version (for NFS) */
__le32 i_file_acl; /* File ACL */
__le32 i_dir_acl; /* Directory ACL */
__le32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
__u8 l_i_fsize; /* Fragment size */
__u16 i_pad1;
__le16 l_i_uid_high; /* these 2 fields */
__le16 l_i_gid_high; /* were reserved2[0] */
__u32 l_i_reserved2;
} linux2;
struct {
__u8 h_i_frag; /* Fragment number */
__u8 h_i_fsize; /* Fragment size */
__le16 h_i_mode_high;
__le16 h_i_uid_high;
__le16 h_i_gid_high;
__le32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; /* Fragment number */
__u8 m_i_fsize; /* Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
};
/*
* Constants relative to the data blocks
*/
#define EXT2_NDIR_BLOCKS 12
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
// 备注:EXT2_N_BLOCKS = 15

📌 再次重点注意:

  • 文件名不属于inode存储内容,文件名存放于目录文件的数据块中

  • inode固定大小:128字节 / 256字节,本课程统一默认128字节

  • 文件内容大小各不相同,但所有文件inode属性结构体大小完全一致

遗留两大核心问题:

  1. 硬盘是块设备,读写最小单位为块,块分散在分区内,系统如何统一管理、快速检索空闲块?

  2. 存储文件属性的inode,在磁盘分区中如何排布、如何管理空闲inode?

文件系统的核心作用:统一组织、管理分区内的inode与数据块!

3. ext2 文件系统

3-1 宏观认识

所有的准备工作都已经做完,是时候认识下文件系统了。我们想要在硬盘上储存文件,必须先把硬盘格式化为某种格式的文件系统,才能存储文件。文件系统的目的就是组织和管理硬盘中的文件。

在 Linux 系统中,最常见的是 ext2 系列的文件系统。其早期版本为 ext2,后来又发展出 ext3 和 ext4。ext3 和 ext4 虽然对 ext2 进行了增强,但是其核心设计并没有发生变化,我们仍是以较老的 ext2 作为演示对象。

ext2文件系统将整个分区划分成若干个同样大小的块组 (Block Group)。只要能管理一个分区就能管理所有分区,也就能管理所有磁盘文件。

📌 启动块(Boot Block/Sector)核心规则:

  • 固定大小1KB,由PC硬件标准强制规定

  • 作用:存储磁盘分区信息、系统启动引导信息

  • 权限限制:任何文件系统都不可修改启动块内容

  • 排布位置:启动块之后,才正式开始ext2文件系统结构

3-2 Block Group 块组

ext2文件系统会根据分区的大小划分为数个独立Block Group。每一个Block Group内部结构完全一致

通俗类比:如同政府行政区划管理,整块分区=国家,块组=各个行政区,行政区架构统一、独立管理属地资源。

3-3 块组内部六大构成

3-3-1 超级块(Super Block)

存放文件系统全局结构信息,描述整个分区的文件系统参数,属于文件系统核心元数据。

超级块核心记录信息:

  • 分区block总量、空闲block数量

  • 分区inode总量、空闲inode数量

  • 单个block大小、单个inode大小

  • 最近挂载时间、最近写入时间、最近磁盘校验时间

  • 其余全局文件系统管控参数

📌 超级块备份机制:

  • 第一个块组头部必须存在超级块

  • 其余块组可选备份超级块副本

  • 所有备份超级块数据完全一致,用于磁盘局部扇区损坏后,恢复文件系统结构

  • 风险:超级块全部损毁,等同于整个分区文件系统结构损毁

3-3-2 GDT(Group Descriptor Table)块组描述符表

作用:描述单个块组专属属性信息,分区有多少个块组,就对应多少个块组描述符。

单块组描述符存储内容:本组inode表起始位置、本组数据块起始位置、本组空闲inode数量、本组空闲数据块数量、目录文件数量等。

备份规则:每个块组头部均存放一份GDT副本。

ext2块组描述符内核源码:

复制代码
cpp 复制代码
/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{
__le32 bg_block_bitmap; /* Blocks bitmap block */
__le32 bg_inode_bitmap; /* Inodes bitmap */
__le32 bg_inode_table; /* Inodes table block*/
__le16 bg_free_blocks_count; /* Free blocks count */
__le16 bg_free_inodes_count; /* Free inodes count */
__le16 bg_used_dirs_count; /* Directories count */
__le16 bg_pad;
__le32 bg_reserved[3];
};

3-3-3 块位图(Block Bitmap)

  • 以bit位为最小标识单位

  • 作用:标记本组每一个Data Block占用状态

  • 规则:1bit标识1个数据块,0=空闲、1=已占用

3-3-4 inode位图(Inode Bitmap)

  • 以bit位为最小标识单位

  • 作用:标记本组每一个inode节点空闲状态

  • 规则:1bit标识1个inode,0=空闲可用、1=已绑定文件

3-3-5 i节点表(Inode Table)

  • 存储当前块组全部inode节点集合,存放文件所有属性信息

  • 存储内容:文件大小、所有者、所属组、时间属性、权限、块指针等

  • 编号规则:inode号以整个分区为单位统一编号,inode不可跨分区使用

3-3-6 Data Block 数据块区

分区文件数据存储区域,由一个个格式化好的block组成,不同文件类型存储规则不同:

  • 普通文件:文件正文内容,直接存储在本组数据块中

  • 目录文件:目录名下所有文件名、子目录名,存储在目录专属数据块;ls -l其余属性,全部存储在对应文件inode中

📌 编号规则:数据块Block号以分区为单位统一划分,数据块不可跨分区调用。

3-4 inode和datablock映射(弱化了解)

  • inode结构体核心数组:__le32 i_blockEXT2_N_BLOCKS; /* Pointers to blocks */

  • 固定宏定义:EXT2_N_BLOCKS =15

  • 作用:建立inode属性与数据块的映射关系,通过inode即可找到文件所有数据块

  • 闭环逻辑:依托映射关系,文件=inode属性+block内容,系统可完整读取整份文件

3-5 目录与文件名

新建文件四大核心操作(必考流程)

创建一个新文件主要有以下4个操作:

  1. 存储属性:内核先找到一个空闲的i节点(示例inode号:263466)。内核把文件权限、大小、属主等全部文件信息记录到该inode中。

  2. 存储数据:该文件业务数据需要占用三个磁盘块,内核通过块位图检索三个空闲块:300,500,800。将内核缓冲区文件分片数据,依次复制存入300、500、800数据块。

  3. 记录分配情况:文件内容按300,500,800顺序存放。内核在inode内部i_block块指针区域,记录文件占用的数据块序号列表,建立属性与数据映射。

  4. 添加文件名到目录:新文件名为abc。内核将映射入口(inode号:263466,文件名:abc)添加到当前目录文件中。依靠文件名-inode映射,串联文件名、文件属性、文件数据。

核心答疑问答

问题:

  • 我们访问文件,都是用的文件名,从没直接使用inode号访问文件?

  • 目录是文件吗?该如何理解目录本质?

标准答案:

  • 目录本质也是文件,磁盘底层没有专属目录结构,磁盘只有:文件属性 + 文件内容两类数据

  • 目录文件属性:遵循标准inode属性结构;目录文件内容:专门存储 文件名 --- Inode号 映射关系

目录inode映射验证代码(readdir.c)

课堂备注:验证代码课堂无需手写,直接复制编译运行即可

cpp 复制代码
// readdir.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <directory>\n", argv[0]);
exit(EXIT_FAILURE);
}
DIR *dir = opendir(argv[1]); // 系统调用,自行查阅
if (!dir) {
perror("opendir");
exit(EXIT_FAILURE);
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) { // 系统调用,自行查阅
// Skip the "." and ".." directory entries
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..")
== 0) {
continue;
}
printf("Filename: %s, Inode: %lu\n", entry->d_name, (unsigned
long)entry->d_ino);
}
closedir(dir);
return 0;
}

程序运行终端输出

bash 复制代码
zsx@bite:~/code/test/test$ ./readdir /
Filename: mnt, Inode: 1048577
Filename: tmp, Inode: 1179650
Filename: sys, Inode: 917506
Filename: libx32, Inode: 17
Filename: srv, Inode: 786434
Filename: lib64, Inode: 16
Filename: sbin, Inode: 18
Filename: dev, Inode: 131073
Filename: swapfile, Inode: 12
Filename: run, Inode: 1048578
Filename: log.txt, Inode: 20
Filename: proc, Inode: 1179649
Filename: lost+found, Inode: 11
Filename: etc, Inode: 262145
Filename: lib, Inode: 14
Filename: opt, Inode: 917505
Filename: usr, Inode: 1179651
Filename: lib32, Inode: 15
Filename: boot, Inode: 655361
Filename: var, Inode: 655365
Filename: product-service-1.0-SNAPSHOT.jar, Inode: 19
Filename: bin, Inode: 13
Filename: media, Inode: 393217
Filename: home, Inode: 786433
Filename: root, Inode: 655362

ls -li 对照核验结果

复制代码
bash 复制代码
zsx@bite:~/code/test/test$ ls -li /
total 1014436
13 lrwxrwxrwx 1 root root 7 Sep 14 2020 bin -> usr/bin
655361 drwxr-xr-x 3 root root 4096 May 6 14:34 boot
2 drwxr-xr-x 17 root root 3880 Jul 17 10:39 dev
262145 drwxr-xr-x 98 root root 4096 Oct 27 14:56 etc
786433 drwxr-xr-x 6 root root 4096 Sep 4 14:56 home
14 lrwxrwxrwx 1 root root 7 Sep 14 2020 lib -> usr/lib
15 lrwxrwxrwx 1 root root 9 Sep 14 2020 lib32 -> usr/lib32
16 lrwxrwxrwx 1 root root 9 Sep 14 2020 lib64 -> usr/lib64
17 lrwxrwxrwx 1 root root 10 Sep 14 2020 libx32 ->usr/libx32
20 -rw-r--r-- 1 root root 461 Jul 16 15:51 log.txt
11 drwx------ 2 root root 16384 Sep 14 2020 lost+found
393217 drwxr-xr-x 4 root root 4096 Sep 14 2020 media
1048577 drwxr-xr-x 3 root root 4096 Oct 17 17:47 mnt
917505 drwxr-xr-x 3 root root 4096 May 6 14:37 opt
1 dr-xr-xr-x 169 root root 0 Jul 17 10:26 proc
19 -rw-r--r-- 1 root root 45457485 Feb 3 2024 product-service-1.0-SNAPSHOT.jar
655362 drwx------ 13 xjh xjh 4096 Oct 27 09:36 root
2 drwxr-xr-x 25 root root 780 Oct 28 20:36 run
18 lrwxrwxrwx 1 root root 8 Sep 14 2020 sbin -> usr/sbin
786434 drwxr-xr-x 2 root root 4096 Apr 23 2020 srv
12 -rw------- 1 root root 993249280 Sep 14 2020 swapfile
1 dr-xr-xr-x 13 root root 0 Jul 17 18:26 sys
1179650 drwxr-xrwt 20 root root 4096 Oct 28 20:39 tmp
1179651 drwxr-xr-x 14 root root 4096 Nov 10 2023 usr
655365 drwxr-xr-x 12 root root 4096 Jun 16 16:40 var

访问文件底层逻辑

  • 访问文件流程:打开当前目录文件 → 通过文件名匹配获取对应inode号 → 通过inode读取文件属性+数据块内容

  • 访问文件前置条件:必须依托当前工作目录,本质是读取目录内部文件名inode映射表

bash 复制代码
zsx@bite:~/code/test/test$ pwd
/home/whb/code/test/test
zsx@bite:~/code/test/test$ ls -li
total 24
1596260 -rw-rw-r-- 1 whb whb 814 Oct 28 20:32 test.c

示例解析:访问test.c,必须先打开test本级目录文件,匹配文件名拿到test.c专属inode,最终读写文件数据。

3-6 路径解析

递进式答疑

问题:打开当前工作目录,依旧依靠文件名匹配inode,上级目录同样是目录文件,是不是无限递归?

答案1:访问本级目录,需要打开上级目录;访问上级目录,需要打开上上级目录,形成递归查找逻辑。

答案2:目录查找递归出口:根目录 /

最终结论:访问绝对路径文件,例如 /home/whb/code/test/test/test.c,系统必须从根目录出发,逐级打开各级目录、匹配目录inode,逐层检索,最终定位目标文件,该全过程即为Linux路径解析

核心注意:

  • 文件访问格式:目录+文件名 = 完整路径,缺一不可

  • 根目录inode号、目录信息开机固化,无需递归查找

  • 进程内置CWD(当前工作目录),进程自主提供访问路径

  • 系统默认目录 + 用户自建目录,共同搭建Linux全局文件路径树

3-7 路径缓存

核心问答

问题1:Linux磁盘硬件层面,存在真正专属目录结构吗?

答案:磁盘无目录概念,磁盘只有文件属性+文件数据两类存储结构。

问题2:每访问一个文件,都必须从根目录逐级解析路径吗?

答案:底层规则需要逐级解析,但是效率极低,内核会做路径缓存优化。

问题3:Linux用户态目录树形概念从何而来?

答案:目录文件被打开后,内核在内存维护树形路径结构,虚拟生成目录层级。

内核路径缓存结构体:struct dentry

dentry:内核维护目录树形结构、实现路径缓存的核心结构体

cpp 复制代码
struct dentry {
atomic_t d_count;
unsigned int d_flags; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
/*
* The next three fields are touched by __d_lookup. Place them here
* so they all fit in a cache line.
*/
struct hlist_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */
struct qstr d_name;
struct list_head d_lru; /* LRU list */
/*
* d_child and d_rcu can share memory
*/
union {
struct list_head d_child; /* child of parent list */
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs; /* our children */
struct list_head d_alias; /* inode alias list */
unsigned long d_time; /* used by d_revalidate */
struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
void *d_fsdata; /* fs-specific data */
#ifdef CONFIG_PROFILING
struct dcookie_struct *d_cookie; /* cookie, if any */
#endif
int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};

📌 dentry核心特性:

  • 所有已打开普通文件、目录文件,内核都会分配专属dentry结构体

  • 所有dentry在内核组成全局文件树,实现路径缓存加速访问

  • 绑定Hash链表:根据文件名快速哈希查找,提升检索速度

  • 绑定LRU最近最少使用算法:闲置dentry自动淘汰,节省内核内存

  • 访问逻辑:优先查询内存dentry缓存,命中直接取用inode;未命中再从磁盘解析路径,新增缓存节点

3-8 挂载分区

前置核心问题

inode不可跨分区使用,Linux系统存在多个磁盘分区,系统如何判定文件归属分区?依靠挂载机制解决分区识别问题。

3-8-1 回环分区挂载实操实验

复制代码
cpp 复制代码
# 1. 生成5M空白镜像文件,模拟一块磁盘分区
$ dd if=/dev/zero of=./disk.img bs=1M count=5 
# 2. 给镜像格式化ext4文件系统
$ mkfs.ext4 disk.img 
# 3. 创建空挂载目录
$ mkdir /mnt/mydisk 
# 4. 查看系统现有挂载分区
$ df -h 
Filesystem Size Used Avail Use% Mounted on
udev 956M 0 956M 0% /dev
tmpfs 198M 724K 197M 1% /run
/dev/vda1 50G 20G 28G 42% /
tmpfs 986M 0 986M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 986M 0 986M 0% /sys/fs/cgroup
tmpfs 198M 0 198M 0% /run/user/0
tmpfs 198M 0 198M 0% /run/user/1002

# 5. 将ext4镜像分区挂载至指定目录
$ sudo mount -t ext4 ./disk.img /mnt/mydisk/ 
# 6. 挂载后查看分区
$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 956M 0 956M 0% /dev
tmpfs 198M 724K 197M 1% /run
/dev/vda1 50G 20G 28G 42% /
tmpfs 986M 0 986M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 986M 0 986M 0% /sys/fs/cgroup
tmpfs 198M 0 198M 0% /run/user/0
tmpfs 198M 0 198M 0% /run/user/1002
/dev/loop0 4.9M 24K 4.5M 1% /mnt/mydisk

# 7. 卸载分区
$ sudo umount /mnt/mydisk 
# 8. 卸载后分区消失
zsx@bite:/mnt$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 956M 0 956M 0% /dev
tmpfs 198M 724K 197M 1% /run
/dev/vda1 50G 20G 28G 42% /
tmpfs 986M 0 986M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 986M 0 986M 0% /sys/fs/cgroup
tmpfs 198M 0 198M 0% /run/user/0
tmpfs 198M 0 198M 0% /run/user/1002

📌 loop回环设备详解:

  • 设备标识:/dev/loop0 为首款循环伪设备

  • 设备属性:伪块设备,无需物理磁盘

  • 核心功能:将普通文件镜像,虚拟为可挂载的磁盘块设备

复制代码
bash 复制代码
# 系统全部loop设备查看
zsx@bite:/mnt$ ls /dev/loop* -l
brw-rw---- 1 root disk 7, 0 Oct 17 18:24 /dev/loop0
brw-rw---- 1 root disk 7, 1 Jul 17 10:26 /dev/loop1
brw-rw---- 1 root disk 7, 2 Jul 17 10:26 /dev/loop2
brw-rw---- 1 root disk 7, 3 Jul 17 10:26 /dev/loop3
brw-rw---- 1 root disk 7, 4 Jul 17 10:26 /dev/loop4
brw-rw---- 1 root disk 7, 5 Jul 17 10:26 /dev/loop5
brw-rw---- 1 root disk 7, 6 Jul 17 10:26 /dev/loop6
brw-rw---- 1 root disk 7, 7 Jul 17 10:26 /dev/loop7
crw-rw---- 1 root disk 10, 237 Jul 17 10:26 /dev/loop-control

3-8-2 挂载核心结论

  • 分区格式化文件系统后,无法直接读写使用,必须绑定空目录完成挂载,才可接入系统文件树

  • 分区判定规则:通过文件路径前缀,即可识别文件归属磁盘分区

3-9 文件系统整体总结

本章配套多张原理示意图,从磁盘物理层、块组管理层、inode映射层、目录路径层、挂载管理层多角度复盘ext2文件系统全流程,串联磁盘硬件、寻址、格式化、文件存储、路径访问、分区挂载全套知识点。

4. 软硬链接

结合前文目录底层逻辑:系统依托inode定位磁盘文件,而非文件名。Linux支持多个文件名绑定同一个inode,该绑定关系即为硬链接。

实操演示命令

bash 复制代码
[root@localhost linux]# touch abc          # 创建源文件abc
[root@localhost linux]# ln abc def         # 为abc创建硬链接def
[root@localhost linux]# ls -li abc def
263466 abc
263466 def

核心特性

  • abc、def共用同一个inode,磁盘属性、文件数据完全共享,无任何区别

  • inode内部记录硬链接计数,本例inode:263466 硬链接数更新为2

  • 📌 文件删除底层两步逻辑:1、目录内删除当前文件名-inode映射;2、inode硬链接计数-1;计数减为0,内核回收文件inode+数据块磁盘空间

📌 硬链接硬性限制(必考易错)

  • 不支持跨分区创建:inode分区独立,无法跨分区绑定inode

  • 不支持目录创建硬链接:仅系统默认`.` `..`目录硬链接,用户禁止手动创建目录硬链接

  • 仅可针对已有文件创建,无法指向不存在文件

核心本质:硬链接通过inode指向文件,软链接通过文件名路径指向源文件;软链接属于独立文件,拥有专属inode,Windows下等价于文件快捷方式。

实操演示

bash 复制代码
[root@localhost linux]# ln -s abc abc.s    # 语法:ln -s 源文件 软链接文件名
[root@localhost linux]# ls -li
263563 -rw-r--r--. 2 root root 0 9月 15 17:45 abc
261678 lrwxrwxrwx. 1 root root 3 9月 15 17:53 abc.s -> abc
263563 -rw-r--r--. 2 root root 0 9月 15 17:45 def

文件三大时间属性详解(必考)

  • Access(访问时间atime):文件内容最近被读取、浏览的时间

  • Modify(修改时间mtime):文件磁盘数据内容最近变更时间,修改内容必改mtime

  • Change(更改时间ctime):文件inode属性最近变更时间,修改权限、属主、链接数、文件名都会变更ctime

4-3 软硬链接核心对比

  • 软链接:独立文件,独占inode、独占少量数据块,存储源文件路径信息

  • 硬链接:不属于独立文件,仅新增一条【文件名-inode】映射,不新增inode、不占用磁盘空间

4-4 软硬链接适用场景

硬链接使用场景

  • 目录内置` . `(本级目录硬链接)、` ..`(上级目录硬链接),系统自带硬链接

  • 简易文件备份:多文件名绑定同一inode,删除单一文件名不丢失文件数据

  • 防止文件误删,提升文件安全性

软链接使用场景

  • 系统快捷方式,简化深层路径访问

  • 软件版本切换:统一链接指向不同版本程序

  • 支持跨分区、跨目录、指向不存在文件,使用无限制

📌 终极考点总结

  1. 删源文件:硬链接文件不受影响;软链接直接失效变红报错

  2. 硬链接共享inode,软链接独享inode

  3. 修改文件内容:所有软硬链接文件同步变更内容