【Linux取经路】文件系统——inode与软硬链接

在这里插入图片描述

文章目录

  • 一、前言
  • 二、认识硬件——磁盘
    • 2.1 磁盘的存储构成
    • 2.2 磁盘的逻辑抽象
  • 三、操作系统对磁盘的使用
    • 3.1 再来理解创建文件
    • 3.2 再来理解删除文件
    • 3.3 再来理解目录
  • 四、硬链接
  • 五、软链接
  • 六、结语

一、前言

在之前的【Linux取经路】文件系统之被打开的文件——文件描述符的引入一文中讨论了被打开的文件,今天讨论的话题则是没有被打开的文件。文件等于文件内容文件属性,没打开的文件一定是存储在磁盘上的,并且 Linux 是将文件的属性和内容分开存储文件内容以数据块的形式进行存储,文件属性以 inode 的形式进行存储

在这里插入图片描述

二、认识硬件——磁盘

我们这里说的磁盘指的是机械磁盘,并非我们现在我们笔记本上使用的 SSD。机械磁盘是计算机上唯一的一个机械设备,也是一个外设。
在这里插入图片描述
小Tips:磁头是一面一个,磁头与盘面不接触。磁头通过向盘面进行充放电来完成数据的写入。磁盘叫做永久性存储介质,内存叫做掉电易失性存储介质。

2.1 磁盘的存储构成

在这里插入图片描述
每一个盘面由多个磁道构成,一个磁道又有多个扇区构成。磁盘被访问的最基本单元是扇区,一般扇区的大小是 512 字节,有的是 4KB。要修改磁盘中 1 字节的数据,需要把该字节所在的扇区都加载到内存中。可以把磁盘看成是由无数个扇区构成的存储介质。要把数据存储到磁盘,第一个需要解决的问题就是如何定位一个扇区,首先需要定位盘面,也就是确定用哪个磁头,因为一个磁头对应一个盘面,接下来需要定位磁道,最后定位扇区。所有的磁头都是同步运动的,在某一时刻,从从上向下看去,以磁头所在点为半径的不同盘面上的磁道就会形成一个叫做柱面的结构。磁头运动主要是去定位磁道,盘面旋转主要是去定位扇区,磁头的定位是由硬件电路进行控制。由此可见,磁盘的读取效率取决于磁头、盘面的运动速度和运动次数,运动越少,效率越高;运动越多,效率越低。因此,在软件设计上要求设计者一定要有意识的将相关数据放在一起。

2.2 磁盘的逻辑抽象

在这里插入图片描述
最终一个磁盘可以看作是基于扇区的数组,每一个扇区都对应有一个下标来唯一标识。通过这个下标(LBA 逻辑扇区地址),再结合每一面磁道的个数和每一个磁道上扇区的个数就可以定位到该扇区在磁盘上的位置(CHS地址)。

小Tips:不仅 CPU 有寄存器,其它外设也有,磁盘中也有寄存器。比如:控制寄存器,用来存储 CPU 下发的读写指令;数据寄存器,存储要写入的磁盘的数据;地址寄存器,存储 CPU 传送来的 LBA 地址;状态寄存器,存储磁盘的状态,操作系统通过检查该状态寄存器去判断读写是否成功。

三、操作系统对磁盘的使用

