【Linux】磁盘 | 文件系统 | inode

🪐🪐🪐欢迎来到程序员餐厅💫💫💫

          主厨:邪王真眼

主厨的主页:Chef‘s blog  

所属专栏:青果大战linux

总有光环在陨落,总有新星在闪烁


模电好难啊,不知不觉怎么就要期末考试了,还有六级考试,哦哭了


前言 

我们之前讲的文件都是被打开的文件,或者说被加载到内存中的文件,但事实上计算机中没有被打开的文件比被打开的文件数量多得多,操作系统是如何管理这些没被打开的文件的呢?显然不会是一股脑往硬盘里一塞就啥也不管了, 今天我们就来好好介绍一下。


磁盘

在了解硬盘中的文件之前,我们要先来了解一下磁盘

计算机中存储数据有两种方式,,一种是存放在内存中,一种是存放在硬盘中,我们常说的电脑是512+16,手机是256+12,这里的大数字“256”、“512”就是硬盘的空间大小(单位G),小数字就是内存的空间大小(单位G)。

内存的特点叫做掉电即丢失,也就是说当你的电脑没电了那你内存中存储的数据会直接清空,要想保存数据就要一直开着电脑,这显然是不可能的,这时就要让硬盘发挥作用了,硬盘的不仅空间比内存大得多,而且他的数据存储是掉电不丢失的,除此之外价格也便宜很多。

硬盘分为机械磁盘和SSD(固态硬盘)

上图中,左侧是磁盘,右侧是SSD。

  1.  机械磁盘是我们的计算机中唯一一个机械设备,IO交互慢

  2. 固态硬盘IO效率、功耗、噪音大小上明显比机械磁盘更好,

事实上我们现在的PC上大多都是固态硬盘,那么为什么我们还要讲磁盘,而不是SSD呢?

首先虽然性能上有明显差异,但是SSD和磁盘的文件系统大框架是一样的,只是SSD多了些优化。

其次,对于企业来说他们要在服务器上安装硬盘,单块硬盘就是几个TB,并且一台机器可以安装几十块,这些硬盘主要是起到存储数据的作用,对他的IO交互速度、噪音什么的没什么要求,为了最大可能的节约成本,当然就要用机械磁盘了。


磁盘的物理结构

一个磁盘是由多个盘面组成的,我们先单拿出一个盘面讲解

在上图中我们可以看到很多圆环,每条圆环都是一条磁道,在工作时,中心的马达会带动磁盘高速旋转(一分钟几千转),磁头可以在磁头臂的帮助下移动到不同的磁道,这样一来磁头就可以读取任何一张盘面的任何地方了,当然磁头不是贴着盘面的,不然会刮坏盘面,而是以极近的距离挨着它。

机械磁盘是通过磁头在高速旋转的盘片表面进行数据的读写操作。盘片表面涂有磁性材料,磁头可以改变盘片上磁性材料的磁极方向来写入数据。例如,当磁头通过电流产生磁场时,就可以在盘片的磁性涂层上产生对应的磁极排列,这些不同的磁极排列就代表了 0 和 1 这样的二进制数据(例如规定N极为1,S为0)。而在读取数据时,磁头会检测盘片上磁性材料的磁极方向,从而将其转换为计算机能够识别的电信号。

磁盘是由多个盘面组成的,每个盘面都有一个磁头,用于写该面的数据,注意每个盘面正反都可以读写,也都各有一个磁头。

我们将不同盘面的相同大小的磁道看作一起,就可以当作一个柱面。


数据的存储

每个圆环都是一个磁道,而每个磁道又被分为了许多扇区,

扇区是磁盘IO的最小单位,一般固定是512字节

当然请注意,越是远离圆心,一个扇区所占面积就越大,为了使得扇区的数据空间都是512,所以外围的磁密度也会减小。

CHS寻址

  1. 第一步确定在哪个Cylinder(柱面),
  2. 第二步确定是哪个磁道,要用哪个Header(磁头)
  3. 第三步确定在哪个Sector(扇区)

数据的逻辑结构 

相信不少朋友小时候都玩过这个东西,揪着一边然后把它整个磁带全部撤出来,最后自然是按不回去了,不难看出磁带里面也是一圈一圈缠绕的,被扯出来后则是一根直线

事实上,这不就是二维数据转化为一维数组吗,我们的磁盘也是同样,于是乎在逻辑结构上我们可以把它从一个CHS三维的数组,转化为一个一维数组,

注意CHS中计算数量,扇区号是从下标1开始算的,磁道号和柱面号是下标0开始

在这个逻辑结构基础上,先人又发明了LAB寻址,

