
1.理解硬件上一篇文章我们已经学习了被进程打开的文件是被加载到在内核的内存中中由OS进行以先组织后描述“的方法进行管理的那么没有被加载到内存的文件是在哪里呢由谁管理呢不错是在磁盘上由Ext文件系统进行管理而Ext文件系统本质上是被建立在磁盘分区上的一套管理数据的结构与规则包含超级块、inode 表、数据块等全部存储在磁盘上用于组织、索引、存放文件。所以我们先从磁盘开始学习吧1.1磁盘① 磁盘特点机械磁盘是计算机中唯一的机械设备磁盘也属于外设运行速度满但是容量大价格便宜② 磁盘的物理结构③磁盘的存储结构④ 如何定位一个扇区先定位磁头(也就是我们看到的哪一面注意正方面都有磁面也就都有磁头)现在三维空间变成二维了然后我们再定位要访问哪一个磁道(柱面不是横着的柱面竖着的)一个面的哪一圈最后定位是这一圈上的哪一段也就是扇区我们把这样的地址定位方法叫做CHS地址定位关于CHS寻址 对早期的磁盘⾮常有效知道⽤哪个磁头读取哪个柱⾯上的第⼏扇区就可以读到数据了。但是CHS模式⽀持的硬盘容量有限因为系统⽤8bit来存储磁头地址⽤10bit来存储柱⾯地址⽤6bit来存储扇区地址⽽⼀个扇区共有512Byte这样使⽤CHS寻址⼀块硬盘最⼤容量为256 * 1024 * 63 * 512B 8064 MB(1MB 1048576B)若按1MB1000000B来算就8.4GB总结扇区是磁盘读出和写入信息的最小物理单位通常大小为 512 字节现代磁盘也常见 4096 字节的高级格式化扇区。磁头head数每个盘片有上下两个盘面每个盘面对应 1 个独立磁头因此 1 个盘片对应 2 个磁头多盘片则磁头数按盘面数累加。磁道track数磁道是盘片上以主轴为中心的同心圆从外圈向内圈依次编号为 0 磁道、1 磁道……靠近主轴的最内侧同心圆为 “着陆区”停靠区仅用于磁头停靠不存储数据。柱面cylinder数所有盘片上同一编号的磁道垂直对齐形成柱面柱面数量与单个盘片的磁道数量完全相等。扇区sector数每个磁道被等分成若干扇形区域扇区同一磁盘中每道的扇区数量固定且相同。盘片platter数即磁盘中物理盘片的总数量。磁盘容量计算公式磁盘容量 磁头数 × 柱面数 × 每道扇区数 × 每扇区字节数。核心细节所有磁头固定在同一传动臂上移动时同步进退即所有磁头同时定位到对应盘片的同一编号磁道。⑤磁盘的逻辑结构磁带上⾯可以存储数据我们可以把磁带“拉直”形成线性结构这样每⼀个扇区就有了⼀个线性地址(其实就是数组下标)这种地址叫做 LBA真实结构磁道柱面整体整个磁盘不就是多张⼆维的扇区数组表(三维数组)所有寻址⼀个扇区先找到哪⼀个柱⾯(Cylinder) ,在确定柱⾯内哪⼀个磁道(其实就是磁头位置Head)在确定扇区Sector所以就有了 CHS 。现在我们再看在其实全部都是⼀维数组所以每⼀个扇区都有⼀个下标我们叫做 LBA(Logical Block Address) 地址,其实就是线性地址。所以怎么计算得到这个LBA地址呢OS只需要使用LBA就可以了LBA地址转成CHS地址CHS如何转换成为LBA地址。谁做啊磁盘自己来做⑥CHS 与 LBA 地址转换核心总结CHS柱面 - 磁头 - 扇区是早期磁盘的物理寻址方式LBA逻辑块寻址是将磁盘抽象为一维扇区数组的逻辑寻址方式二者可互相转换且现代系统仅使用 LBA 寻址磁盘内部自动完成与 CHS 的转换扇区号SCHS 中从 1 开始编号LBA 中从 0 开始编号柱面号C、磁头号H均从 0 开始编号磁盘会自动维护总柱面数、磁头数、每磁道扇区数等参数系统开机时可读取。CHS 转 LBA物理地址→逻辑地址先计算单个柱面的扇区总数单个柱面扇区数 磁头数 × 每磁道扇区数转换公式LBA 柱面号 C × 单个柱面扇区数 磁头号 H × 每磁道扇区数 扇区号 S - 1减 1 是因为 CHS 扇区从 1 开始LBA 从 0 开始完成编号对齐。LBA 转 CHS逻辑地址→物理地址柱面号 C LBA // (磁头数 × 每磁道扇区数) // 表示整除取整磁头号 H (LBA % (磁头数 × 每磁道扇区数)) // 每磁道扇区数扇区号 S (LBA % 每磁道扇区数) 1 加 1 还原 CHS 扇区从 1 开始的编号规则。现代操作系统将磁盘抽象为“以扇区为元素的一维数组”数组下标即为扇区的 LBA 地址只需通过一个数字即可访问对应扇区CHS 仅作为磁盘底层的物理寻址方式由磁盘硬件自行完成与 LBA 的转换使用者无需关注。2.ExT文件系统一块磁盘 → 分成分区 → 每个分区放 Ext4 文件系统2.1什么是块硬盘是典型的块设备。操作系统读取硬盘数据时不会以单个扇区为单位读取这样效率太低而是一次性连续读取多个扇区即一次性读取一个块Block。硬盘的每个分区都会被划分为一个个块块的大小在格式化时确定之后不能更改最常见的大小是4KB也就是由连续的8 个 512 字节的扇区组成一个块。块是文件系统存取数据的最小单位。2.2什么是分区磁盘可以被划分成多个分区partition。以 Windows 为例一块磁盘可以分成 C、D、E 盘C、D、E 就是分区。分区并不是格式化而是在磁盘上划分出一段连续的物理范围格式化是在分好的分区上建立文件系统。Linux 下所有设备都以文件形式存在分区同样对应设备文件如 /dev/sda1、/dev/sda2。柱面是传统磁盘分区的最小单位分区的本质就是记录每个分区的起始柱面号和结束柱面号以此圈定一段独立的物理空间。我们可以把磁盘上所有柱面按顺序平铺展开看作一个线性的地址空间分区就是在这个线性空间里划定一段连续的范围。2.3什么是inode文件由 数据 属性元信息组成使用ls -l时除文件名外看到的都是文件元数据。ls -l会读取磁盘上的文件信息并显示出来。文件数据存储在块block中而存储文件元信息如文件创建者、时间、大小、权限等的区域称为 inode索引节点。每个文件都对应一个 inode里面存放该文件的相关属性。由此可知Linux 中文件的属性与内容是分开存储的。存放文件属性的集合称为 inode一个文件对应一个 inode每个 inode 有唯一的inode 号。文件名并不存储在 inode 结构中inode 大小通常固定为 128 字节或 256 字节后续统一按 128 字节理解。不同文件的数据长度可以不同但属性inode的大小是固定的。3.正式理解Ext文件系统所有准备工作完成后我们来认识文件系统。想要在硬盘上存储文件必须先将硬盘格式化为某种文件系统才能正常存放和管理文件文件系统的作用就是组织和管理硬盘中的文件。在 Linux 中最常见的是Ext 系列文件系统早期为 Ext2后续发展出 Ext3 和 Ext4Ext3、Ext4 在 Ext2 基础上做了功能增强但核心设计基本保持不变。Ext2 文件系统会把整个分区划分为若干个大小相同的块组Block Group。只要理解了一个块组的管理方式就能理解整个分区的管理逻辑进而实现对磁盘上所有文件的组织与管理。每一块在一个磁道上整个分区是柱面的一部分3.1每一块的作用①启动块启动块Boot Block/Sector的大小是确定的为1KB由PC标准规定用来存储磁盘分区信息和启动信息任何文件系统都不能修改启动块。启动块之后才是ext2文件系统的开始和文件系统管理无关。②超级块SuperBlock整个文件系统的 “总说明书”多大、有多少 inode、有多少数据块、块大小是多少超级块Super Block用于存放文件系统自身的结构信息描述整个分区的文件系统状况。它记录的主要信息包括block 与 inode 的总量、未使用的 block 和 inode 数量、block 和 inode 的大小、最近一次挂载时间、最近一次数据写入时间、最近一次磁盘检验时间等其他文件系统相关信息。超级块的信息一旦被破坏整个文件系统结构就会损坏。超级块在每个块组的开头都可能存在一份拷贝第一个块组必须包含超级块后面的块组可以选择性备份。为了保证磁盘部分扇区出现物理故障时文件系统仍能正常工作必须确保超级块信息依然可以访问。因此一个文件系统的超级块会在多个块组中进行备份且所有备份的超级块数据保持一致③组描述符管理每个块组的信息相当于 “片区管理员”。块组描述符表Group Descriptor Table用于描述块组的属性信息。整个分区划分为多少个块组就对应有多少个块组描述符。每个块组描述符存储一个块组的管理信息例如该块组中 inode 表从哪里开始、数据块从哪里开始、空闲的 inode 和数据块还有多少个等。为了保证文件系统的可靠性块组描述符也会像超级块一样在每个块组的开头都保存一份拷贝。④块位图 inode 位图⑤块位图记录哪个数据块是空的、哪个被用了每一个bit表示一个inode是否空闲可用⑥inode 位图记录哪个 inode 是空的、哪个被用了每一个bit表示一个ionde是够空闲可用⑦inode 表核心存放文件属性如文件大小、文件所有者、最近修改时间、权限等。每个块组中当前组所有 inode 的集合称为 inode 表inode Table。inode 编号以分区为单位统一分配不能跨分区使用。⑧ 数据块真正存文件内容的地方。也就是一个一个的block,对于普通文件文件的数据存储在数据块中对于目录该目录下的所有文件存储在所在目录的数据块中除了文件名外分区后的格式化操作本质是对分区进行块组划分并在每个块组中写入超级块SB、块组描述符表GDT、块位图Block Bitmap、inode 位图Inode Bitmap等管理信息这些管理信息的集合就构成了文件系统。只要知道文件的 inode 号就能在指定分区中确定它所属的块组进而在该块组中定位到对应的 inode。找到 inode 后就能获取到文件的全部属性同时通过 inode 中记录的信息找到文件数据所在的数据块从而获取文件的完整内容。3.2 inode和datablock文件映射3.3 思考(重点)请解释知道inode号的情况下在指定分区请解释对⽂件进⾏增、删、查、改是在做什么①查读取文件根据 inode 号找到对应的 inode 结构。从 inode 中读出文件属性权限、大小、时间等文件数据所在的 数据块编号把对应的数据块把内容读出来。一句话查 用 inode 找到数据块读取内容 属性。②改修改文件内容通过 inode 号定位到 inode。根据 inode 里的指针找到原有数据块。把新内容写入这些数据块覆盖或追加。如果文件大小变了更新 inode 里的文件大小。一句话改 找到数据块改写内容并更新 inode。③增给文件追加内容 / 增加数据定位到文件的 inode。看当前数据块是否够用够用 → 直接写。不够用 → 通过块位图申请新的空闲数据块。把新块编号记入 inode。更新 inode 中的文件大小。一句话增 申请新数据块写入数据更新 inode。④删删除文件删除文件根本不删数据只做 3 件事根据 inode 号找到 inode。把 inode 对应的 inode 位图 标记为未使用。把文件占用的所有 数据块 通过块位图标记为空闲。数据本身还在磁盘上只是被标记为 “可覆盖”。一句话删 释放 inode 释放数据块标记为可用3.4 在实际中分析通过touch 创建一个新文件看磁盘文件的具体操作情况[rootlocalhost linux]# touch abc [rootlocalhost linux]# ls -i abc 263466 abc①存储属性内核先找到一个空闲的 inode索引节点此处为 263466并将文件的属性信息如大小、所有者、创建时间等记录到该 inode 中。②存储数据该文件需要占用三个磁盘块来存储内容内核从磁盘中找到三个空闲的数据块编号为 300、500、800随后将内核缓冲区中的数据按顺序复制到这些块中第一部分数据写入 300 块第二部分写入 500 块第三部分写入 800 块。③记录分配情况文件内容按 300→500→800 的顺序存放内核会在该文件对应的 inode 中专门记录数据块分布的区域指针区记录这三个块的编号列表以此关联文件属性与数据存储位置。④添加文件名到目录新建文件名为 abcLinux 会在当前目录中完成如下记录内核将映射关系inode 号 263466文件名 abc作为一条条目添加到目录文件的数据块中。文件名与 inode 号的对应关系是连接文件名、文件内容和文件属性的核心纽带。注意目录也是普通文件存储在数据块的块中目录的内容中保存的是文件名和inode的映射关系所以访问文件必须打开当前目录根据文件名获得相应的inode号然后进行文件的访问所以访问文件必须知道当前的工作目录本质是必须打开当前工作目录的文件查看目录文件的内容4.路径解析我们先理清核心问题当前工作目录本质是目录文件访问它看似只知道文件名实则需要先找到它的 inode但要获取当前工作目录的 inode又得先访问它的上级目录 —— 这就陷入了 “先有鸡还是先有蛋” 的循环。①表层疑问要访问当前工作目录目录文件确实需要先打开它的上级目录再通过 “上级目录文件中的「当前目录名→inode 号」映射关系” 找到当前目录的 inode但上级目录本身也是目录文件同样需要解析它的上级目录。②核心逻辑这个过程类似 “递归解析”而递归的 “出口” 是根目录「/」 ——根目录的 inode 号是 Linux 内核固定约定的通常为 2无需通过其他目录解析是路径解析的起点。③最终结论Linux 路径解析访问任何文件 / 目录比如 /home/whb/code/test/test/test.c系统都会从根目录「/」开始按路径层级依次解析每一个目录①打开根目录「/」已知 inode2找到其中「home→inode 号」的映射获取 home 目录的 inode②打开 home 目录找到其中「whb→inode 号」的映射获取 whb 目录的 inode③依次解析 code、test第一层、test第二层目录最后在最终的 test 目录中找到··test.c→inode 号」的映射完成文件定位。整个逐层解析目录、从根到目标的过程就是 Linux 的路径解析。可是路径是谁提供的呢我们访问文件时看似是手动输入指令 / 使用工具操作本质是进程在访问文件每个进程都有自己的当前工作目录CWD进程会基于 CWD 或用户提供的路径来定位文件比如调用open函数时传入的路径。但核心疑问是最初的路径从何而来 这需要从 Linux 文件系统的设计逻辑和使用逻辑两层解答①根目录的核心意义Linux 必须有根目录「/」—— 它是所有路径的起点inode 号固定为 2没有根目录就无法完成路径解析的 “递归出口”所有文件 / 目录都失去了定位的基础而根目录下的默认目录如/bin、/etc、/home、/usr等是系统预设的标准化结构目的是按功能分类存储文件比如/bin存系统指令、/etc存配置、/home存用户数据让系统和用户能统一、规范地管理文件。②家目录与自定义目录的意义每个用户都有专属家目录如/home/whb是系统为用户分配的默认操作空间用户也可以自行新建目录 —— 这些行为的本质都是在磁盘的文件系统中新建目录文件。而我们新建的任何文件都会被创建在系统或用户指定的目录下这就天然赋予了文件 “可被解析的路径”比如/home/whb/test.txt。综上Linux 的路径结构并非凭空存在由系统预设根目录和标准化默认目录作为基础框架再由用户根据需求新建目录 / 文件填充最终形成完整、可解析的路径体系5.路径缓存(struct dentry)问题 1Linux 磁盘中存在真正的 “目录” 吗答案不存在。磁盘中只有 “文件” 这一种存储形态 —— 无论是普通文件还是我们认知中的 “目录”本质都是文件仅存储两部分内容文件属性inode 文件内容数据块所谓 “目录”只是内容为「文件名→inode 号」映射表的特殊文件。问题 2访问任何文件都要从「/」目录开始进行路径解析吗答案原则上是根目录是路径解析的唯一起点但纯磁盘级的逐层解析效率极低。因此 Linux 会在内存中缓存历史路径结构优先从缓存查找大幅提升访问速度。问题 3Linux “目录” 的概念是怎么产生的答案磁盘中仅存在 “目录文件”而我们感知到的 “目录树”“路径层级” 等 “目录” 概念是操作系统在内存中构建的逻辑结构当打开的文件是目录文件时Linux 内核会在内存中通过dentry 结构体目录项结构体struct dentry 维护路径关系。所有被打开的文件包括普通文件、目录文件都有对应的 dentry 结构这些 dentry 节点在内存中串联成树形路径结构这就是我们感知到的 “目录树”该树形节点同时隶属于LRULeast Recently Used最近最少使用淘汰机制长时间未访问的 dentry 节点会被释放节省内存节点还被纳入哈希表Hash通过路径快速哈希查找避免逐层遍历提升查找效率核心作用这棵内存中的 dentry 树构成了 Linux 的路径缓存—— 访问文件时先在缓存中按路径查找 dentry 节点✅ 找到直接通过 dentry 获取 inode属性和数据块内容无需访问磁盘❌ 没找到从磁盘加载路径、创建对应的 dentry 节点并加入缓存再返回文件信息。6.挂载分区我们已经掌握在指定分区内可通过 inode 号找到文件也能通过目录文件的「文件名→inode 号」映射定位 inode看似能自由操作文件但核心疑问随之而来inode 号仅在所属分区内唯一无法跨分区识别Linux 系统支持多个分区如/dev/sda1、/dev/sda2如何判断目标文件所在的分区先补充关键背景/dev/loop0是 Linux 的第一个循环设备loop device也叫回环 /loopback 设备属于伪设备pseudo-device。它的核心作用是允许将普通文件如 ISO 镜像当作块设备使用可像物理硬盘分区一样挂载为文件系统。而解决 “跨分区识别” 问题的核心机制是挂载mount磁盘分区被写入文件系统后无法直接访问必须将分区与系统中一个指定的目录挂载点建立关联即 “挂载”才能通过该目录访问分区内的文件。由此得出核心结论通过目标文件的「路径前缀」就能准确判断其所在的分区理解到这一层即可。比如若文件路径是/home/test.txt且/home是/dev/sda2的挂载点则该文件在/dev/sda2分区若文件路径是/mnt/iso/file.iso且/mnt/iso是/dev/loop0的挂载点则该文件在/dev/loop0对应的循环设备文件分区中。总结inode 号仅在分区内唯一跨分区无意义需通过 “挂载” 解决跨分区访问问题分区需挂载到指定目录挂载点才能使用目标文件的路径前缀对应其挂载点由此可判断所在分区/dev/loop0是循环伪设备可将文件当作块设备挂载本质仍遵循 “路径前缀→分区” 的判断逻辑。7.软硬连接7.1软链接①本质软连接 快捷方式自己是独立的小文件有自己的 inode。内容只有一行指向原来的路径源文件删了软连接就失效变红可以跨分区、可以给目录创建②特点相当于 Windows 快捷方式可以跨分区可以链接目录源文件没了软连接就断了③实现ln -s 源文件 软连接文件7.2硬链接①本质硬链接 同一个 inode多个文件名文件真正的身份是 inode 号所有硬链接共用同一个 inode删除其中一个文件名文件本体还在只有当最后一个文件名被删掉文件才真正删除② 特点不能跨分区不能给目录创建硬链接系统限制不占用额外 inode删哪个名字都不影响文件本体③用途A.防止误删文件最核心你给文件建几个硬链接删掉任何一个文件名文件本体都不会丢。只有最后一个名字被删文件才真正删除。→ 适合重要数据、备份、不想被误删的文件。B.同一个文件在多个地方能用比如/a/file.txt你在 /b/ 也想用它建硬链接/b/file.txt两个路径访问的是完全同一个文件不占双倍空间。C. 节省磁盘空间硬链接不复制数据只多一个目录项。→ 大文件想在多处使用又不想复制用硬链接。④实现ln 源文件 硬链接文件8.pid和inode的区别① inode索引节点管的是磁盘上的文件在哪磁盘、文件系统里作用标识一个文件属性 数据位置谁用文件系统、open、read、write一句话inode 文件的身份证号磁盘层面②PID进程 ID管的是内存里跑的进程在哪内存、操作系统内核里作用标识一个正在运行的程序谁用ps、kill、fork、调度一句话PID 进程的身份证号内存 / 运行层面③ 最直观对比一秒分清你创建一个 test.txt → 系统给它分配 inode你运行一个 ./a.out → 系统给它分配 PID一个管硬盘文件一个管运行程序完全不搭边。