拂拉氏头像
关注
【知识讲解】 Linux文件系统的深入认识封面图

【知识讲解】 Linux文件系统的深入认识


目录

前言

Part1. 分区与文件系统基础概念

Part1.1. 文件块

Part1.2. Bitmap 位图

Part1.3. GDT 块组描述符表

Part1.4. Super Block 超级块

Part1.5. 格式化

Part1.6. inode表

Part2. inode多级块指针寻址

Part3. 目录、dentry目录项、路径解析与dentry缓存

Part3.1. 路径解析完整流程

Part3.2. dentry高速缓存

Part3.3. 挂载的概念

Part3.4. open 调用底层流程

Part4. 硬链接与软链接

Part4.1. 硬链接

Part4.2. 软链接

Part5. 创建文件的底层本质

Part6. 结语


前言

  Linux下一切皆文件,对于文件的认识是非常重要的,接下来来跟随小编的视角来看看吧。


let's go!!!!!!!!


Part1. 分区与文件系统基础概念

一块物理磁盘可以划分多个分区,例如 300G、300G、200G。不同分区可以使用不同的文件系统,一个分区可以格式化为 Ext4,另一个分区可以是 XFS。


一句话区分:分区是磁盘的空间划分;文件系统是写在分区内部的空间管理规则。


当执行 mkfs.ext4 格式化分区,操作系统会把整个分区切分成大量块组(Block Group),每个块组内部结构完全相同。


块组的设计目的:利用局部性原理,同一个文件的数据尽量分配在同一个块组,减少机械硬盘磁头寻道开销,同时方便分区资源并行管理。

单个块组包含6个核心组成部分:

1. Super Block 超级块

2. GDT 块组描述符表

3. Block Bitmap 块位图

4. Inode Bitmap inode位图

5. Inode Table inode表

6. Data Blocks 数据块区


Part1.1. 文件块

磁盘硬件最小读写单元是扇区,512字节。
Ext4 文件系统以块 Block作为管理单元,默认大小4KB,和操作系统内存页大小保持一致。

为什么不直接使用512字节扇区?

1. 提升IO效率:一次IO读取4KB,减少系统调用次数;

2. 内存页对齐:磁盘块加载到内存页时,不需要拆分拼接,避免跨页碎片;

3. 权衡碎片开销:块太大,小文件会产生大量内部碎片;块太小,元数据(位图、inode表)占用空间会急剧膨胀。


Data Blocks 数据块区:磁盘上唯一存放文件真实内容的区域,文本、二进制、日志全部保存在这里。


Part1.2. Bitmap 位图

位图本质是一串二进制比特:0代表空闲,1代表占用。

• Block Bitmap 块位图:每1bit对应一个Data Block。bit=1代表数据块已占用,bit=0代表空闲。

• Inode Bitmap inode位图:每1bit对应一个inode,标记inode是否被占用。


面试高频考点:为什么rm删除文件速度很快?
rm不会擦除磁盘上原始数据。内核仅仅修改两张位图,把对应bit置0,标记资源为空闲。磁盘上原始数据还保留在原地,直到新文件写入覆盖。这就是误删文件可以被数据恢复软件找回的底层原理。


Part1.3. GDT 块组描述符表

GDT块组描述符表,记录每一个块组的资源位置与状态:
当前块组的块位图、inode位图、inode表在磁盘上的位置,当前块组空闲块数量、空闲inode数量。

操作系统挂载分区时,会一次性把 Super Block 和 GDT 加载到内存,后续所有文件操作优先操作内存中的元数据,再异步刷回磁盘。


Part1.4. Super Block 超级块

超级块存储整个文件系统全局信息:块大小、扇区大小、分区总块数、总inode数量、挂载状态、文件系统版本等。


面试题:超级块保存整个文件系统全局信息,为什么要做多个副本?
超级块是整个文件系统的命脉。一旦存放超级块的磁盘块损坏,整个分区无法挂载,文件全部丢失。


Ext4 不会在每一个块组都存放完整超级块,只挑选部分块组保存冗余备份,用于fsck故障修复。


Part1.5. 格式化

很多人误以为格式化就是清空磁盘上所有数据。
真实过程:操作系统在分区上写入Super Block、GDT、两张位图、inode表,划分好各个区域。


格式化完成后,分区没有任何业务文件。挂载操作,就是OS把Super Block、GDT加载进内存,准备管理这套文件系统。


Part1.6. inode表

inode表是一块连续磁盘区域,存放大量inode结构体。Ext4默认单个inode大小128字节。


简单计算:1个数据块4KB,4096 / 128 = 32。
 一次磁盘IO读取一个4KB块,可以一次性载入32个inode。


核心知识点:

1. inode编号仅在当前分区内唯一,跨分区inode编号可以重复;

2. ls -i 命令可以查看文件对应的inode编号;


Part2. inode多级块指针寻址

inode内部维护一个数组,一共15个块指针,用来定位存放文件内容的数据块。
如果只有直接指针,最多只能管理12个块,12 × 4KB = 48KB,大文件完全无法支持。因此Ext4设计了多级间接寻址:


1. 前12项:直接块指针
指针直接指向保存文件内容的数据块。
48KB以内的小文件,只需要直接寻址,不需要额外读间接块,访问速度最快。


