Brilliantwxx头像
【Linux】 从磁盘硬件到 ext2 文件系统:完整深度详解封面图

【Linux】 从磁盘硬件到 ext2 文件系统:完整深度详解


   从磁盘硬件到 ext2 文件系统:完整深度详解   

第一部分:理解硬件

1.1 磁盘、服务器、机柜、机房

数据存储的物理层级是:

机房(IDC)
  └─ 机柜(Rack,单位 U,常见 42U)
       └─ 服务器 / 磁盘阵列(RAID / JBOD)
            └─ 磁盘(HDD / SSD)
                 └─ 盘片、磁头、扇区

        磁盘是持久化数据的最终载体。

        相比内存(DRAM 掉电即失),磁盘断电后数据不丢,这是它成为"持久存储"的根本原因。

1.2 磁盘物理结构(HDD)

机械硬盘(Hard Disk Drive)由以下核心部件构成:

部件英文作用
盘片Platter圆形,表面涂磁性材料,靠磁畴方向记录 0/1;一块盘有多张盘片
主轴Spindle带动盘片高速旋转(5400 / 7200 / 10000 / 15000 RPM)
磁头Read/Write Head每个盘面对应一个磁头,读写数据,悬浮在盘片上方几纳米
磁头臂Actuator Arm带动磁头沿半径方向移动,定位磁道
磁道Track磁头不动、盘片旋转形成的同心圆
扇区Sector磁道被划分出的弧段,最小读写单位
柱面Cylinder所有盘片上相同半径磁道的集合

1.3 磁盘的存储结构

  • 盘片表面是磁性材料,磁头通电产生磁场改变磁畴方向(写),磁畴变化在磁头感应出电流(读);
  • 数据按扇区存放,每个扇区包括:数据区(512/4096 字节)+ 扇区头(编号、同步信息)+ ECC 校验;
  • 读写必须以整个扇区为单位,哪怕只读 1 个字节,也要把整个扇区读出来。

1.4 磁盘的逻辑结构

1.4.1 理解过程:CHS 三维寻址

早期定位一个扇区,需要三个坐标:

  • C(Cylinder,柱面):先移动磁头到某个半径;
  • H(Head,磁头):选择哪个盘面;
  • S(Sector,扇区):等目标扇区转到磁头下。

        这就是 CHS 三维地址。

设计柱面的好处是:

        同一柱面内切换磁头(电子切换,极快),不用移动磁头臂(机械寻道,很慢),所以早期操作系统尽量把连续数据放在同一柱面。

1.4.2 真实过程:LBA 线性寻址

        CHS 有个致命假设:每个磁道扇区数相同。

        但实际磁盘采用分区位记录(ZBR),外圈磁道周长更长、扇区更多。

        CHS 无法表达真实布局,还带来容量上限。

于是现代磁盘统一使用 LBA(Logical Block Address,逻辑块地址):

  • 把所有扇区从 0 开始线性编号:0, 1, 2, 3 ...;
  • 磁盘内部的控制器负责把 LBA 翻译成真实的 C/H/S;
  • 对操作系统而言,磁盘就是一个"扇区(块)的一维数组"。

1.5 CHS 与 LBA 地址

CHS转成LBA:
  1. 磁头数*每磁道扇区数 = 单个柱⾯的扇区总数
  2. LBA = 柱⾯号C*单个柱⾯的扇区总数 + 磁头号H*每磁道扇区数 + 扇区号S - 1
  3. 即:LBA = 柱⾯号C*(磁头数*每磁道扇区数) + 磁头号H*每磁道扇区数 + 扇区号S - 1
  4. 扇区号通常是从1开始的,⽽在LBA中,地址是从0开始的
  5. 柱⾯和磁道都是从0开始编号的
  6. 总柱⾯,磁道个数,扇区总数等信息,在磁盘内部会⾃动维护,上层开机的时候,会获取到这些参数。
LBA转成CHS:
  1. 柱⾯号C = LBA // (磁头数*每磁道扇区数)【就是单个柱⾯的扇区总数】
  2. 磁头号H = (LBA % (磁头数*每磁道扇区数)) // 每磁道扇区数
  3. 扇区号S = (LBA % 每磁道扇区数) + 1
  4. "//": 表⽰除取整