在这里插入图片描述
上图为 Linux ext2 磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,操作系统首先会对磁盘进行分区,就如我们电脑中的 C 盘和 D 盘。接着,磁盘分区被划分为若干个块组(Block group),每个块组中有许多块(block),一个 block 的大小是由格式化的时候确定的,并且不可以更改,常见的是 4KB,即 4096字节。

  • Boot Block:通常存储操作系统启动的相关信息,比如:操作系统在什么位置、当前磁盘一共被划分成了多少个分区等。这些信息一般存储在磁盘的最前面,当然为了防止意外,这些内容在其它地方也会有备份。

  • Block Group:ext2 文件系统会根据分区的大小划分为数个 Block Group。而每个 Block Group 都有着相同的结构组成。

  • Super Block:存放文件系统本身的信息,这里面记录了整个分区的信息。例如:整个分区有多大、该分区里面每组的起始位置、每个组的大小、每个组的 inode 数量、每个组的 block 数量、每个组的其实 inode 编号、block 和 inode 的总量,未使用的 block 和 inode 的数量,一个 block 和 inode 的大小、文件系统的类型与名称、最近一次挂载的时间、最近一次写入数据的时间、最近一次检验磁盘的时间、该文件系统所拥有的字段以及字段的存储顺序和起始位置(也就是规定了一个组的空间划分)等其它文件系统的相关信息。Super Block 的信息被破坏,可以说整个文件系统结构就被破坏了。该字段并不是在每一个分组中都有,而是在部分组里面有,防止意外发生,操作系统通过“魔数”来判断是否是 Super Block。

  • Group Descriptor Table:块组描述符,存储块组属性信息,例如:当前分组的大小、使用情况、下一个文件描述符应该从哪开始。

  • Block Bitmap:块位图,将比特位的位置和块号映射起来,里面记录着 Data Block 中哪个数据块已经被占用,哪个数据块没有被占用。

  • inode Bitmap:每个 bit 表示一个 inode 是否空闲可用。

  • inode Table:一组 inode。每一个 inode 用来存放单个文件的所有属性,如:文件大小、所有者、最近修改时间等。每个 inode 的大小一般是 128字节,且每一个 inode 都有唯一的编号。一般而言,一个文件一个 inode。

  • Data block:数据区,存放文件内容。以块的形式呈现,常见块的大小是 4KB。每个块都有自己独一无二的块号。

小Tips:操作系统在访问磁盘的时候,会以块为基本单位进行访问。

格式化:每个组的前四个字段存储的都是一些文件系统的属性信息或者分组的使用情况信息,这些内容应该在我们使用磁盘之前都准备好。所以,每一个分区在被使用前,都必须将部分文件系统的属性信息提前设置进对应的分区中,方便后续对分区和分组的使用,这个动作就叫做格式化。

在 Linux 中,文件的属性里面是不包含文件的名称在 Linux 系统里面标识文件用的是 inode 编号。一个 inode 表示一个文件的所有属性,文件名并不属于 inode 内的属性。

在这里插入图片描述
一个 inode 与 数据块的对应关系:

在这里插入图片描述
其中直接索引对应的块中存储的就是文件内容,二级索引对应的块中存储的不是文件内容而是块号。假设块的大小是 4KB,块号用 4字节。那么一个块就可以存储 1024 个块号,这 1024 个块号对应的块里面存储的是文件的内容,三级索引同理。这样做的目的是在 inode 里面用较少的空间就可以映射出更多的数据块。

小Tips:inode 编号是以分区为单位进行统一分配的,而且不能跨分区,即每个分区中的 inode 编号都是从 0 开始,且一个分区中的 inode 个数是有上限的,因此可能会存在一下情况:一个分区中的 inode 被用完了,但是数据块还没有被用完,这种情况对应的就是创建了非常多的文件,但是每个文件的内容非常小;一个分区中的数据块被用完了,但是 inode 还没有被用完,这种情况就是创建的文件并不多,但是每个文件的大小非常大。

3.1 再来理解创建文件

首先创建文件一定是在一个路径下(目录)进行创建,这个路径就会帮我们定位到一个分区,然后去从第一个分组开始查看当前分组的 GDT 字段,看该分组中 inode 的使用情况,若当前分组中的 inode 还有剩余,接着去读取 inode_Bitmap,获取最近一个未被使用的 inode 编号,然后拿着 inode 编号去 inode_Table 里面找到对应的 inode,将文件的属性信息一填。如果有文件内容,先拿着 inode 编号找到对应的分组,根据写入内容的大小去 Block_Bitmap 中找出对应数量未被使用的块号,然后将这些块号写入到 inode 对应的属性里面,然后拿着块号去 Data blocks 中进行写入。

3.2 再来理解删除文件