2. 第13项:一级间接块指针
这个块不存文件内容,里面存放一堆数据块编号。
4KB的块,每个块号占4字节:4096 / 4 = 1024个块号。可以额外寻址1024个4KB数据块。


3. 第14项:二级间接块指针
指向一级间接块。一级间接块内部再存放1024个指针,每个指针指向一级间接块。
寻址容量:1024 × 1024 × 4KB。


4. 第15项:三级间接块指针
三层嵌套索引,用来支持GB、TB级别的超大文件。


设计思想总结:小文件直接寻址,速度优先;大文件依靠多级间接索引,突破单文件容量上限。


Part3. 目录、dentry目录项、路径解析与dentry缓存

Linux哲学:一切皆文件。目录本身也是文件。

目录文件不会存放普通业务数据,目录文件里面存储一条条struct dentry目录项。
每一条dentry记录两件核心信息:文件名 + 对应inode编号。


简单理解:目录 = 一张「文件名 → inode号」的映射表。


Part3.1. 路径解析完整流程

当我们打开 /home/xxx/test.txt,内核解析路径的全过程:

1. 根目录/的inode是固定的;

2. 读取根目录对应的目录文件,遍历dentry,找到home目录项,拿到home目录inode;

3. 读取home目录的目录文件,找到xxx目录项,拿到xxx目录inode;

4. 读取xxx目录,找到test.txt目录项,拿到文件inode;

5. 加载inode到内存,通过inode内部15个块指针,找到存放文件内容的数据块。


Part3.2. dentry高速缓存

如果每次打开文件,都从根目录开始,一次次读磁盘解析目录,磁盘IO会爆炸,性能极差。
Linux内核维护dentry cache目录项高速缓存:

• 内存中维护一颗目录树,缓存曾经访问过的所有目录项;

• 搭配哈希表快速查找;

• 使用LRU淘汰机制:内存紧张时,淘汰最近最少使用的目录项。

绝大多数文件访问,直接命中内存缓存,不需要访问磁盘,大幅提升路径查找效率。find命令遍历文件,就会充分利用这套缓存。


Part3.3. 挂载的概念

格式化后的分区,操作系统不能直接使用,必须挂载到某个目录上。
举例:将分区挂载到/x目录。挂载成功后,进入/x目录,等价于进入这个分区的根目录。
后续所有在/x下面的查找、新建、删除操作,都会在这个分区内部执行。


struct dentry结构体内部有d_sb指针,标记这个目录项属于哪一个超级块,也就是属于哪一个分区。


CPU无法直接访问磁盘,必须通过挂载,把磁盘分区关联到目录树。


Part3.4. open 调用底层流程

调用open系统调用(C库fopen底层封装了open):

1. 用户传入文件路径,内核开始路径解析,依托dentry缓存逐级查找目录项;

2. 找到目标文件对应的dentry,拿到inode编号,把inode加载进内核内存;

3. 内核创建struct file结构体,记录本次打开文件的状态、读写偏移量;

4. 分配文件描述符fd,返回给用户态程序。


Part4. 硬链接与软链接

Part4.1. 硬链接

命令 ln 原文件 y 创建硬链接。

1. 硬链接不会创建新的inode。新文件名y,只是在当前目录新增一条dentry目录项,指向原文件inode;

2. inode中维护引用计数,创建硬链接,引用计数+1。多个文件名,对应磁盘上同一个inode、同一套数据块;

3. 删除原文件,只是删除一条目录项,inode引用计数减一。只要引用计数>0,inode和数据块保留,其他硬链接依然可以正常访问;

4. 限制:不能跨分区创建硬链接(inode仅分区内唯一);不能给目录创建硬链接,防止目录环路。


补充:目录的引用计数初始值为2。目录内.代表当前目录,..代表上级目录。新建子目录,父目录引用计数继续增加。inode引用计数降到0,内核才会真正释放磁盘上的inode和数据块。


Part4.2. 软链接

命令 ln -s 原文件 y 创建软链接。

1. 软链接会创建独立的inode,独立的数据块;

2. 软链接的数据块里面不保存原文件内容,保存的是目标文件的字符串路径;

3. 可以跨分区创建,也可以给目录创建软链接,效果类似Windows快捷方式;

4. 访问软链接时,内核读取里面保存的路径,重新走一遍路径解析流程,找到目标文件;

5. 如果原文件被删除,软链接本身还存在,但是指向不存在的路径,也就是常说的断链。


一句话区分
硬链接:多个文件名,共用同一个inode,本质是同一个文件。
软链接:全新独立文件,内容是目标路径字符串,属于快捷方式。


Part5. 创建文件的底层本质

当我们新建一个普通文件,内核执行步骤:

1. 在当前块组的inode位图,找到空闲bit,分配一个inode;

2. 在当前目录的目录文件里,新增一条dentry目录项:新文件名 + 新分配inode编号;

3. 向文件写入数据时,再从块位图分配空闲数据块,将内容写入Data Blocks;

4. 更新inode里的块指针、文件大小等元信息。


Part6. 结语

   这篇文章我们深入的知道了文件的相关知识,接下来,小编还会带来更多Linux相关的知识,敬请期待~

 最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!

 最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波,谢谢大家!~

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2501_93971468/article/details/167081680

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--