【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

六、结语

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

在这里插入图片描述

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

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

相关文章

自动驾驶加速落地,激光雷达放量可期(上)

1 激光雷达应用广泛,汽车有望成最大催化 激光雷达(LiDAR)是一种主动遥感技术,通过测定传感器发出的激光在传感器与目标物体之间的传播距离,来分析目标地物表面的反射能量大小、反射波谱的幅度、频率和相位等信息&#…

python基础使用之记录日志模块

我们在编写Python 程序时,记录日志信息是一种非常重要的需求,日志可以帮助调试和跟踪程序的执行过程。那么Python中提供了内置的logging模块,用于记录各种级别的日志信息。本文主要介绍Python日志信息输出的实现过程。 1. 导入 logging 模块…

C++入门全集(4):类与对象【下】

一、再谈构造函数 1.1 构造函数体内赋值 我们知道,在创建对象时,编译器会自动调用构造函数给对象中的各个成员变量一个合适的初始值 class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;}private:int _yea…

开源项目:智能化图像分类技术在新能源发电监控中的应用与实践

一、引言 在当今世界,能源的转型和升级是推动社会可持续发展的关键因素。随着技术的进步,新能源发电逐渐成为能源结构调整的重要力量。在众多发电方式中,新能源发电技术如风力、太阳能等因其清洁、可再生的特性而备受青睐。然而,…

百度文库旋转验证码识别

最近研究了一下图像识别,一直找到很好的应用场景,今天我就发现可以用百度的旋转验证码来做一个实验。没想到效果还挺好,下面就是实际的识别效果。 1、效果演示 2、如何识别 2.1准备数据集 首先需要使用爬虫,对验证码图片进行采…

MATLAB中sigmoid函数用法

目录 语法 说明 示例 应用 sigmoid 激活 sigmoid函数的功能是应用sigmoid激活 语法 Y sigmoid(X) 说明 sigmoid 激活运算将 sigmoid 函数应用于输入数据。此运算等效于: 注意 此函数将 sigmoid 运算应用于 dlarray 数据。如果要在 layerGraph 对象或 Layer …

Git 版本控制

Git 版本控制 1. About Version Control (关于版本控制)1.1. Local Version Control Systems (本地版本控制系统)1.2. Centralized Version Control Systems (集中化的版本控制系统)1.3. Distributed Version Control Systems (分布式版本控制系统) 2. 换行符的处理3. keyboard…

深入理解Docker自定义网络:构建高效的容器网络环境

目录 博客前言: 一.docker自定义网络介绍 1.docker自定义网络介绍 2.使用技术的优势 3.基本使用流程 二.实战操作 1.模式理论介绍 bridge模式(默认模式) host模式 2.模式特点 查看桥接模式的特点 查看仅主机模式的特点 3.实战操作 bridge模式 host模式 自定义网络…

Android Compose - PlainTooltipBox(已废弃)的替代方案

Android Compose - PlainTooltipBox 的替代方案 TooltipBox(positionProvider TooltipDefaults.rememberPlainTooltipPositionProvider(),tooltip {PlainTooltip {Text(/* tooltip content */)}},state rememberTooltipState(), ) {// tooltip anchorIconButton(onClick {…

EdgeX Foundry - MQTT 设备服务

文章目录 一、MQTT 设备服务1.概述2.服务配置3.协议属性4.多级 Topics4.1.异步数据4.2.命令 二、连接 MQTT 设备1.docker-comepse2.设备配置文件3.安装自定义配置4.启动 EdgeX Foundry5.创建 MQTT 设备模拟器6.访问 UI6.1. consul6.2. EdgeX Console 7.测试7.1.命令7.2.事件7.3…

【踏雪无痕的痕五】——一年级数学题映射动态规划

目录 一、背景介绍三、过程1.那是什么样的一个数学题?2.动态规划是个啥?3.为啥联系到动态规划了?4.拿01背包算法做个小例子练练手吧5.感受 四、总结 一、背景介绍 小编发烧并发症一周了,这一周从最开始的轻飘飘找不到灵魂在哪里—…

【心理】程序人生之情绪与压力篇,附心理学相关证书备考指南(心理学312统考,心理治疗师,中科院心理咨询师,家庭教育指导师,企业培训证书)

程序员生活指南(情绪与压力篇)之 【心理】程序人生之情绪与压力专项,附心理学相关证书备考指南(心理学312统考,心理治疗师,中科院心理咨询师,家庭教育指导师,企业培训证书&#xff0…

Linux之进程信号

目录 一、概念引入 1、生活中的信号 2、Linux中的信号 二、信号处理常见方式 三、信号的产生 1、键盘产生信号 2、系统调用接口产生信号 3、软件条件产生信号 4、硬件异常产生信号 四、信号的保存 相关概念 信号保存——三个数据结构 信号集——sigset_t 信号集操…

程序员如何选择职业赛道?

程序员选择职业赛道就像是在一个充满挑战和机遇的迷宫中探索。不同的职业赛道代表着不同的路径,每条路径都有其独特的风景和挑战。我愿意为大家提供一些关于如何选择职业赛道的建议。本文将分为几个部分,包括了解自己、了解行业、职业规划、技能提升和持…

单片机独立按键控制LED状态

一、前言 这幅图是按键的抖动与时间的联系 按键抖动:对于机械开关,当机械鮑点断开、闭合时,由于机械触点的弹性作用,一个开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,所以在开关闭合及断开的…

加密与安全_探索数字证书

文章目录 Pre概述使用keytool生成证书使用Openssl生成证书 (推荐)证书的吊销小结 Pre PKI - 借助Nginx 实现Https 服务端单向认证、服务端客户端双向认证 PKI - 04 证书授权颁发机构(CA) & 数字证书 PKI - 数字签名与数字证…

matplotlib散点图

matplotlib散点图 假设通过爬虫你获取到了北京2016年3, 10月份每天白天的最高气温(分别位于列表a, b), 那么此时如何寻找出气温和随时间(天)变化的某种规律? from matplotlib import pyplot as pltx_3 range(1, 32) x_10 range(51, 82)y_3 [11,17,16,11,12,11,12,6,6,7,8…

GEE:使用双曲正切(tanh)激活函数对单波段图像进行变换(以NDVI为例)

作者:CSDN @ _养乐多_ 本文将介绍在 Google Earth Engine (GEE)平台上,对任意单波段影像进行 双曲正切(tanh)激活函数 变换的代码。并以对 NDVI 影像中像素值的变换为例。 文章目录 一、tanh激活函数1.1 tanh激活函数1.2 用到遥感图像上有什么用?二、代码链接三、完整代…

STL——queue

queue 1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。 2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特…

Linux入门到入土

Linxu Linux 简介 Linux 内核最初只是由芬兰人林纳斯托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的。 Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX(可移植操作系统接口&#xff09…