LAB下标=柱面号*单个柱面的扇区数+磁道号*单个磁道的扇区数+扇区号-1(最后减一是因为LAB下标从0开始算)

但是一个扇区的大小只有512字节,这个单位太小了,经过大量时间后人们发现当OS与磁盘单次OI以1kb、2kb、4kb、8kb为单位时效率高,其中又以4kb最为常用,于是我们接下来都是对4kb为单位的OS进行讨论。

我们把八个扇区看作一个数据块,这个块就是4字节,即OS与磁盘IO的单位 


文件系统

inode

属性会以结构体类型struct_inode的方式被构建出来,一个文件只有一个inode,他是文件属性的集合。

一个inode一般为128字节(某些OS下是256),他的主要内容如下

struct inode {
	unsigned long		i_ino;
	umode_t			i_mode;
	uid_t			i_uid;
	gid_t			i_gid;
	loff_t			i_size;
};
  1. i_ino:该inode结构体的编号

  2. i_mode:该文件的权限和类型(文件还是普通文件或其他的类型)

  3. uid:文件拥有者

  4. i_gid:文件拥有组

  5. i_size:文件大小 

使用指令 ls -i即可查看文件的inode编号

请注意,在linux中文件名属性没有在inode中保存, 


 分区&分组管理 

我们的PC一般是1T或者512G,而服务器可达几十TB,如此巨大的空间会存储大量的数据,那么如何对这么多数据进行管理呢?思路很简单,分治,分而治之。

这里的分区对应的就是我们windows里的分盘,C盘、D盘、E盘,不同的盘可以是不同的文件系统,这样可以防止出现一个文件系统挂了,文件全部出问题的情况

此时我们要做的就是如何管理好一个组的问题了,只要一个组管理好了,其他组就借鉴他的管理方法就可以了。


Group内容

我们先看看一个组里都有什么

 inode Table 

用于存储该组中的文件的inode,

Data blocks

以块为单位保存该组中的文件的内容,一份文件所占用块数是“文件大小/4kb”(向上取整)。

加入一个文件只有一个字节,就是是1/4k(向上取整),要给他分配一个数据块。

如果是大小为6kb,那就是6/4(向上取整),要分配两个数据块。

inode Bitmap&Block Bitmap

我们把inode Table中的空间以一个inode的大小(128字节)分为一份一份的,如何确定某一份空间有没有被使用呢,如何确定Data Block中的一个块(4字节)有没有被使用,靠的就是他们俩Bitmap。

这是两个位图,对于inode Bitmap第i个比特位为0表示第i份空间还没被使用,第i个比特位为1,表示第i份空间被使用了,Block Bitmap的第i个比特位负责表示第i个数据块是否被用了

当然了,虽然我们这里用的是位图,但是我们之前说了磁盘数据的IO要以块为单位,所以哪怕你只修改bitmap中的一个比特位,也要把一个块大小的Bitmap都读进去。

OS在给inode分配空间时,不是一定是连续的,加入第一份空间被使用了,第二份还没有,那么下次存储inode不一定会用第二份,而可能是第三、第五、第一千份空间。


Group Descriptor Table

简称GDT,块组描述符,用于描述块组属性信息

  • 该块组内的可用数据块数量。。
  • 该块组内的可用inode数量。
  • 该块组的块位图和inode位图的位置
  • 该块组的inode表的位置。

Boot block通常包含了启动计算机或其他设备所需的初始指令和数据,这些指令和数据是设备启动过程中最先被加载和执行的部分。我们现在先不考虑他。

Super Block(超级块)

存放文件系统本身的结构信息,是文件系统的核心。
Super Block的信息被破坏,可以说整个文件系统结构就被破坏了
记录的信息主要有:
  • bolck 和 inode的总量,
  • 未使用的block和inode的数量
  • 一个block和inode的大小
  • 最近一次挂载的时间,
  • 最近一次写入数据的时间
  • 最近一次检验磁盘的时间等其他文件系统的相关信息。
  • 还有一些用于管理文件的函数

从功能上来讲,一个分区有一个Super Block就够了,那为什么实际是每隔几个Group就要设立一个Super Block呢?

因为一旦一个Super Block崩溃了,那么他管理的数据都要gg,所以我们不能把鸡蛋都放在一个篮子里。因此每隔几个group就设立一个super Block,正常情况下就一个Super Block负责管理该区,当他出了问题,OS就会把好的SuperBlock复制过去以修复问题,大大提高了文件系统的稳定性。请注意一个区中的不同位置的Super block的数据是完全一样的,

文件系统以分区为单位,不同的分区可以安装不同的文件系统