1.6 磁盘访问的性能拆解

1.6.1 一次磁盘 I/O 的三段时间

阶段符号含义典型耗时
寻道时间T_seek磁头臂移动到目标磁道平均 3-10ms(约 5ms)
旋转延迟T_rotation等待目标扇区转到磁头下平均半圈
传输时间T_transfer数据实际读写数据量 / 传输速率

        平均旋转延迟 = 0.5 / (RPM/60):7200 RPM 约 4.17ms,15000 RPM 约 2ms。

        平均访问时间 = 寻道 + 旋转延迟 + 传输。

1.6.2 IOPS 与吞吐量

  • 随机 IOPS ≈ 1 / (寻道 + 旋转延迟):7200 转 HDD 约 110 IOPS;
  • 顺序吞吐:连续读写几乎不寻道,HDD 约 100-200MB/s;
  • 这解释了为什么顺序 I/O 远快于随机 I/O。

1.7 磁盘接口与现代存储

1.7.1 接口协议

接口带宽特点
SATA6Gbps(~600MB/s)AHCI 协议,单队列,消费级
SAS12/24Gbps企业级,双端口,可靠性高
NVMePCIe 3.0/4.0/5.04/8/16GB/s,64K 队列,多队列并行

1.7.2 SSD 内部原理

  • NAND 闪存:按 SLC/MLC/TLC/QLC 区分每单元位数,位数越多越便宜、寿命越短;
  • 以页(Page)读写、以块(Block)擦除:不能直接覆写,必须先擦后写;
  • FTL(闪存转换层):
    • LBA → PBA(物理地址)映射;
    • 磨损均衡(Wear Leveling)、坏块管理;
    • 垃圾回收(GC):把有效数据搬走再擦除整块;
  • 写放大(WAF):实际写入闪存量 / 主机写入量,GC 导致放大;
  • TRIM:通知 SSD 哪些 LBA 已删除,提升 GC 效率;
  • OP 冗余空间:预留空间给 GC 和映射,降低写放大。

1.7.3 RAID 级别

级别组成可用容量冗余
RAID 0条带N 块无
RAID 1镜像1 块高
RAID 5条带 + 分布式校验N-1允许坏 1 块
RAID 6双校验N-2允许坏 2 块
RAID 10镜像 + 条带N/2高,性能好

第二部分:引入文件系统

        裸磁盘上只有一堆扇区,无法直接管理文件。

        文件系统就是在扇区之上建立的一套组织规则,核心引入三个概念:块、分区、inode。

2.1 引入"块"概念

  • 扇区(512B/4KB)是硬件的最小单位,对文件系统来说太小;
  • 文件系统把若干连续扇区打包成一个块(Block),作为文件系统的最小分配单位:
    • 块大小通常是 1KB / 2KB / 4KB(ext2 可选);
    • 4KB 块 = 8 个连续的 512B 扇区;
  • 为什么用块:
    • 扇区太小,管理海量扇区的元数据开销巨大;
    • 块越大,寻址和 I/O 效率越高,但小文件浪费空间(一个 1B 文件也要占一个块,即内部碎片)。

2.2 引入"分区"概念

分区是把一块磁盘划分成若干个逻辑独立区域,每个区域可以单独格式化、挂载、管理。

2.2.1 MBR 分区(位于 LBA 0,512 字节)

  • 446 字节:引导代码(bootloader);
  • 64 字节:分区表,最多 4 个主分区(每个 16 字节),需要更多分区用扩展分区 + 逻辑分区;
  • 2 字节:魔数 0x55AA。

MBR 分区表项(16 字节)字段:

偏移长度含义
01引导标志:0x80 活动,0x00 非活动
1-33起始 CHS
41分区类型(0x83 Linux、0x82 swap、0x07 NTFS、0x0F 扩展、0xEE GPT 保护)
5-73结束 CHS
8-114起始 LBA
12-154扇区总数

        4 字节扇区数 + 512B 扇区 → 单分区最大 2TB,这是 MBR 的硬限制。

2.2.2 GPT 分区(UEFI 标准)

LBA内容
0保护 MBR(类型 0xEE)
1GPT 头:签名 EFI PART、磁盘 GUID、当前/备份头位置、分区表起止、CRC
2-33分区表:默认 128 项,每项 128 字节
末尾备份 GPT 头和分区表

