Ext系列文件系统 [ 上 ]
我们本篇针对的文件相关话题不是内存了是更侧重外设磁盘找到文件位置以及和内存之间的联系我们之前说过文件 内容 属性这是我们从一个文件的视角去谈的而系统当中存在成百上千的文件在系统层面上文件也就被打开了一小部分操作是将那么多的文件是进行怎么样的管理呢更重要的是我们之前fopen()打开文件的时候为什么我们的系统就能够准确的把我们想要打开的文件打开并且可以在系统层面上将文件信息加载到内存怎么可以做到如此精准我们在理解文件是时单个文件是为内容 属性而在宏观角度上文件是被分成被打开的文件该话题在 基础 IO 当中已经说明清楚了。 ---内存中的文件未被打开的文件被打开的文件是在内存当中的因为操作系统要管理他如果文件没有被打开呢他在哪里呢答案是在磁盘上那么没有被打开的文件多多了我们又是如何将这么大量的文件归类保存到磁盘当中使我们能快速找到如果找不到那我们之前所说的打开一个文件就不能谈起因为我们默认打开这个文件就相当于该文件能够被找到。答案是文件是通过树状的目录结构组织在磁盘上的这种结构以根目录为起点逐层展开形成一个层次化的存储体系。我们可以通过路径来定位文件路径分为绝对路径和相对路径绝对路径是从根目录开始的完整路径而相对路径是从当前目录开始的路径。操作系统OS负责管理和组织文件它通过文件系统来记录文件的位置、属性以及目录结构确保文件能够被快速、准确地找到和访问。这种机制是操作系统的基本功能之一也是文件存储和管理的核心。所以找文件的工作是通过文件系统完成的我们先从硬件角度开始谈文件系统磁盘都不了解谈什么文件系统本章重点一个文件没有被打开在操作系统当中是如何组织的一. 理解硬件1.1 磁盘·服务器·机柜·机房磁盘传统的机械存储设备通过磁性介质存储数据。优点是容量大、成本低缺点是读写速度较慢。固态硬盘SSD基于闪存技术的存储设备读写速度快无机械部件抗震性强。适用于对性能要求较高的场景。现状现代笔记本电脑大多使用固态硬盘而磁盘在服务器领域仍占主流地位。企业级磁盘容量大、效率高、品质高用于服务器和数据中心。桌面级磁盘适用于个人电脑容量和性能适中。磁盘用途存储海量数据磁盘因其性价比高而被广泛用于存储海量数据。冷热数据分离企业级磁盘分为存储盘和效率盘根据数据的冷热程度选择不同的存储方案。机械结构盘片数据存储在盘片的磁性表面。马达驱动盘片高速旋转转速从7200转/分钟到20000转/分钟不等。磁头与摆臂磁头通过摆臂在盘片半径路径上移动进行数据的读写操作。类比说明磁盘的工作原理类似于VCD/DVD光盘但磁盘可以进行读写操作而光盘只能读取。服务器服务器通常没有鼠标、键盘和显示器主要通过网络进行交互。服务器内部可以插入多块磁盘用于存储数据。例如一台服务器可以插入24块4TB的磁盘总存储容量为96TB。机柜机柜用于存放多台服务器便于管理和散热。一个机柜可以容纳多台服务器通过网络连接实现数据交互。机房机房由多个机柜组成是数据中心的核心部分。机房内的服务器用于部署各种服务通过网络对外提供服务。存储方式冷热数据分离热数据频繁访问的数据存储在高性能的存储设备上如SSD。冷数据不常访问的数据存储在大容量、低成本的磁盘上。示例微信朋友圈的早期记录可能会被备份到低成本的存储设备上。存储设备磁盘和固态硬盘是计算机系统的重要组成部分尤其在服务器和数据中心中扮演关键角色。磁盘因其大容量和低成本被广泛用于存储海量数据而固态硬盘则在性能上有优势。服务器通过机柜和机房组成数据中心用于部署各种服务。企业级磁盘和存储方案的选择需要根据数据的冷热程度和性能需求进行优化。国内在存储技术上逐步推进国产化以满足信息安全需求。1.2 磁盘物理结构磁盘表面与存储单元磁盘表面看起来光滑但由许多微小的存储单元类似小磁铁构成。每个存储单元通过磁极南极和北极来表示二进制数据0和1。磁盘写入原理写入数据时磁头通过改变存储单元的磁极方向来存储二进制信息。磁盘的存储是永久性的除非主动删除或破坏磁盘。主轴马达主轴是硬盘内部的一个关键部件它通过马达驱动磁片旋转。主轴的转速通常以每分钟转数RPM来衡量如7200 RPM转速越高硬盘的读写速度通常越快。磁盘相当于纸磁盘是硬盘中用于存储数据的磁性材料层。数据通过改变磁盘上特定区域的磁性来记录类似于在纸上写字。磁头相当于笔磁头是负责读写磁盘上数据的部件。它通过改变磁盘上磁性区域的极性来写入数据或者通过检测磁性区域的极性来读取数据。磁头臂磁头臂是连接磁头和主轴的机械臂它负责将磁头移动到磁盘的正确位置以便进行数据的读写操作。永磁铁永磁铁用于辅助磁头臂的移动确保磁头能够准确地定位到磁盘的特定位置。这些部件共同工作使得硬盘能够存储和检索大量数据。硬盘的工作原理可以类比为一个记录系统其中磁盘相当于纸磁头相当于笔而主轴和磁头臂则确保“笔”能够在“纸”上正确地写入和读取信息。磁盘的耐用性与破坏方式磁盘在密封状态下具有很高的耐用性内部接近真空状态。如果需要彻底销毁磁盘数据可以通过高温加热使其退磁。1.3 磁盘的存储结构主轴Spindle硬盘中心的旋转轴盘片固定在主轴上通过主轴的旋转使盘片高速旋转。盘片Platter硬盘中用于存储数据的磁性材料数据以磁性形式存储在盘片表面。磁道Track盘片表面的同心圆每个同心圆是一个磁道用于存储数据。面Surface每个盘片有两个面即上表面和下表面都可以存储数据。扇区Sector磁道被分割成的扇形区域是硬盘存储数据的基本单位通常为512字节。其实硬盘通常包含多个盘片每个盘片都有两个存储面的即上表面和下表面都可以用于存储数据。在多盘片的硬盘中所有的盘片都堆叠在一起并且它们共享同一个主轴因此会同步旋转。柱面Cylinder所有盘片中位于同一半径的磁道组成的集合称为柱面。当磁头移动到某个柱面时所有盘片上对应的磁道都会被定位。磁头Head每个盘面对应一个磁头用于读取和写入数据。所有磁头都连在同一个磁臂上因此所有磁头只能“共进退”。磁头臂Actuator Arm连接磁头和主轴的机械臂负责将磁头移动到磁盘的正确位置。每个盘片的每个存储面都有一个对应的磁头用于读写该面上的数据。磁头安装在磁头臂上磁头臂可以沿半径方向移动以便磁头可以访问不同半径上的磁道。当磁头臂移动时所有磁头会同步移动到对应的磁道上因为它们都是连接在同一磁头臂上的。因此在多盘片硬盘中可以同时从多个盘片的不同磁道上读写数据这增加了数据访问的效率。每个盘片的所有磁道组成一个柱面当磁头移动到某个柱面时所有盘片上相同半径位置的磁道都会被定位允许并行读写多个盘片上的数据。数据存储单位扇区Sector硬盘存储数据的基本单位通常为512字节。操作系统在读写硬盘时必须以扇区为单位进行操作。并不是1比特不然IO效率得多慢呀数据定位方式柱面Cylinder所有盘片中位于同一半径的磁道组成的集合称为柱面。当磁头移动到某个柱面时所有盘片上对应的磁道都会被定位。磁头Head每个盘面对应一个磁头用于读取和写入数据。所有磁头都连在同一个磁臂上因此所有磁头只能“共进退”。扇区Sector磁道被分割成的扇形区域是硬盘存储数据的基本单位。数据读写操作磁盘定位硬盘通过磁头臂的移动来定位到特定的柱面然后通过磁盘的旋转来定位到特定的扇区从而实现数据的读写。读写操作在写入数据时数据会被写入到一个或多个扇区中。硬盘通过记录每个扇区的柱面、磁头和扇区号CHS地址来定位文件。企业级硬盘与桌面级硬盘主要区别在于寻址速度和精度。企业级硬盘通常具有更快的转速和更精确的磁头定位能力因此性能更高。硬盘的物理结构和数据存储方式是通过一系列的机械部件如磁盘、磁头、磁头臂等和逻辑结构如磁道、扇区、柱面等共同实现的。硬盘的读写操作基于扇区进行而文件的存储则是通过记录文件所占用的扇区的CHS地址来实现的。硬盘的性能受到其机械结构和电子控制的影响企业级硬盘通常具有更高的性能和可靠性。可以使用fdisk命令查看硬盘的分区信息包括扇区大小、磁盘类型等磁盘容量计算磁盘容量 磁头数 × 磁道柱面数 × 每道扇区数 × 每扇区字节数。文件系统通过记录文件所占用的扇区的CHS地址来实现文件的存储和管理。但是CHS寻址还是有不足寻址限制CHS寻址方式支持的硬盘容量有限。由于系统用8 位存储磁头地址用10 位存储柱面地址用6 位存储扇区地址一个扇区为512字节因此使用CHS寻址一块硬盘最大容量为\(256 × 1024 × 63 × 512\)字节 8064 MB约8.4 GB。CHS寻址方式是硬盘数据定位的一种传统方法通过柱面、磁头和扇区的组合来定位数据。然而由于寻址位数的限制CHS寻址方式支持的硬盘容量有限最大约为8.4 GB。现代硬盘通常采用更先进的寻址方式如LBA逻辑块寻址以支持更大的存储容量。但是计算机不是我们想的直接用磁盘直接拿着CHS这三个参数直接进行地址的访问所以我们接下来对磁盘做逻辑抽象。硬件 - 系统的过渡1.4 磁盘的逻辑结构1.4.1 理解过程磁带上⾯可以存储数据我们可以把磁带“拉直”形成线性结构。说明了磁盘的逻辑存储结构可以类比为卷在一起的磁带其中每个存储单元扇区可以看作是磁带上的一个线性块那么磁盘本质上虽然是硬质的但是逻辑上我们可以把磁盘想象成为卷在⼀起的磁带那么磁盘的逻辑存储结构我们也可以类似于这就是先描述再组织对磁盘的管理转化成了对数组的增删查改但是因为由于磁盘的物理结构磁盘在本质上进行定位的时候依旧是在自己内部使用CHS但是我们可以抽象成线性的这样每⼀个扇区基本单元就有了⼀个线性地址(其实就是数组下标定位一个扇区只是数组下标)这种地址叫做LBALBA 是硬盘对外提供的逻辑地址它将硬盘的所有扇区最小存储单元从 0 开始连续编号形成一个线性的 “扇区数组”。每个 LBA 值对应一个唯一的扇区就像数组下标对应数组中的一个元素。LBA 就像硬盘扇区的 “数组下标”通过连续的数字编号屏蔽了底层物理结构的复杂性让操作系统可以像访问数组一样高效、统一地管理硬盘存储。这种设计是现代硬盘寻址的主流方式。当代我们的磁盘不再直面上让操作系统直接使用CHS寻址了清一色全是LBA磁盘认识LBA那么磁盘会拿着LBA地址在内部转化成CHS然后帮我们自动寻址我们现在虽然还不知道LBA和CHS是怎么互相转化的我们后面会讲但是我们心里要知道从今天开始磁盘在我看来就是一个黑盒我给他喂了一个LBA地址他就要给我在磁盘特定的扇区里读写数据了。那有那么多扇区操作系统是不是要将所有的扇区对应的LBA地址记录下来呢其实是没有必要的但是操作系统依旧可以使用任意一个LBA因为扇区大小是固定的换句话说其实我作为操作系统我在开机的时候只要能够识别出来这块磁盘的总容量每一个扇区的地址我便都有了。得到了地址范围我们下面来谈谈真实的过程。1.4.2 真实过程⼀个细节传动臂上的磁头是共进退的。柱⾯是⼀个逻辑上的概念其实就是每⼀⾯上相同半径的磁道逻辑上构成柱⾯。所以磁盘物理上分了很多⾯但是在我们看来逻辑上磁盘整体是由“柱⾯”卷起来的所以磁盘的真实情况是磁道是由某一盘面的某一磁道展开也就是一维数组柱面整个磁盘所有盘面的同一磁道即柱面展开柱⾯上的每个磁道扇区个数是⼀样的这不就是⼆维数组吗整盘整个磁盘不就是多张二维的扇区数组表 (三维数组)所有寻址一个扇区先找到哪一个柱面 (Cylinder)再确定柱面内哪一个磁道 (其实就是磁头位置Head)再确定扇区Sector所以就有了CHS。我们之前学过C/C的数组在我们看来其实全部都是一维数组所以每一个扇区都有一个下标我们叫做LBA(Logical Block Address) 地址其实就是线性地址。所以怎么计算得到这个LBA地址呢OS 只需要使用 LBA 就可以了LBA地址转成CHS地址CHS如何转换成为LBA地址。谁做啊磁盘自己来做固件 (硬件电路伺候服务系统)1.5 CHS LBA 地址CHS 转成 LBA:磁头数*每磁道扇区数 单个柱面的扇区总数LBA 柱面号C单个柱面的扇区总数 磁头号H每磁道扇区数 扇区号S - 1即LBA 柱面号C*(磁头数每磁道扇区数) 磁头号H每磁道扇区数 扇区号S - 1扇区号通常是从1开始的而在LBA中地址是从0开始的柱面和磁道都是从0开始编号的总柱面磁道个数扇区总数等信息在磁盘内部会自动维护上层开机的时候会获取到这些参数。LBA 转成 CHS:柱面号C LBA // (磁头数*每磁道扇区数)【就是单个柱面的扇区总数】磁头号H (LBA % (磁头数*每磁道扇区数)) // 每磁道扇区数扇区号S (LBA % 每磁道扇区数) 1//: 表示除取整所以从此往后在磁盘使用者看来根本就不关心CHS地址而是直接使用LBA地址磁盘内部自己转换。所以从现在开始磁盘就是一个元素为扇区的一维数组数组的下标就是每一个扇区的LBA地址。OS使用磁盘就可以用一个数字访问磁盘扇区了。硬件解释清楚了接下来就跟硬件没有关系了我们该慢慢进入软件也就是操作系统该如何管理磁盘了。二. 引入文件系统2.1 引入“块” 概念其实硬盘是典型的 “块” 设备操作系统读取硬盘数据的时候其实是不会一个个扇区地读取这样效率太低而是一次性连续读取多个扇区即一次性读取一个块block。块Block是操作系统为了提高读写效率在逻辑层面定义的最小数据传输单位例如Linux中常见的4KB、8KB等。它是对底层扇区的 “打包”—— 一个块通常由连续的多个扇区组成例如若扇区是512字节4KB的块就包含8个连续扇区。块的大小由操作系统和文件系统决定如ext4、NTFS等目的是减少磁盘I/O次数一次读一个块比多次读单个扇区效率高得多。与块设备相对应的是字符设备比如说键盘显示器就是典型的字符设备字符设备和块设备最重要的区别是字符设备不支持随机读取就像我们在键盘输入abcd怎么输入的顺序一样在程序当中就是怎么读的而且读取时是以字符为单位进行一一读取的。所以文件系统访问磁盘不以扇区为单位而是以 “块” 为单位。硬盘的每个分区是被划分为一个个的 “块”。一个“块”的大小是由格式化的时候确定的并且不可以更改最常见的是4KB即连续八个扇区组成一个”块”。”块” 是文件存取的最小单位。物理层面磁盘的物理结构决定了数据的存储是以扇区为单位的磁盘驱动器在硬件层面只能以扇区为单位进行读写。逻辑层面操作系统为了提高数据管理效率和读写性能引入了块的概念。块是操作系统与磁盘交互的最小单位。也是处于软件和硬件解耦的考量如果你让OS直接用磁盘的扇区的话万一磁盘技术发生更新的话那么OS你也会更改磁盘就是一个三维数组我们把它看待成为一个 一维数组数组下标就是LBA每个元素都是扇区每个扇区都有LBA那么 8 个扇区一个块每一个块的地址我们也能算出来。知道LBA块号 LBA/8知道块号LBA 块号 * 8 n. (n是块内第几个扇区)2.2 引入“分区” 概念想象一下如果让你管理一片800GB的数据国土你会怎么做直接管理每一个小小的存储单元就像试图用中央政府去管理每一寸土地一样成本和难度都高得吓人但聪明的人类早就找到了解决办法 ——分区。就像把广袤的国土划分为不同的省份我们把800GB的磁盘划分为几个区域比如300GB、300GB和200GB这样管理一个分区的方法就可以复制到其他分区大大降低了工作量。但这还不够我们还可以进一步把每个分区划分为更小的 “城市” —— 也就是分组。比如把300GB的分区再分成10个30GB的小块只要管理好一个30GB的小块其他的小块也可以用同样的方法搞定我们接下来就是重点在于分区分组后的其中一组的内容我们还要注意因为文件 内容 属性在Linux下内容和属性是分开存储的在我们所有的分组当中基本单位是块哦是4KB我们文件的内容是在分组后的成员Data Blocks当中。假设文件内容大小为17KB那么就占其5个块。这个是很重要的说一个题外话现在我们还在谈文件系统后面将文件系统通信这样的话题谈完我们到后面多线程的时候我们到时候会谈磁盘和内存之间是如何进行交互的也就是内存管理的基本模式是什么到那时候我们会知道其实内存管理也是以4KB为单位的也就是说我们磁盘上面的数据块天然的就是为了随时载入内存而做准备的属性就是在inode Table当中了我们接下来就要引入其相关概念了。这种 “分而治之” 的思想不仅让管理变得简单还让整个磁盘的管理变得高效。在Windows系统里正常来说只有一块磁盘磁盘进行分区这些分区被显示为C盘、D盘、E盘等分区从实质上说就是对硬盘的一种格式化。但是Linux的设备都是以文件形式存在那是怎么分区的呢柱面是分区的最小单位我们可以利用参考柱面号码的方式来进行分区其本质就是设置每个区的起始柱面和结束柱面号码。此时我们可以将硬盘上的柱面分区进行平铺将其想象成一个大的平面如下图所示柱面大小一致扇区个数一致那么其实只要知道每个分区的起始和结束柱面号知道每一个柱面多少个扇区那么该分区多大其实和解析LBA是多少也就清楚了。2.3 引入“inode” 概念在深入了解Linux文件系统之前我们先来探讨一个核心概念 ——inode。inode索引节点是理解Unix/Linux文件系统和硬盘存储的基础。inode是文件系统中用于存储文件元数据的数据结构它并不存储文件的实际数据内容而是记录与文件相关的各种信息。每个文件和目录在文件系统中都有一个唯一的inode与之关联。之前我们说过文件 数据 属性我们使用ls -l的时候看到的除了看到文件名还能看到文件元数据属性[rootlocalhost 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.cls -l读取存储在磁盘上的文件信息然后显示出来。其实这个信息除了通过这种方式来读取还有一个stat命令能够看到更多信息[rootlocalhost linux]# stat test.c File: test.c Size: 654 Blocks: 8 IO Block: 4096 普通⽂件 Device: 802h/2050d Inode: 263715 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-09-13 14:56:57.059012947 0800 Modify: 2017-09-13 14:56:40.067012944 0800 Change: 2017-09-13 14:56:40.069012948 0800到这我们要思考一个问题文件数据都储存在 ” 块”中那么很显然我们还必须找到一个地方储存文件的元信息属性信息比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode中文译名为”索引节点”。inode结构体定义在Linux内核源码的include/linux/fs.h文件中以下是Linux中inode结构体的主要内容以简洁的代码形式展示并附上简要注释struct inode { umode_t i_mode; // 文件类型和权限 kuid_t i_uid; // 文件所有者的用户ID kgid_t i_gid; // 文件所有者的组ID loff_t i_size; // 文件大小以字节为单位 struct timespec64 i_atime; // 文件最后访问时间 struct timespec64 i_mtime; // 文件最后修改时间 struct timespec64 i_ctime; // inode最后更改时间 unsigned int i_nlink; // 硬链接计数 dev_t i_rdev; // 设备文件的主次设备号 unsigned long i_ino; // inode编号文件系统中唯一标识 const struct inode_operations *i_op; // inode操作函数表 struct super_block *i_sb; // 所属超级块 struct address_space *i_mapping; // 文件数据的地址空间映射 };我们不同文件都要有属性的只是属性的内容不同由于每一个 struct inode 的大小固定为128字节所以文件的属性大小是一样的。inode中存储的信息包括文件类型普通文件、目录、链接等文件大小以字节为单位文件所有者的用户IDUID和组IDGID文件的读、写、执行权限时间戳包括文件的创建时间ctime、最后修改时间mtime和最后访问时间atime链接数记录有多少个文件名指向这个inode数据块指针指向存储文件实际内容的磁盘数据块当中一些链接我们会在软硬链接讲到。在 Linux 文件系统中文件名和 inode 是分离的也就是说文件名不会作为属性保存在文件的inode中。也是保证了文件的属性大小是一样的因为文件名字符数组大小不定当然还有其他考量我们接下来会说。