目录
Part3. 目录、dentry目录项、路径解析与dentry缓存
前言
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