每个 GPT 表项(128 字节):

        分区类型 GUID、分区唯一 GUID、起始/结束 LBA、

        属性标志、分区名(72 字节 UTF-16)。

2.3 引入"inode"概念

一个文件在磁盘上由两部分组成:

  • 数据(Data):文件的实际内容,存放在数据块(Data Block);
  • 元数据(Metadata):描述文件的属性,存放在 inode(index node):
    • 文件大小、权限(rwx)、属主(uid/gid);
    • 时间戳(atime/mtime/ctime)、硬链接计数;
    • 数据块的位置指针(最关键);
  • 注意:inode 不存文件名。文件名存放在它所属目录的"目录项"里,目录项记录「文件名 → inode 号」的映射。
[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

每⾏包含7列:
• 模式
• 硬链接数
• ⽂件所有者
• 组
• ⼤⼩
• 最后修改时间
• ⽂件名
读取文件:
文件名 →(查目录)→ inode 号 → 找到 inode → 拿到数据块指针 → 读数据块

2.4 目录项结构(ext2_dir_entry_2)

目录是一种特殊文件,其数据块里存放一条条目录项:

字段长度含义
inode4该文件的 inode 号
rec_len2本条记录总长度(用于找下一条)
name_len1文件名长度(最长 255)
file_type11 普通文件 / 2 目录 / 3 字符设备 / 4 块设备 / 5 FIFO / 6 socket / 7 符号链接
name变长文件名,按 4 字节对齐

2.5 硬链接与软链接

硬链接:

        多个目录项指向同一个 inode,共享数据,链接计数 +1;

        不能跨文件系统,不能对目录。

软链接:

        独立文件,有自己的 inode,数据块存目标路径;

        可跨文件系统、可对目录,目标删除后悬空。


第三部分:ext2 文件系统

3.1 宏观认识

序号名称中文名管理范围核心作用
1Super Block超级块整个文件系统记录全局元信息(块 /inode 总数、空闲数、块大小)
2GDT(Group Descriptor Table)组描述符表所有块组记录每个块组的位图位置、inode 表位置和空闲计数
3Block Bitmap块位图本组数据块用每一位标记数据块是否空闲,管块的分配 / 回收
4inode Bitmapinode 位图本组 inode用每一位标记 inode 是否空闲,管 inode 的分配 / 回收
5inode Tableinode 表本组所有 inode连续存放该组全部 inode 结构
6Data Blocks数据块文件 / 目录内容真正存放文件数据和目录项

        ext2(Second Extended Filesystem) 是 Linux 早期经典文件系统(1993 年),结构清晰、无日志,是理解 ext3/ext4 的基础:

  • ext3 = ext2 + 日志(journal);
  • ext4 = ext3 + extent、多块分配等。

一个分区被 mkfs.ext2 格式化后,布局如下:

[启动块 Boot Block][块组0][块组1][块组2] ... [块组N]
  • 启动块(Boot Block):前 1024 字节,不属于任何块组,存放系统引导程序;
  • 其余空间被划分为多个块组(Block Group)。

3.2 Block Group(块组)

为什么把整个分区切成多个块组?

  • 若位图、inode 表集中在一处,文件数据散落在全盘,读写一个文件要来回寻道;
  • 分成块组后,一个文件的 inode 和数据块尽量分配在同一个块组内,减少磁头移动,提升性能;
  • 每个块组自带管理信息,结构相同,也便于冗余备份。

3.3 块组内部构成

每个块组从前往后依次包含 6 个部分:

3.3.1 超级块(Super Block)

超级块是整个文件系统的"户口本",完整字段:

字段含义
s_inodes_count / s_blocks_countinode / 块总数
s_r_blocks_count保留给 root 的块数(默认 5%,磁盘满时管理员可用)
s_free_blocks_count / s_free_inodes_count空闲块 / inode 数
s_first_data_block第一个数据块(1KB 块时为 1,否则 0)
s_log_block_size / s_log_frag_size块 / 片大小(2^n × 1024)
s_blocks_per_group / s_frags_per_group / s_inodes_per_group每组块 / 片 / inode 数
s_mtime / s_wtime最后挂载 / 写入时间
s_mnt_count / s_max_mnt_count挂载次数 / 强制检查的次数
s_magic0xEF53
s_state / s_errors状态(干净/脏)/ 出错策略
s_creator_os / s_rev_level创建 OS / 修订级别
s_def_resuid / s_def_resgid保留块默认 uid/gid
s_first_ino / s_inode_size第一个非保留 inode / inode 大小(动态版)
s_feature_compat / incompat / ro_compat兼容特性位图

3.3.2 GDT(Group Descriptor Table)

每个块组对应一个 32 字节的描述符:

字段含义
bg_block_bitmap块位图所在块号
bg_inode_bitmapinode 位图所在块号
bg_inode_tableinode 表起始块号
bg_free_blocks_count该组空闲块数
bg_free_inodes_count该组空闲 inode 数
bg_used_dirs_count该组目录数

3.3.3 块位图(Block Bitmap)

  • 块位图占一个块,每一位对应块组里的一个数据块:0=空闲,1=占用;
  • 分配时找 0 位置 1,释放时清 0;
  • 一个 4KB 块有 4096 位,可管理 4096 个数据块(16MB)。

3.3.4 inode 位图(Inode Bitmap)

        与块位图结构相同,每一位对应一个 inode,管理 inode 的分配与回收。

3.3.5 inode 表(Inode Table)

        所有 inode 连续存放在 inode 表中,每个 ext2 inode 固定 128 字节,完整字段:

字段含义
i_mode文件类型 + 权限
i_uid / i_gid属主 uid/gid
i_size文件大小(字节)
i_atime / i_ctime / i_mtime / i_dtime访问 / inode 改变 / 修改 / 删除时间
i_links_count硬链接计数
i_blocks占用块数(512B 为单位)
i_flags文件标志
i_block[15]数据块指针(12 直接 + 3 间接)
i_generation文件版本(NFS 用)
i_file_acl / i_dir_acl访问控制块

3.3.6 数据块(Data Block)

        存放文件实际内容;

        目录的内容(目录项)也存放在数据块中。

3.4 inode 与数据块映射

inode 中的 i_block[15] 有 15 个 4 字节指针,采用直接 + 多级间接寻址,兼顾小文件和大文件:

寻址能力(块大小 4KB,一个间接块可存 1024 个指针):

寻址方式对应 i_block最大容量
直接块[0]~[11]12 × 4KB = 48KB
一级间接[12]1024 × 4KB = 4MB
二级间接[13]1024² × 4KB = 4GB
三级间接[14]1024³ × 4KB = 4TB

设计思想:

        小文件(绝大多数文件)只用直接块,一次定位、速度快;

        大文件才用间接块,用多级索引换取超大寻址空间。

3.5 创建文件的完整流程

3.6 数据块寻址实例

块大小 4KB,一个间接块可存 4096/4 = 1024 个指针。读取文件偏移 100000 字节:

  1. 逻辑块号 = 100000 / 4096 = 24,块内偏移 = 100000 % 4096 = 1696;
  2. 前 12 个直接块覆盖逻辑块 0-11;
  3. 逻辑块 24 → 24 - 12 = 12,落在一级间接,索引为 12;
  4. 找到 i_block[12] 指向的间接块,读取其中第 12 个指针,得到物理数据块;
  5. 从该块偏移 1696 处读取。

判断偏移落在哪个层级:

逻辑块范围寻址方式
0-11直接块
12-1035一级间接(1024 项)
1036-1049611二级间接(1024² 项)
1049612 以上三级间接

第四部分:实操命令

# 查看磁盘扇区/分区
sudo fdisk -l
lsblk

# 格式化为 ext2 并查看文件系统信息
mkfs.ext2 /dev/sdb1
dumpe2fs /dev/sdb1       # 查看超级块、块组、GDT 详细信息

# 查看块大小和保留块
tune2fs -l /dev/sdb1 | grep -i block

# 挂载与查看
mount /dev/sdb1 /mnt
df -i                    # 查看 inode 使用情况
df -h                    # 查看空间使用情况

# 查看文件的 inode 与占用块
stat file
ls -ls file
ls -i file

# 链接
ln source link           # 硬链接
ln -s source link        # 软链接

# SSD TRIM
sudo fstrim -v /

第五部分:面试题(含答案)

磁盘的最小读写单位是什么?文件系统的最小分配单位是什么?

         扇区(512B/4KB)是硬件最小单位;

        块(Block,通常 4KB)是文件系统最小分配单位,由多个连续扇区组成。

磁道、扇区、柱面分别是什么?

        磁道是同心圆,扇区是磁道上的弧段,柱面是所有盘片相同半径磁道的集合。

CHS 和 LBA 有什么区别?为什么现代磁盘用 LBA?

        CHS 是三维物理寻址,假设每磁道扇区数相同,无法表达分区位记录、限制容量;

        LBA 线性编号,由控制器翻译成真实 C/H/S,磁盘被抽象成扇区一维数组。

CHS 到 LBA 的转换公式?

         LBA = (C × HPC + H) × SPT + (S − 1)。

一次磁盘访问包含哪几段时间?

        寻道(机械移动)+ 旋转延迟(等扇区)+ 传输,HDD 随机 IOPS 约 100。

为什么顺序 I/O 比随机 I/O 快得多?

        顺序几乎不寻道,随机每次都要付寻道 + 旋转延迟。

SSD 为什么快?FTL 做什么?

         无机械结构;FTL 做 LBA→PBA 映射、磨损均衡、GC、坏块管理。

MBR 单分区为什么最大 2TB?

         4 字节扇区数 × 512B ≈ 2TB,GPT 用 64 位 LBA 解决。

MBR 最多几个主分区?怎么扩展?

        4 个主分区,用扩展分区 + 逻辑分区突破。

inode 存文件名吗?文件名存哪?

         不存,文件名在父目录的目录项里,目录项记录 name→inode。

一个文件由哪两部分组成?

         元数据(inode)+ 数据(数据块)。

硬链接和软链接的本质区别?

        硬链接共享同一 inode(计数+1,不能跨 fs、不能对目录);

        软链接是独立文件、存目标路径,可跨 fs、可对目录。

新建目录的链接计数为什么是 2?

         自身 "." + 父目录 "..",每个子目录还会让它再 +1。

ext2 为什么分块组?

         让一个文件的 inode 和数据块尽量在同一组,减少磁头移动、提升性能。

ext2 块组内部依次包含什么?

         超级块 → GDT → 块位图 → inode 位图 → inode 表 → 数据块。

超级块记录什么?魔数是多少?

         块/inode 总数、空闲数、块大小、每组块数等,魔数 0xEF53;

        块组0为正本,其余有备份。

GDT 记录什么?

        每个块组的块位图、inode 位图、inode 表位置和空闲计数。

位图的作用?

        块位图/inode 位图用每一位表示块/inode 是否空闲,是分配的账本。

文件系统怎么分配一个空闲块?

        查块位图找 0 位、置 1,更新组描述符和超级块空闲计数。

ext2 大文件怎么寻址?

         12 直接 + 一/二/三级间接,4KB 块下三级间接可达 4TB。

保留块(reserved blocks)是干什么的?

         留给 root,磁盘满时管理员仍能启动/恢复,默认 5%。

块大小怎么选?

         大块顺序效率高,小文件浪费少,取决于典型文件大小和工作负载。

总结

整条链路的核心是把"磁盘怎么转、块怎么分、inode 怎么找到块"三件事打通:

  1. 硬件层:磁盘 = 盘片 + 磁头,数据按扇区存放;
  2. CHS 是三维物理寻址,LBA 是现代线性寻址,磁盘被抽象成"扇区一维数组";
  3. HDD 慢在机械寻道(随机 ~100 IOPS),SSD 用 FTL 和电子寻址消除了它。
  4. 文件系统引入:块(多个扇区,最小分配单位)、分区(MBR/GPT 划分独立区域)、inode(文件元数据 + 数据块指针,不存文件名);
  5. 文件名在目录项里,链接分硬链接(共享 inode)和软链接(独立文件存路径)。
  6. ext2 实现:分区划为多个块组,每个块组依次是超级块 → GDT → 块位图 → inode 位图 → inode 表 → 数据块;位图管分配,inode 用直接 + 三级间接寻址,小文件快、大文件容量大。

记住这条主线:扇区 → 块 → inode → 数据块,磁盘与文件系统的底层原理就彻底打通了。


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

原文链接:https://blog.csdn.net/2602_95649725/article/details/169168993

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

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