删除文件只要拿着该文件的 inode 编号,在 inode Table 中找到对应的 indoe,获取到里面的 blocks,即拿到该文件对应的所有块号,然后根据这些块号将 Block Bitmap 中对应的比特位置0(假设 0 表示对应的块未被使用)。最后再根据 inode 编号到 inode Bitmap 中将该 inode 对应的比特位置为0,至此,一个文件就被删除啦。可以发现从头到尾并没有去修改块中的内容,这也是为什么拷贝 4G 的文件很慢,删 4G 的文件很快。所以在理论上,一个被删除的文件,可以根据 inode 将其恢复出来。

总结:删文件就是去修改 inode_Bitmap 和 Block_Bitmap 中的字段。在计算机领域的删除并不等于清空,大部分情况下,删除都表示可覆盖。因为清空会导致效率大大下降。

3.3 再来理解目录

上面说的所有对文件的操作都离不开 inode 编号,但是我们作为普通用户平时好像也并没有关注过 inode 编号,我们一般是直接使用文件名,此时就必须再来理解一下目录了。目录也是文件,也有自己的 inode,目录也有属性。目录也有(数据块),目录的数据块里面存放的是这个目录下的所有文件名和该文件名对应的 inode 编号的映射关系,这是一种 key-value 结构,这就是为什么一个目录里面不允许出现同名文件。与此同时,和目录有关的一些历史问题也得到了解决,对于一个目录,没有 w,我们无法在该目录下创建文件,本质就是我们不能向目录对应的数据块中写入文件名和 inode 的对应关系;没有 r,无法产看该目录下的文件,本质就是不能读取目录文件的数据块。因此我们在查找一个文件时,首先需要知道该文件所在目录的 inode,要知道目录文件的 inode 编号,就需要知道目录文件所在目录的 inode 编号,如此递归一直到根目录,这就是为什么我们在操作一个任何一个文件的时候都需要知道它的绝对或者相对路径。如果每操作一个文件都要去这样递归一层层的查找,那么效率是非常低的。因此在 Linux 操作系统中有一个叫做 dentry 缓存(目录项缓存),里面记录了该用户经常访问的文件名和 inode 编号之间的映射关系。

四、硬链接

// 创建硬链接的指令
ln test.txt hard-link

在这里插入图片描述
硬连接不是一个独立的文件,因为它没有独立的 inode。所谓建立硬连接,本质其实就是在特定目录的数据块中新增文件名和指向的文件的 inode 编号的映射关系。上图也可以证明文件名不是 inode 中的属性,因为一个 inode 编号对应一个 inode,如果文件名是 inode 中的属性,那么上图中编号 1978740 的文件不可能对应两个文件名。

小Tips:任意一个文件,无论是目录,还是普通文件,都有 inode,每一个 inode 内部,都有一个叫做引用计数的计数器,这个计数器记录了有多少个文件名“指向”该文件(由硬链接可以得知,在 Linux 中可以让多个文件名对应于同一个 inode)。完整的删除文件过程就是先将特定目录数据块中的文件名与 inode 的映射关系删除,然后根据 inode 的编号,将对应 inode 中的引用计数减减,最终看其是否减到零,减到零再执行 3.2 小结的步骤。此外,创建一个普通文件,它的硬链接数默认是1。

创建目录文件的默认链接数为什么是 2 ?

在这里插入图片描述
硬链接数为2,说明与该文件 inode 编号有关的映射关系有两个,其中一个映射关系保存在 dir 所在目录文件的数据块,即 2023-11-06 目录文件中的数据块中,另外一个保存在 dir 目录自身的数据块中。

在这里插入图片描述
根目录的硬链接数减2就是根目录下创建的目录个数。根目录稍微有一点特殊,根目录中的 ... 文件名对应的 inode 编号是一样的,都是根目录。除去这俩文件名和 inode 编号的映射关系外,剩下的硬链接数就表示根目录下创建的目录个数,剩下的 18 个就是根目录中所有目录文件中 .. 与根目录 inode 编号的链接关系。可以这样计算的本质原因就是,根目录下所有目录中的 .. 都一定是指向根目录的,对应根目录的 inode 编号(也就是上图中的 2 )。这种计算方法也可以推行到其它任意目录。

总结:建立硬链接就是给一个已存在的文件创建别名,硬链接通常用来进行路径定位,采用硬链接,可以进行目录间切换。