inode编号是以分区为单位分配的,而不是以组为单位,

即C盘中可能有个inode编号是100,D盘也有个inode编号100,但是不可能在C盘的两个inode编号都是100

每个组的inode在分配编号时只需要确定该组的起始inode编号即可(保存在GDT中),他的编号就等于该组的起始inode编号+i(在该组用的第i份空间),例如她所在组的起始inode编号是1000,它用的是第25份空间,那他的编号就是1025,Datablock也是同理。


inode对Data block的映射

在inode中还有一个元素

__le32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */

i_block就是一个int类型的数组,他的容量是EXT2_N_BLOCKS,这个宏是15,这个数组的前12个空间存放的就是数据块的编号,显然靠这12编号最多只能存放48个字节的数据

一级间接块索引表指针存储的数据块编号所对应的数据块不是直接存储文件数据的,而是在这个块中存储其他块的编号,一个编号是int类型占四个字节,一个块是4KB可以存1000个块号,通过这1000个块可以存储的数据时4MB

同理 一级间接块索引表指针指向的数据块存的是1000个一级间接块索引表指针,相当于可以存4GB。

三级间接块索引表指针指向的数据块存的是1000个二级间接块索引表指针,相当于可以存4TB。

加入我们没有这些间接索引,那单单12个块很容易就会不够,可如果你开太大比如1200甚至120000个块,那inode本身空间就太大了消耗了很多空间。

如此一来就在保证inode本身所占空间不太大且固定的基础上,基本可以满足各种大小的文件的存储,

或许有同学会问,为什么不直接放个int类型指针,需要几个块就malloc几个int空间来存放

因为mallco分配的是内存空间,我们这里讨论的都是磁盘空间!!

只能说,优雅,太优雅了(间谍过家家音)。


inode编号与文件名的映射

显然我们在通过指令或者代码中的函数操作文件时,使用的都是文件名,那么文件名和inode又有何关系呢?

首先明确,文件名没有存放在inode中。

如何理解目录?

事实上,目录本身也是个文件,

所以它也有自己的inode和data block,我们可以看出在底层磁盘,是不区分所谓的文件类型的,大家都是一个inode+几个block,

目录的内容是什么?

是文件名和inode编号的映射关系 ,当然这个映射是相互的,inode编号也可以映射文件名,这也是为什么一个目录下不会有同名文件。

所以我们我们要在磁盘中找到一个文件,只需要通过他的上级目录和它自己的文件名就可以得到他的inode编号,接着通过编号找到这个inode结构体,结构体里面有对应的数据块编号,如此就得到了文件的数据,即可加载到内存中。

这里我们就知道了,一个文件的文件名是存储在他的上级目录中的。这就是为什么当你没有读权限时无法看到目录中的内容,因为读不了目录文件,所以就无法获得inode与文件名的关系,所以你就访问不了目录里面的东西;没有写权限就是无法将inode与文件名的映射写到目录中

为什么不把文件名放到inode?

编号可以进行加减以实现一些优化,编号的大小比较速度也优于字符串,因此为了提高效率就只用inode了,那么没有用武之地的文件名就没有在inode的存放的必要了。事实上用户id,组id等信息也是以整型的形式存放的,而不是直接存储我们的字符串形式的用户名。而文件名即字符串这种东西是为了方便我们用户的观看和使用才被使用的。可以看出OS为了提高效率真的是煞费苦心。

但是你先别高兴,要从磁盘找到我们的文件,要先找到上级目录拿着它的inode映射去在磁盘找,可是,要找到上级目录得先找到上上级目录啊,诶死循环了。

当然不是啦,根目录是特殊处理的,他的inode和文件名是固定的,所以找到根目录不用再依靠别的文件。这就是为什么我们访问一个文件需要相对路径或者绝对路径,因为要打开一个文件,就要从自身开始层层递归到根目录才可以。


路径缓存struct dentry

他是一个存放于内存的结构

我们现在知道了要找到一个文件,就要从他的根目录开始把他的路径中的文件夹都打开(从磁盘加载到内存),才可以最终获得该文件的inode,进而在磁盘中找到它,但是这样就意味着我们为了找到inode要不断和磁盘做IO去打开文件,效率不忍直视,于是佬们发明了dentry

首先dentry是一种树状结构,它里面有父子节点的指针以便于构造树状结构,它里面存放了一个文件的文件名(字符串)和她对应的inode

他所构建的结构就像linux的tree命令一样

 

