2026/5/21 21:09:44
网站建设
项目流程
免费自建网站,wordpress 百度站长,广东地区建网站的公司,ui需要学哪些内容本系列主要旨在帮助初学者学习和巩固Linux系统。也是笔者自己学习Linux的心得体会。 个人主页#xff1a; 爱装代码的小瓶子 文章系列#xff1a; Linux 2. C 文章目录 1.前言#xff1a;2 文件系统的概念#xff1a;2-1 引入“块”概念#xff0c;更好的理解文件爱装代码的小瓶子文章系列Linux2.C文章目录1.前言2 文件系统的概念2-1 引入“块”概念更好的理解文件2-2 引入“区”的概念2-3 引入“组”的概念3. ext2系统的正式介绍3-1 Data Blocks和Block Bitmap3-2 inode Table 和inode bitmap3-3 GDT和Super Block3-4 实验 总结4. 从磁盘到内存文件的生与死**4-1 诞生与静态存在磁盘上的“户籍”与“房产”****4-2 打开从磁盘加载到内存的“唤醒”仪式****4-3 读写数据的流动与缓冲****4-4 关闭与消亡资源的释放**4-5 总结与描述总结1.前言在我们之前的文章中主要讲的是内存中被打开的视角今天这篇文章我们着重讲述磁盘的文件系统为了便于对文件进行管理引入块的概念。引入分区的概念。引入inode的概念。我将一步一步带你讲解这些概念让你更好的理解磁盘上的文件。随后我们需要引入ext2的文件系统的概念。其实这里也是比较难的。但是也是我们理解Linux系统的基石。2 文件系统的概念在我们的磁盘上面有这么多的文件我们应该怎么管理呢接下来我们讲慢慢深入探讨Linux下的文件是如何被系统给管理的。2-1 引入“块”概念更好的理解文件其实硬盘就是一个块设备。操作系统在读取硬盘的时候是不会一个一个扇区来来读取的而是八个扇区完成读写的这八个扇区512B * 8 4096B 4KB即1 Block (4KB) 8 × Sectors (512B) 1 \text{ Block (4KB)} 8 \times \text{Sectors (512B)}1Block (4KB)8×Sectors (512B)如果说扇区是磁盘的“物理刻度”那么块就是文件系统的“逻辑容器”。无论你是电影还是音频还是txt文本在操作系统中一切都是以块为调度的。1.什么是CHS磁盘由柱面Cylinder、磁头Head、扇区Sector构成。CHS就是通过这三个坐标来定位一个具体的物理扇区2.什么是LBA为了解决上述问题我们将磁盘复杂的物理结构进行“拉直”。你可以想象把磁盘所有盘片上的所有磁道按柱面顺序首尾相连拼接成一根很长的“磁带”。这根“磁带”上的每一个扇区就获得了唯一的、连续的线性地址就像一维数组的下标。这个线性地址就是 LBA。从此在操作系统和用户看来磁盘就是一个“一维数组”数组下标是LBA每个元素是一个扇区。磁盘就是⼀个三维数组我们把它看待成为⼀个⼀维数组数组下标就是LBA每个元素都是扇区。在硬件物理视角是如何看待磁盘是一个三维数组我们一层一层的来看磁盘看作一个“一维数组”磁盘的物理结构是三维的柱面、磁头、扇区但操作系统和上层应用通过LBA将其抽象为连续的一维地址空间每个LBA对应一个唯一的扇区就像数组的下标扇区Sector- 传统机械硬盘和许多固态硬盘的基本读写单位通常为512字节或4KB高级格式化。- 一个扇区在逻辑上对应一个LBA。我们通过对CHS和LBA的相互转化就可以了相连的八个扇区就是一个块。2-2 引入“区”的概念这里我们先谈了分区的概念像我们的windows平台提供了不同的区比如:C盘和D盘但是实际上你的硬盘并没有被一分为二。这里区是为了更好的管理整个硬盘。分区的本质是设置每个区域的起始和结束柱面号。“柱面是分区的最小单位”。如果把一整块物理硬盘想象成一大块“原始土地”。那么分区就是在这块土地上用篱笆划出几块独立的、逻辑上的“大区域”。例如C区、D区、E区。分区之后每个区域就需要建立自己的“管理规则”即文件系统这个过程就是格式化。所以文档说“分区从实质上说就是对硬盘的一种格式化”但格式化后还不能直接使用需要挂载这里挂载后面再讲我们这里说一个分区就是一个完整的文件系统了。2-3 引入“组”的概念什么是分组分组是文件系统内部的管理单元是一个分区被文件系统格式化后内部进一步的细粒度划分。为什么这样划分一个区还是太大了为了便于管理每一个数据和组织起每一块区域。在前面我们不能详细的讲太多但是这里还是可以点一些东西出来便于管理将大分区的元数据如inode表、块位图分散存储避免寻找空闲块或inode时需要遍历整个庞大的分区提升效率。提高可靠性超级块 (Super Block) 在每个块组都有备份。如果一个块组的超级块损坏可以从其他块组的备份中恢复增强了文件系统的健壮性。支撑大容量这种结构能更好地支持和管理非常大的硬盘分区。这些我们后面都会讲出来。3. ext2系统的正式介绍我们借ext2正式来介绍文件系统时怎么管理我们先看图片这里我们就详细的画了一个硬盘是如何划分成为不同的区再通过不同的区划分成为不同的组一个组里面有什么大致分成什么部分。这里都是我们要讲清楚的Data Blocks :存放数据的区域。inode Table inode 表inode bitmapinode 的位图Block Bitmap: 数据块的位图。GDT :一个组信息。Super Block超级块备份思想接下来我们就详细说说这个六个吧3-1 Data Blocks和Block Bitmap其中Data Blocks用于存储实际文件数据、目录条目等。这是块组的最大部分。比如我们从网上下一个电影或者文章就是存放在这个位置。我们在之前的文章中我们经常说文件 文件内容 属性在普通的文件中这里存放的是就是文件里面的内容。我们文件里面的内容也是我们写的代码就是放在这里的对于目录创建的目录mkdir)在Data Blocks中存放的就是文件名和inode的映射现有个印象后面会讲那么这个Data Blocks 就清楚了那么这个相关的位图有什么用呢没错他就是用于看那个db里面那个区域存放了数据哪里没有存放这个巧妙的使用另一个01就控制了db里面的数据到底是存放还是没有存放。其中1表示已用0表示空闲。通常的大小是1块。题外话我们在删除文件或者电影或者某个程序就是讲这里的块位图置为0.下次再下载的时候直接进行覆写就可以了。我们后面还会讲到inode bitmap怎么变化。“由此可见Block Bitmap是文件系统管理存储空间的核心数据结构之一。它通过简单的0/1标记高效地记录了数百个数据块的空闲状态使得文件的创建分配块和删除释放块变得非常迅速。”3-2 inode Table 和inode bitmap我们刚刚说到了文件 文件内容 文件属性。文件内容我们已经知道在DB里面了但是属性呢你想到没错就是放在inode table 里面了。inode表是每个块组中一个连续的块序列用于存储文件系统的inodeIndex Node结构。那么inode是什么inode是ext2文件系统的核心元数据单元每个文件、目录、符号链接或设备文件都对应一个唯一的inodeinode号从1开始0保留。inode编号的唯一性是再一个分区里面的也就是只给1进程是不知道文件再哪里的。inode表是一个连续的磁盘块区域由组描述符中的bg_inode_table字段指向起始块号。表内按inode号顺序排列inode号1的结构体在表的最开头inode号2紧接着依此类推。偏移计算公式(inode_number - 1) * inode_sizeinode_size通常128字节。这里面的结构体到底记录什么吗偏移字段名称大小字节描述0-1i_mode2文件类型和权限2-3i_uid2低16位用户ID4-7i_size4文件大小低32位8-11i_atime4访问时间12-15i_ctime4创建时间16-19i_mtime4修改时间20-23i_dtime4删除时间0表示未删除24-25i_gid2低16位组ID26-27i_links_count2硬链接数28-31i_blocks4占用的512字节扇区数32-35i_flags4文件标志36-39i_osd14OS特定字段40-87i_block[15]48块指针数组12个直接 1间接 1双间接 1三间接88-91i_generation4文件版本NFS用92-95i_file_acl4文件ACL块号96-99i_size_high / i_dir_acl4大小高32位或目录ACL100-103i_faddr4碎片地址…其余填充/扩展字段…OSD2等视系统而定大致就这样这里已经很详细可以看一下。不是本文的重点。那么 inode bitmap是做什么的呢类似块位图用于标记块组内哪些inode已被分配。大小为1块。也是和上面一样的。所以真正的删除只要改变两个位图其实就好了这又是为什么删除比下载快多了的原因。3-3 GDT和Super Block先说GDT是什么他是每一个组都必备的。ext2把整个文件系统划分为多个块组Block Groups而GDT就是用来描述“每个块组长什么样、里面有哪些东西”的表格。位置GDT紧跟在超级块Superblock之后。块组0里有主拷贝其他某些块组如1、3、5、7的幂次方组里有备份拷贝用于损坏恢复。Super Block超级块就是一个区域的描述。超级块Superblock是ext2文件系统的“总控制台”或“全局配置文件”它存储了整个文件系统的核心元数据让内核一读就能知道这个分区是ext2、有多大、怎么划分等信息。由于它特别重要所以我们能看到他在很多分组中能看到这个超级块。当有一个被破坏了进程可以读取其它的来恢复超级块。简单说超级块告诉你文件系统整体有多大、有多少块组GDT则告诉你“第N个块组的位图和inode表在哪儿、还剩多少空间”。这张图形象地解释了“操作系统是如何知道磁盘哪里是空的哪里是满的”**。它没有去扫描每一个具体的硬盘扇区那样太慢了而是查看一张“地图”位图。如果地图上标记为 0系统就知道那里是个空车位可以直接停进去。3-4 实验 总结我们先来看看如何看待每个文件是怎么知道知道每一个文件的inode 呢?我们可以使用ls-a -li来查看该目录文件的inode我们说进程是不认识这些文件而是通过inode 来寻找。但是反直觉的是我们再寻找的时候一般都是通过find 加路径和名字来寻找的这里我们就要回顾我们之前在Data Blocks里面说的目录存储的是文件名 和inode 的对应关系。目录Directory本身也是一种特殊的文件。虽然文件的 Inode 里没有存文件名但是**目录的数据块Data Block**里存了一张“对照表”。当我们说lesson8是一个目录时你可以把它想象成一个“电话本”。这个电话本的内容Data Block长这样文件名 (Filename)Inode 编号 (索引节点号).(当前目录)415984..(上级目录)392468test.c415986main.c415990可以试着运行一下stat test.c命令。它会把 inode、权限、修改时间等信息一次性全部列出来这样我们就知道了进程是如何把这些文件转换成为了inode来搜索这个文件的位置了。读到这里我们已经知道了知道文件时怎么存放在磁盘上面的接下来我们讲讲什么文件时怎么到内存里面的open函数时怎么精确定位的。4. 从磁盘到内存文件的生与死我们已经剖析了文件在磁盘上的“静态家园”ext2结构。现在让我们跟随一个文件的旅程看它如何从冰冷的磁盘被唤醒进入活跃的内存为进程服务最终走向消亡。4-1 诞生与静态存在磁盘上的“户籍”与“房产”一个文件在磁盘上并非一个连续的整体而是被拆解为一份户籍inode存储在inode Table中。拥有唯一编号inode number记录了文件的元数据大小、权限、所有者、时间戳等以及最关键的信息——其数据块存放在哪些 Data Blocks 中通过直接、间接指针。多处房产Data Blocks实际存储文件内容的地方。由 inode 中的指针寻址。位图登记它的存在被记录在inode bitmap和block bitmap中状态为“已占用“。核心观点**此时文件是静止的。操作系统通过文件系统如ext2的这套“账簿”超级块、位图、inode表来管理它但文件本身并未参与任何运4-2 打开从磁盘加载到内存的“唤醒”仪式当进程执行open()系统调用时魔法开始了。这是磁盘与内存的第一次握手。路径解析内核根据文件路径从根目录/或当前目录开始逐级查找目录的 Data Blocks里面存着文件名-inode编号的映射最终找到目标文件的inode number加载元数据内核根据 inode number去对应的块组中读取文件的inode信息。在内存中创建一个struct inode的内核对象VFS层复制或映射磁盘 inode 的关键信息。这是该文件在内存中的核心代表。创建访问句柄内核为本次“打开”创建一个struct file对象。它包含了指向内存inode的指针。文件读写偏移量f_pos。访问模式读、写、追加等。操作函数集指针指向具体文件系统如ext2的读写函数。与进程关联在进程的文件描述符表File Descriptor Table中分配一个最小的空闲编号如3。将这个struct file对象的地址填入其中。open()系统调用将这个文件描述符fd例如3返回给用户程序。此时的状态文件的“魂”inode信息已被调入内存并准备好了“操作界面”struct file。但文件的实际数据内容还懒洋洋地躺在磁盘的 Data Blocks 里并未全部加载。4-3 读写数据的流动与缓冲当进程通过read(fd, buffer, size)或write(...)操作文件时数据开始流动。通过 fd 找到一切内核用 fd如3从进程的文件描述符表找到struct file再找到struct inode。页面缓存Page Cache—— 内存中的“数据驿站”这是Linux内核一个至关重要的机制。内核会在内存中开辟一片区域作为磁盘数据的缓存。第一次读内核根据 inode 中的指针从磁盘 Data Blocks 读取所需数据到页面缓存然后再复制到用户提供的buffer中。后续读如果数据已在页面缓存中则直接从内存提供速度极快。写操作数据通常先写入页面缓存并被标记为“脏页”。内核会在合适的时机或调用fsync()时再将“脏页”写回磁盘对应的 Data Blocks。修改回写写入操作可能会导致磁盘上文件的inode元数据变更如文件大小、修改时间这些变更也需要同步回磁盘的 inode Table。核心思想内存中的页面缓存解耦了进程快速的读写请求与相对缓慢的磁盘IO是文件系统性能的关键。4-4 关闭与消亡资源的释放关闭 (close(fd))进程调用close()内核释放对应的struct file对象。递减引用计数该文件的struct inode的引用计数减1。如果减到0没有进程再打开它内核可能会尝试释放内存中的 inode 对象。重要关闭文件并不立即刷新“脏页”到磁盘。数据可能还在页面缓存中等待内核线程写回。删除 (unlink()) - 真正的“死亡”unlink()系统调用操作的是目录的 Data Blocks它删除了文件名-inode编号这条映射记录。关键步骤将该文件 inode 的硬链接数减1。如果硬链接数变为0且没有进程打开此文件inode引用计数为0则文件系统开始真正的清理将其 inode 在inode bitmap中标记为空闲(0)。将其占用的数据块在block bitmap中标记为空闲(0)。注意如果文件正在被进程使用已打开即使执行unlink磁盘空间也不会立即释放会延迟到最后一个打开它的进程关闭文件后。这解释了为什么有时删除了一个大文件磁盘空间却没马上回来。4-5 总结与描述我们open的时候按理会从更目录一直读到目标位置为了不每次都读磁盘Linux 有一个dentry cache (目录项缓存)如果刚才访问过这些目录它会直接从内存缓存里拿到 Inode 号速度极快。找到 Inode 号之后系统把磁盘上的 Inode 信息权限、大小、Block位置拷贝一份到内存里。创建struct_inode。那么struct_task里面会有一个结构体指针files指向struct_file,里面有一个数组fd_array,里面012都已经存储了三个标准文件。我们刚刚打开的文件就会在4号。我们通过这个找到struc file。里面有他的inode指针指向struct inode。这里就描述了他在哪里。但是仅仅通过这个还是不行我们不知道他在哪个区域我们还需要挂载进程struct_task会一个指针打开struct_path,里面有两个变量他的地址我们通过地址就知道他是哪个区的。这样才能顺利完成读写。这上面还是有些错误我来重写修改:我们 open 的时候按理会从根目录(更目录) 一直读到目标位置。为了不每次都读磁盘Linux 有一个dentry cache (目录项缓存)。如果刚才访问过这些目录它会直接从内存缓存里拿到 Inode 号速度极快。找到 Inode 号之后系统把磁盘上的 Inode 信息权限、大小、Block位置拷贝一份到内存里创建struct inode。那么task_struct(struct_task) 里面会有一个结构体指针files指向struct files_struct(struct_file注意这是文件描述符表不是文件对象)里面有一个数组fd_array。里面 012 都已经存储了三个标准文件我们刚刚打开的文件通常就会在3 号(4号)。我们通过这个fd 索引找到struct file。关键点在这里里面有他的inode指针指向struct inodestruct file里面包含了一个struct path。进程struct_task会一个指针打开struct_path这个struct path里面有两个变量mnt指针(他的地址)我们通过它就知道他是哪个文件系统/哪个分区(哪个区的)dentry指针它指向struct inode这里描述了物理数据在哪里。总结这篇文章完整揭示了Linux文件系统以ext2为例的核心机制在磁盘上文件被拆解为存储属性的inode和存储内容的Data Blocks并通过位图高效管理空间当文件被打开时内核将其inode加载到内存并创建访问句柄进程通过文件描述符经由页面缓存进行快速读写而删除文件本质上只是清除位图中的占用标记因此速度极快这体现了文件系统通过精巧的元数据设计来桥接物理磁盘与逻辑访问的精髓。这篇文章稍微有点长有点难希望大家能有所收获感谢各位对本篇文章的支持。谢谢各位点个三连吧