在这里插入图片描述
小Tips:Linux 系统不允许用户对目录文件建立硬连接。只要是为了避免在文件搜索的时候发生环路问题,系统在搜索文件的时候并不会搜索 ...,如果允许用户为目录文件创建硬链接,那么操作系统在进行文件搜索的时候就无法避免环路问题。

五、软链接

// 创建软链接的指令
ln -s file.txt soft-link

在这里插入图片描述
软链接是一个独立的文件,有独立的 inode,也有独立的数据块,它的数据块里面存的是指向文件的路径。软链接非常像 Windows 中的快捷方式。软链接的使用场景:一般发布的可执行程序可能存在一个较深的路径下面,要执行它的话就需要带很长一串路径,显得十分麻烦,此时我们就可以创建一个软链接指向该可执行文件,之后要想运行该可执行程序就直接去执行软链接即可。

在这里插入图片描述
在这里插入图片描述
小Tips:可以对任意类型的文件创建软链接。

// 删除软硬链接都可以用 unlink 指令
unlink soft-link

六、结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,春人的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是春人前进的动力!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DevStack 基于 Ubuntu 部署 OpenStack

Devstack 简介 DevStack 是一系列可扩展的脚本,用于基于 git master 的最新版本快速调出完整的 OpenStack 环境。devstack 以交互方式用作开发环境和 OpenStack 项目大部分功能测试的基础。 devstack 透过执行 stack.sh 脚本,搭建 openstack 环境&…

Day31|贪心算法1

贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 无固定套路,举不出反例,就可以试试贪心。 一般解题步骤: 1.将问题分解成若干子问题 2.找出适合的贪心策略 3.求解每一个子问题的最优解 4.将局部最优解堆叠成全局最…

【MySQL】深入解析 Buffer Pool 缓冲池

文章目录 1、前置知识1.1、Buffer Pool介绍1.2、后台线程1.2.1、Master Thread1.2.2、IO Thread1.2.3、Purge Thread1.2.4、Page Cleaner Thread 1.3、重做日志缓冲池 2、Buffer Pool 组成2.1、数据页2.2、索引页2.3、undo页2.4、插入缓冲2.5、锁空间2.6、数据字典2.6、自适应哈…

JavaScript之structuredClone现代深拷贝

