Linux: Ext系列文件系统
Ext系列文件系统磁盘硬件机械磁盘是计算机中唯一的机械设备。盘片磁盘存储数据的载体表面有磁性涂层一张硬盘可有多片盘片盘片正反两面都能存数据每面对应一个独立磁头。主轴马达带动所有盘片同步高速旋转读写时盘片持续转动。磁头臂 读写磁头所有磁头绑定同一根机械臂共进退只能同步移动到同一半径磁头悬浮在盘片上方不接触盘面负责读写磁性数据。磁盘存储结构。扇区 Sector磁盘硬件读写最小单位标准 512 字节一个圆环磁道被切分成若干扇形小块编号从 1 开始。磁道 Track盘面上一圈同心圆外圈是 0 号磁道向内依次递增同一盘面同一半径的圆环就是一条磁道。柱面 Cylinder所有盘片相同半径的全部磁道合起来称为一个柱面因为磁头共进退读写同一柱面不用移动机械臂性能更高。磁盘容量 磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数。CHS寻址(老式寻址有容量上限)通过柱面 C 磁头 H 扇区 S三维定位扇区硬件位数限制最大仅支持约 8GB 硬盘现已淘汰。LBA线性寻址(现代磁盘默认)把磁盘所有扇区拉直成一维数组每个扇区分配唯一连续数字下标LBA 编号从 0 开始操作系统只使用 LBA磁盘固件内部自动完成 LBA ↔ CHS 转换上层无需关心物理结构。磁盘最终可看成一个三维数组。文件系统概念硬盘是典型的“块”设备操作系统读取硬盘数据的时候其实是不会一个个扇区地读取这样效率太低而是一次性连续读取多个扇区即一次性读取一个”块”block。硬盘的每个分区是被划分为一个个的”块”。一个”块”的大小是由格式化的时候确定的并且不可以更改最常见的是4KB即连续八个扇区组成一个 ”块”。”块”是文件存取的最小单位。磁盘就是一个三维数组我们把它看待成为一个一维数组数组下标就是LBA每个元素都是扇区。每个扇区都有LBA那么8个扇区一个块每一个块的地址我们也能算出来。块号 LBA / 8 LAB 块号 × 8 n (n是块内第几个扇区)。磁盘可以被分成多个分区partition以Windows观点来看你可能会有一块磁盘并且将它分区成C,D,E盘。那个C,D,E就是分区。分区从实质上说就是对硬盘的一种格式化。柱面是分区的最小单位我们可以利用参考柱面号码的方式来进行分区其本质就是设置每个区的起始柱面和结束柱面号码。 此时我们可以将硬盘上的柱面分区进行平铺将其想象成一个大的平面。文件数据都储存在”块”中那么很显然我们还必须找到一个地方储存文件的元信息属性信息比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode中文译名为”索引节点”。每一个文件都有对应的inode。Linux下文件的存储是属性和内容分离存储的保存文件属性的集合是inode一个文件有一个inodeinode内有一个唯一的标识符叫做inode号。ls -i查看文件inode号。文件名属性并未纳入到inode数据结构内部inode大小一般是128字节或者256字节后面统一128字节。ext2文件系统我们想要在硬盘上储文件必须先把硬盘格式化为某种格式的文件系统才能存储文件。文件系统的目的就是组织和管理硬盘中的文件。在Linux 系统中最常见的是 ext2 系列的文件系统。其早期版本为 ext2后来又发展出 ext3 和 ext4。ext3 和 ext4 虽然对 ext2 进行了增强但是其核心设计并没有发生变化。ext2文件系统将整个分区划分成若干个同样大小的块组 (Block Group)如下图所示。只要能管理一个分区就能管理所有分区也就能管理所有磁盘文件。图中**启动块Boot Block/Sector**的大小是确定的为1KB由PC标准规定用来存储磁盘分区信息和启动信息任何文件系统都不能修改启动块。启动块之后才是ext2文件系统的开始。Data Blocks保存文件内容。inode Table是大小为4KB的块会保存32个文件的inode。Block Bitmap是位图记录着Data Blocks中哪个数据块已经被占用哪个数据块没有被占用。inode Bitmap同理每个bit表示一个inode是否空闲可用。GDT是块组描述符表描述块组属性信息整个分区分成多个块组就对应有多少个块组描述符。每个块组描述符存储一个块组的描述信息如在这个块组中从哪里开始是inode Table从哪里开始是DataBlocks空闲的inode和数据块还有多少个等等。块组描述符在每个块组的开头都有一份拷贝。Super Block存放文件系统本身的结构信息描述整个分区的文件系统信息。记录的信息主要有bolck 和 inode 的总量未使用的block和inode的数量一个block和inode的大小最近一次挂载的时间最近一次写入数据的时间最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏可以说整个文件系统结构就被破坏了。超级块在每个块组的开头都有一份拷贝第一个块组必须有后面的块组可以没有。 为了保证文件系统在磁盘部分扇区出现物理问题的情况下还能正常工作就必须保证文件系统的super block信息在这种情况下也能正常访问。所以一个文件系统的super block会在多个block group中进行备份这些super block区域的数据保持一致。文件名不存放在 inode 内保存在所属目录的数据块中。目录本质也是文件目录同样拥有自己的 inode 与数据块目录数据块内存储文件名 - inode 编号 映射表。文件访问逻辑路径解析用户操作只使用路径 文件名不直接操作 inode操作系统逐层解析路径打开每一级目录读取目录内文件名与 inode 的映射逐级找到目标文件 inode所有文件访问必须依赖路径路径由进程提供。原则上访问任何文件都要从根目录开始进行路径解析但是这样太慢所以Linux会缓存历史路径结构路径缓存。Linux中在内核中维护树状路径结构的内核结构体是struct dentry。每个文件其实都要有对应的dentry结构包括普通文件。这样所有被打开的文件就可以在内存中形成整个树形结构。整个树形节点也同时会隶属于LRU(Least Recently Used最近最少使用)结构中进行节点淘汰。整个树形节点也同时会隶属于Hash方便快速查找。更重要的是这个树形结构整体构成了Linux的路径缓存结构打开访问任何文件都先在这棵树下根据路径进行查找找到就返回属性inode和内容没找到就从磁盘加载路径添加dentry结构缓存新路径。inode 仅在单个分区内有效、不能跨分区Linux 存在多个磁盘分区操作系统需要通过挂载机制根据文件路径区分文件所属分区。分区写入文件系统无法直接使用需要和指定的目录关联进行挂载才能使用。该指定目录为挂载点。文件路径前缀不同挂载点前缀对应不同分区系统借此定位分区再在分区内通过 inode 查找文件。完整文件访问流程用户进程发起文件操作如cat /a/b/test.txt。内核读取当前进程fs_struct的pwd/root作为路径解析起点逐层匹配各级 dentry。通过 dentry 的d_inode找到目标文件 inode通过vfsmount确定文件所在挂载分区。open系统调用在进程files_struct的fd_array分配空闲 fd新建struct file绑定该 inode 与挂载信息。用户调用read(fd)通过 fd 找到struct file调用f_op-read最终调用 ext4 底层接口读取磁盘数据块。软硬链接ln -s 原文件路径 软链接名称软链接依靠文件路径名指向原文件软链接自身是独立文件拥有专属 inode它保存的内容就是原文件的路径。把可执行程序code移到./a/b/c下如果要运行code就要带很长的路径。软链接后输入的路径变短更加方便快捷所以软链接类似Windows快捷方式。ln 原文件路径 硬链接名称硬链接不是独立文件它没有独立inode本质是一组新的文件名和目标文件inode的映射关系。code.c文件属性中的一列数字由1变成2这一列数字是硬链接数。硬链接的一个用处是备份文件。在a目录下备份code.c删除原目录中的code.c仍能在code-backup.c拿到code.c的内容。目录a的硬链接数是3。Linux 目录的硬链接计数 3 个固定组成部分目录自身的.当前目录进入目录 a 后执行ls -al看到的.是目录 a 自身的硬链接占用 1 个计数上级目录里的目录名a外层lesson20260717目录中存在名为a的目录项这是目录 a 的主别名占用第 2 个计数子目录内的..上级目录目录a下面存在子目录b子目录b里自带..硬链接指向父目录a占用第 3 个计数。unlink 软/硬链接删除软硬链接。只能给普通文件建立硬链接目录不能建立硬链接。因为容易出现环路径问题系统查找文件进行深度优先遍历时就会出问题。.和..虽然也是目录的硬链接但系统特殊处理即可。可以对普通文件和目录建立软链接因为建立的软链接是独立文件且不再是普通文件所以不会出现环路径问题。