最开始这个数据结构就会默认把根节点设置为根目录,之后加入我们要把project1打开,就会打开根目录->home->用户->projcet,此时就会对于每个文件都会创建新的dentry把该文件的文件名和inode的映射关系存放进去,并且把这些节点按照上面的树状结构链接起来,如此一来下次我们再要打开project2,就可以在内存中通过dentry直接获取用户A文件的inode,不用从根目录开始层层推导,新的文件也会带来新的dentry,继续链接到该树状结构上。当然一些dentry路径要是一直不被用就会被OS去掉,以节省空间。

这样我们就把找inode的操作只依靠内存实现了,效率比磁盘高了太多。

至于为什么不直接预加载所有路径,因为占用的空间太大了,等你的内存什么时候扩展到512了再说吧。


文件增删查改

在学习了这些东西后,我们回头在看文件的增删查改。

查找一个文件

如果是对于相对路径,先拼接成成绝对路径,

先去dentry里看有没有对应的缓存,如果有直接拿到inode,如果没有就层层展开,从根目录开始映射文件名和inode编号,最后拿到目标文件的inode

让inode编号和每个组Group的GDT中记录的inode起始编号比较,直到找到该文件所在Group,然后在inode Bitmap中检查该inode编号是否合法(即bitmap的该比特位为1),合法后去inode Table找到inode结构体,通过结构体中的i_block找到文件的数据块,至此,文件的内容(数据块)和属性(inode)就算都找到了。

创建一个文件

OS在inode Bitmap中确定第i个比特位,它对应的值为0,表示inode Table对应位置的inode还未被使用。

使用包括inode编号i在内的信息创建一个inode结构体,把它放到inode table第i份(以128字节为单位)空间,接着计算他的大小需要占用几个数据块(向上取整),通过Block Bitmap给他在Data balock分配n个数据块空间存储内容数据,并将数据块的编号存放在inode的i_block数组中。

如何删除一个文件

先查找到文件的inode编号,接着找到inode结构体获取数据块编号,最后把对应的inode Bitmap的比特位和Block Bitmap比特位都置零即可。

这意味着当你删掉了它后,他的数据还在Data Block中保存,也有被恢复的可能,不过你要是接着又建立了一些文件,占用了原本文件的Data Block就真的恢复不了了。

修改一个文件

先通过查找找到该文件,然后把文件加载到内存,对其内容修改,最后将修改后的数据刷新回磁盘中的文件即可。

-------------------------------写了很久,创作不易,麻烦点赞关注支持一下--------------------------------------

​​​​​​​ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924720.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PHP 去掉特殊不可见字符 “\u200e“

描述 最近在排查网站业务时,发现有数据匹配失败的情况 肉眼上完全看不出问题所在 当把字符串 【M24308/23-14F‎】复制出来发现 末尾有个不可见的字符 使用删除键或左右移动时才会发现 最后测试通过 var_dump 打印 发现这个"空字符"占了三个长度 &#xf…

【C#设计模式(15)——命令模式(Command Pattern)】

前言 命令模式的关键通过将请求封装成一个对象,使命令的发送者和接收者解耦。这种方式能更方便地添加新的命令,如执行命令的排队、延迟、撤销和重做等操作。 代码 #region 基础的命令模式 //命令(抽象类) public abstract class …

使用zabbix监控k8s

一、 参考文献 小阿轩yx-案例:Zabbix监控kubernetes云原生环境 手把手教你实现zabbix对Kubernetes的监控 二、部署经验 关于zabbix监控k8s,总体来说是分为两块内容,一是在k8s集群部署zabbix-agent和zabbix- proxy。二是在zabbix进行配置。…

ThingsBoard规则链节点:GCP Pub/Sub 节点详解

目录 引言 1. GCP Pub/Sub 节点简介 2. 节点配置 2.1 基本配置示例 3. 使用场景 3.1 数据传输 3.2 数据分析 3.3 事件通知 3.4 任务调度 4. 实际项目中的应用 4.1 项目背景 4.2 项目需求 4.3 实现步骤 5. 总结 引言 ThingsBoard 是一个开源的物联网平台&#xff0…

10.机器学习--集成学习

机器学习领域有一个强大的思路:集成学习,该方法在诸多机器学习竞赛中往往能够获得最优的结果。集成学习的基本思想实际上非常简单:三个臭皮匠顶一个诸葛亮,即将多个模型组合在一起获得的效果往往要强于单一模型。 目录 集成学习…

结构体详解+代码展示

系列文章目录 🎈 🎈 我的CSDN主页:OTWOL的主页,欢迎!!!👋🏼👋🏼 🎉🎉我的C语言初阶合集:C语言初阶合集,希望能…

深度解析猎板 PCB树脂塞孔工艺