在JavaScript中,实现深拷贝的方式有很多种,每种方式都有其优点和缺点。今天介绍一种原生JavaScript提供的structuredClone实现深拷贝。 下面列举一些常见的方式,以及它们的代码示例和优缺点: 1. 使用JSON.parse(JSON.stringify(…

代码随想录 二叉树第四周

目录 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众树 236.二叉树的最近公共祖先 617.合并二叉树 617. 合并二叉树 简单 给你两棵二叉树: root1 和 root2 。 想象一下,当你将其…

第105讲:Mycat垂直分表实战:从规划到解决问题的完整指南

文章目录 1.垂直分表的背景2.垂直分表案例实战2.1.垂直分表规划2.2.配置Mycat实现垂直分表2.3.重启Mycat2.4.在Mycat命令行中导入数据结构2.5.查看由Mycat分表后每个分片上存储的表2.6.Mycat垂直分表后可能遇到的问题2.7.垂直分表完成 1.垂直分表的背景 我们的商城系统数据库&…

javaWebssh水利综合信息管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh水利综合信息管理系统是一套完善的web设计系统(系统采用ssh框架进行设计开发),对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCA…

MATLAB 实现贝叶斯决策

1. 原理 后验概率: 1.最小错误率决策(最大后验概率决策): 2.最小风险决策: 3.正态分布下的贝叶斯决策 2. 过程 2.1 训练集数据可视化 导入两类训练集数据,并绘制其数据分布,如下:…

云时代【5】—— LXC 与 容器

云时代【5】—— LXC 与 容器 三、LXC(一)基本介绍(二)相关 Linux 指令实战:使用 LXC 操作容器 四、Docker(一)删除、安装、配置(二)镜像仓库1. 分类2. 相关指令&#xf…

JavaSE-09(Java IO精华总结)

Java IO 简单做个总结: 1 .InputStream/OutputStream 字节流的抽象类。2 .Reader/Writer 字符流的抽象类。3 .FileInputStream/FileOutputStream 节点流:以字节为单位直接操作“文件”。4 .ByteArrayInputStream/ByteArrayOutputStream 节点流&#xff…

Running job: job_1709516801756_0003

** yarn运行卡在Running job: job_1709516801756_0003问题解决: ** 在运行wordcount时出现错误,一直卡住 运行命令:hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount /input /output 出现错误&#xff1a…

经典思路!人参叶际微生物如何发8分文章?

中国中医科学院中药研究所在《Environmental Microbiome》期刊上(IF7.9)发表了关于叶际真菌微生态网络的文章,该研究通过对ITS测序结果和环境因子测定结果以及皂苷含量测定结果进行生信分析,提出了维持微生态网络的稳定性策略和影响皂苷含量的因素。 期刊…

H12-821_113

113.如图所示是路由器现ATE输出的部分信息,以下关于这部分信息的描述,错误的是哪一项? A.display pim rp-info命令用来查看组播组对应的RP信息 B.RP地址是2.2.2.2 C.组地址是225.0.0.0 D.RP的优先级是0 答案:C 注释: …

HCIA-Datacom题库(自己整理分类的)_29_PPP协议判断【6道题】

1.数据链路层采用PPP封装链路两端的IP地址可以不在同一个网段。√ 2.PPP链路两端不在同一网段不能通信。 3.参考以下拓扑及配置,路由器R1与R2通过Serial低速线缆连接,且数据链路层封装使用PPP。当R1和R2的Holdtime不一致时,PPP协商失败&…

爬虫实战——麻省理工学院新闻

文章目录 发现宝藏一、 目标二、 浅析三、获取所有模块四、请求处理模块、版面、文章1. 分析切换页面的参数传递2. 获取共有多少页标签并遍历版面3.解析版面并保存版面信息4. 解析文章列表和文章5. 清洗文章6. 保存文章图片 五、完整代码六、效果展示 发现宝藏 前些天发现了一…

MySQL面试题-日志(答案版)

日志 1、为什么需要 undo log? (1)实现事务回滚,保障事务的原子性。 事务处理过程中,如果出现了错误或者用户执 行了 ROLLBACK 语句,MySQL 可以利用 undo log 中的历史数据将数据恢复到事务开始之前的状态…

ssh无法直接登入Linux超级用户root(23/3/3更新)

说明:不允许ssh用超级用户的身份登入是为了安全性,如果只是学习使用对安全性没啥要求可以按以下操作解除限制 以普通用户登录到服务器后,执行以下命令以编辑 SSH 服务器配置文件 /etc/ssh/sshd_config sudo nano /etc/ssh/sshd_config 此时会…

【C++练级之路】【Lv.10】【STL】priority_queue类和反向迭代器的模拟实现

快乐的流畅:个人主页 个人专栏:《C语言》《数据结构世界》《进击的C》 远方有一堆篝火,在为久候之人燃烧! 文章目录 一、仿函数1.1 仿函数的介绍1.2 仿函数的优势 二、priority_queue2.1 push2.2 pop2.3 top2.4 size2.5 empty 三、…

【3D Slicer】心脏CT图像分割操作保姆级教程 Cardiac CT image segmentation

心脏CT图像分割操作流程指南 1 安装3D Slicer软件2 打开文件2.1 从File->Add Data->Choose File2.2 直接拖入 3 进行分割操作4 切片填充 Fill between slices5 第二个例子6 数据保存7 打开保存后的文件 1 安装3D Slicer软件 方式二选一 1.官网:3D Slicer 2.百…

无字母数字rce总结(自增、取反、异或、或、临时文件上传)

目录 自增 取反 异或 或 临时文件上传 自增 自 PHP 8.3.0 起,此功能已软弃用 在 PHP 中,可以递增非数字字符串。该字符串必须是字母数字 ASCII 字符串。当到达字母 Z 且递增到下个字母时,将进位到左侧值。例如,$a Z; $a;将…