PCB 的树脂塞孔工艺是一种在印制电路板制造过程中广泛应用的重要技术,以下是猎板PCB批量工厂对PCB树脂塞孔该工艺的详细介绍: 猎板 PCB树脂塞孔工艺目的 防止短路:在 PCB 制造中,若过孔未被有效封堵,锡膏可能会从孔内…

扫雷-完整源码(C语言实现)

云边有个稻草人-CSDN博客 在学完C语言函数之后,我们就有能力去实现简易版扫雷游戏了(成就感满满),下面是扫雷游戏的源码,快试一试效果如何吧! 在test.c里面进行扫雷游戏的测试,game.h和game.c…

当前就业形势下C++方向后端开发学习指南

文章目录 1. C后端开发的职业方向1.1 C的应用领域1.2 后端开发的职业选择 2. 当前就业形势分析2.1 C开发者的市场需求2.2 C开发者的薪资水平 3. 学习路线3.1 入门阶段:掌握基础知识3.2 进阶阶段:掌握后端开发的核心技术3.2.1 数据库与C3.2.2 网络编程 3.…

FFmpeg 简介与编译

1. ffmpeg 简介: FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移…

【论文复现】BERT论文解读及情感分类实战

📝个人主页🌹:Eternity._ 🌹🌹期待您的关注 🌹🌹 ❀ BERT论文解读及情感分类实战 简介BERT文章主要贡献BERT模型架构技术细节任务1 Masked LM(MLM)任务2 Next Sentence P…

Flink高可用配置(HA)

从Flink架构中我们可以看到,JobManager这个组件非常重要,是中心协调器,负责任务调度和资源管理。默认情况下,每个Flink集群只有一个JobManager实例。这会产生单点故障(SPOF):如果JobManager崩溃,则无法提交新程序,正在运行的程序也会失败。通过JobManager的高可用性,…

【Rabbitmq篇】高级特性----事务,消息分发

目录 事务 消息分发 应用场景 1. 限流 2.负载均衡 事务 RabbitMQ是基于AMQP协议实现的,该协议实现了事务机制,因此RabbitMQ也支持事务机制.SpringAMQP也提供了对事务相关的操作.RabbitMQ事务允许开发者确保消息的发送和接收是原子性的,要么全部成功,要么全部失败. 何为原…

优先算法 —— 双指针系列 - 有效三角形的个数

1. 有效三角形的个数 题目链接: 611. 有效三角形的个数 - 力扣(LeetCode)https://leetcode.cn/problems/valid-triangle-number/description/ 2. 题目解析 以示例1为例: 3. 优化 我们都知道,判断三角形的方法就是两边相…

【H2O2|全栈】Node.js(2)

目录 前言 开篇语 准备工作 npm 概念 常见指令 项目中的包 创建项目 启动项目 服务器搭建 express 基本步骤 搭建应用 创建路由 监听端口 启动服务器 面试相关 结束语 前言 开篇语 本系列博客分享Node.js的相关知识点,本章讲解npm与服务器的简单…

Android 13 Aosp 默认允许应用动态权限

图库 frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java 修改 public void grantDefaultPermissions(int userId) {DelayingPackageManagerCache pm new DelayingPackageManagerCache();grantPermissionsToSysCompon…

【NLP高频面题 - LLM架构篇】LLM对Transformer都有哪些优化?

【NLP高频面题 - LLM架构篇】LLM对Transformer都有哪些优化? ⚠︎ 重要性:★★★ 💯 NLP Github 项目: NLP 项目实践:fasterai/nlp-project-practice 介绍:该仓库围绕着 NLP 任务模型的设计、训练、优化、…

DAY139权限提升-Linux系统权限提升篇Vulnhub辅助项目SUID权限SUDO指令版本漏洞

Linux提权 1、内核溢出提权 2、suid、sudo、nfs、path、ld_preload、cron、lxd、capability、rbash等 3、数据库类型提权 Linux: 系统用户:UID(0-999) 普通用户:UID(1000-*) root用户:UID为0,拥有系统的完全控制…

notepad++文件github下载

1、github下载网址:Releases notepad-plus-plus/notepad-plus-plus GitHub 2、找到操作系统支持的软件: 3、CSDN下载链接:https://download.csdn.net/download/u013083576/90046203

无人机应用板卡详解!

一、核心技术 无人机板卡的核心技术主要包括但不限于以下几种: 通信技术:无人机板卡通常集成了各种通信技术,如无线电通信、卫星通信等,以实现远程控制和数据传输。这些技术确保了无人机能够在复杂环境中保持稳定的通信连接。 …