【Linux】磁盘文件系统(inode)、软硬链接
文章目录
- 1. 认识磁盘
- 1.1 磁盘的物理结构
- 1.2 磁盘的逻辑结构
- 2. 引入文件系统
- 2.1 EXT系列文件系统的分区结构
- 2.2 inode
- 3. 软硬链接
- 3.1 软链接
- 3.2 硬链接

在讲过了内存文件系统后,我们可以知道文件分为两种:
- 打开的文件(内存中)
- 未被打开的文件(磁盘中)
今天我们主要来探讨未被打开的文件。
- 当文件存储在磁盘中时,如果我要打开它,那我首先要能找到它(通过路径)
- 既然是这样,那Linux中每一个文件都要有路径
- 为了更好的进行磁盘级文件的管理,我们必须要有一个磁盘文件系统的东西
那么文件系统是怎么把没有被打开的文件在磁盘上管理起来的呢?
只要它管好了,就可以给我们提供正确的路径,那么我们就可以定位这个文件,在系统层面就可以打开这个文件,进而能够转化到内存中,进行内存文件的管理。
1. 认识磁盘
1.1 磁盘的物理结构
- 磁盘的结构
磁盘在工作时,主轴会高速旋转,磁头也会左右摆动。
- 磁盘的存储结构
一个盘片有两面,每一面都可以存数据。多个盘片,相同磁道之间自上而下形成一种逻辑结构:柱面。
- 磁头在运动过程中不断摆动的本质是:定位磁道或柱面。
- 磁盘在旋转的时候,目的是让磁道上不同的扇区处在磁头下方,本质是:定位扇区。(扇区是磁盘存储数据的基本单位,一般为512字节,读写时是以512字节为整体,构成一个“块”,所以磁盘也叫做块设备)
在linux系统也是可以查到扇区的
- 磁盘每一个面上都有一个磁头,对应h0-h5;读写哪一个磁头,本质是读写哪一面。
- 传动臂上的磁头是共进退的。
所以如何定位一个扇区呢?
- 先定位柱面(cylinder)
- 再定位磁头(head)
- 最后定位扇区(sector)
因此,这叫做CHS定址法。
由于文件 = 内容+属性,但它们都是数据,在磁盘中无非就是占据哪几个扇区的问题。那既然我们能定位一个扇区了,那能不能定位多个扇区呢?
1.2 磁盘的逻辑结构
磁带也是磁盘的一种,在磁带圈起来时,就类似一个盘面。将其拉直展开,就可以看成是由扇区为单位组成的数组。
我们可以将磁盘想象成卷起来的磁带,那么就可以将磁盘的某一个盘片上的某一个磁道抽象为线性结构,类似于数组:
这样,每一个扇区,就有了一个线性地址(数组下标)
所以,在系统使用文件的时候,只需要使用数组下标法(LBA),不用关心CHS,但是数组下标又是怎么得到的呢?
由于传动臂上的磁头是同进退的,所以在我们找磁道时,所有的磁头共同移动,对应就找到了一个柱面。
所以,磁盘虽然分了很多面,但是在我们看来,逻辑上磁盘是由n多个柱面组成的。
所以,磁盘的真实情况应该是:
所以,磁盘就可以抽象为一个”三维数组“,但是在我们看来,其实它还是一个一维数组
所以,每个扇区都有一个下标,我们叫做LBA(Logical Block Address),其实就是线性地址。
LBA与CHS之间可以互相转换(磁盘的工作)。
当磁盘告诉操作系统磁盘的总容量、扇区大小,那OS一瞬间就可以知道有多少个扇区了。
那么从今往后 ,在磁盘的使用者看来,根本不关心CHS地址,而是直接使用LBA地址,磁盘内部自己转换
。
所以,从现在开始,磁盘就是一个元素为扇区的一维数组,数组的下标就是每一个扇区的LBA地址。OS使用磁盘,就可以用一个数字访问磁盘的扇区了。
2. 引入文件系统
2.1 EXT系列文件系统的分区结构
有了上面的知识后,我们知道OS与磁盘进行IO时,就是访问数组下标所对应的扇区,但是扇区512字节有点少,即单次IO的数据量有点少。
为了增加单次IO的数据量,OS与磁盘进行交互时,是以1KB、2KB、4KB、8KB等数据块为单位进行IO的,Linux中选择4KB数据块,一个数据块由8个扇区构成。
所以,在文件系统层面上,它才不管扇区,它IO的基本单位是数据块。
数据块转LBA地址:块号*8 + [1,8]
那么我们的磁盘就被抽象成了以块位单位的数组。
如果直接对块进行管理的话,成本太高了。因此将众多块又划分为一个分区,最终磁盘被划分为N个分区,分区之间各自独立。
分区中又划分出了组
分完组之后,只需要对组进行管理就可以。
一个组又分为如下几个区域:
2.2 inode
由于文件 = 内容+属性,属性也是数据,是以结构体的方式构建出来的,该结构体叫做inode(文件对应属性的集合,一般是128字节),所以在磁盘的一个4KB块中,会有32个inode。
在Linux中可以使用ls - i 选项查看一个文件的inode,下方显示出来的信息起始就是inode struct中的内容。
在一个组中,会存在非常多的inode,所以组中就存在一张inode Table,存放组中所有inode,方便管理每一个文件。
Data Blocks中,全都是划分好的4KB块,存放的是文件的内容。
所以,在Linux下,文件的属性和内容是分开存储的。
那通过inode找到文件的属性后,内容是怎么找到的呢? - - 在inode中,存在一个block数组,记录当前inode所占用的data block块,后面讲。
一个组中的区域分布如下:
- inode table(节点表):存储了每个inode的详细信息,包括文件的大小、权限、时间戳、数据块位置等
- Data blocks(数据区):存放文件内容,全都是划分好的4KB块
- inode Bitmap(inode table位图):每个bit位表示inode table中的inode是否被占用。 inode号在inode table中早就设置好了,只是有没有被使用的问题。inode bitmap中的位置与inode table中的位置是一一对应的。
- Block Bitmap(块位图):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用
- Group Descriptor Table:块组描述符,描述块组属性信息。例如:每个组的起始inode与block编号。
- 超级块(Super Block):
存放当前分区文件系统本身的结构信息
。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。
Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。Super Block有多份拷贝,可在损坏时进行修复。
分区格式化的本质:写入空的文件系统。将组中的super block、GDT、data bitmap、block bitmap置为空即可。
关于inode
- inode是以分区为单位的,一个分区一套inode。因此不同分区可以有相同inode
- inode在分配时,只需要确定当前组起始inode即可
关于block
- 块号也是以分区为单位的
- 块号在分配时,也只需要确定当前组的起始block编号
在一个组中,我们是如何分配一个inode的呢?
- 由于inode bitmap的存在,我们只需要在bitmap中找一个可用位置,然后加上当前组inode的起始编号即可。 由于组起始inode的存在,我们就在不同组的起始inode之间就形成了一个区间,所以我们就可以分配为全局且唯一的inode
在一个组中,我们是如何分配一个block的呢?
- 由于block bitmap的存在,我们只需要在blockmap中找一个可用位置,然后加上当前组block的起始编号即可。 在整个区间中,block号也是全局且唯一的。 当一个组中存储大文件,块不够用时,可以跨组!inode中记录了所有存储文件内容的块
当知道一个inode号或者block块时,只需要在GDT中比对每一个组的起始编号,定位组;然后使用提供的inode号或者block号减去该组的起始编号,即可在位图中找到对应的位置,然后就可以确定inode在inode table的位置。
所以我们就可以确定任意一个块、任意一个组了。
那inode和block是怎么映射的呢?inode中block数组是多大呢?
在ext系列的文件系统中,block数组的大小是15,可是一个块才4KB,总共才60KB,那怎么能行呢?
前12个确实直接指向数据块;后三个则不是,它们3个存的是数据块的编号。
当前组的data block不够用时,是可以跨组的。但不建议这么做,因为一旦跨组访问了,意味所有的块不连续了,磁盘寻址效率也会大大降低。
在上面对文件的所有操作中,都是以inode为前提的,但是inode是怎么得到的呢?我们平时操作文件使用的都得文件名呀!
所以inode是通过文件名找到的,我们在struct inode中也并没有看到文件名的存在,那文件名存在哪里呢?
- 要弄清楚上面的问题,我们首先要知道,文件有普通文件和目录文件,我们之前谈论的全部都是普通文件,那目录文件又是如何呢?
- 上面我们已经从文件系统角度认识文件了,所以目录文件也要有属性和内容,那内容中也要有对应的数据块。
- 目录文件的数据块中存的是什么呢? - -
存文件名和inode的映射关系,二者互为映射
- 所以,文件名存放在文件所属的目录的数据块中
此时,我们就可以更清楚的认识目录的权限:
- r:没有读权限,就无法读取目录的data block,也就得不到文件名和inode的映射关系,拿不到inode,你怎么访问文件。
- w:没有写权限,无法把文件名和inode的映射关系保存到目录的data block中
那我们的文件名又是怎么找到的呢?
要找到一个文件名,首先要打开当前目录,访问当前目录的data block;
可是目录也是文件,也有文件名呀?所以还需要继续向上找,直到根目录。根目录的data block中固定存储了文件名与inode的映射关系。
但是在系统中并不是逆向的,而是正向的。
因为任何一个文件都有路径,在最开始时,系统就按照路径进行查找。
当我访问在同一个目录下的另一个文件时,系统还需要从头再访问一遍磁盘的文件系统吗? - - 不需要了,Linux系统中,会对所访问过的路径进行缓存!会以一个多叉树的结构,将路径缓存在内存中,该结构在内核中叫做 dentry树
所以,系统在查找一个文件时
- 先按照路径找到文件所在的目录
- 在目录的data block块中,获得文件名与inode的映射关系
- 拿着inode,对比磁盘分区的GDT,确定该inode在哪一个分组
- 确定分组后,用inode减去该分组的起始inode,确定inode的位置n
- 通过inode bitmap核实 n 位置,然后找到inode table中的n位置对应的inode
- 通过inode中的block数组,访问对应的数组块。
那inode和进程、文件描述符之间又有什么关系呢?
此时,我们的进程和文件就关联起来了。
那整体上我们应该怎么理解呢?
3. 软硬链接
- Access 最后访问时间
- Modify 文件内容最后修改时间
- Change 文件属性最后修改时间
在之前的学习中,我们直到使用ls -l 命令可以查看文件的属性,可是在文件权限后面的那一列数字,代表的是什么呢?
3.1 软链接
建立软链接的方式:
ln -s 被链接的文件名 链接后的文件名
下面我们将它们的inode也显示出来
发现二者的inode并不相同,软链接有自己独立的inode,因此,软链接本质是一个独立的文件。
当我们对被链接的文件与链接后的文件操作时,发现它俩操作的是同一个文件。
删除一个软链接的方式:
unlink 链接后的文件名
3.2 硬链接
建立硬链接的方式:
ln 被链接的文件名 链接后的文件名
此时我们发现,file-hard.link与file.txt两个文件的inode相同,并且权限后面的那一列数组变成了2,这是什么情况呢?而且如果将file-hard.link删掉,那一列数字又变成了1,那一列数字到底是什么意思呢?
首先,既然二者的inode相同,那么硬链接本质上不是一个独立的文件。
了解软硬链接的创建后,那么该如何理解软硬链接呢?为什么要有软硬链接呢?
- 理解软硬链接
软链接
- 软链接有独立的inode,那么它就有内容和属性。
- 内容中,它保存的是目标文件的路径,等同于快捷方式
硬链接
- 硬链接不是独立的文件,它本质存储的是指向文件inode的引用,通过共享inode来实现对同一文件数据的访问
文件权限后面对应的那一列数字是什么意思呢?
首先我们知道,文件名并不在inode中保存,它保存在文件所属目录的内容(data block)中,这也就意味着会有多个文件名映射到同一个文件上。
换句话说,一个文件在什么时候才能被系统真正的删除呢?- - 没有任何文件名映射到当前文件的inode时。
在inode内部,存在一个引用计数,来统计有多少个文件名映射到当前inode。
那一列数字,对应的就是当前inode的引用计数的个数,即硬链接数。
- 为什么要有软硬链接呢?应用场景是什么?
软链接的作用
- 通过创建一个指向目标文件或目录的软链接,可以简化对目标文件或目录的访问路径。用户可以通过软链接名来访问目标文件或目录,而不需要输入完整的路径。
- 软链接类似于一个文件系统中的“快捷方式”,如果目标文件或目录被删除或移动,软链接将变成“死链接”(dangling link),即指向一个不存在的文件或目录。
当我创建了一个目录时,为什么它的硬链接数是2呢?
当我在empty目录中又创建了一个目录时,它为什么又变成3了呢?
因为有以下三个硬链接指向它
- empty
- empty/.
- empty/dir/. .
所以,这就是为什么一个文件创建时,默认有两个隐藏目录 .
和 . .
,为了方便找路径
硬链接的作用
- 数据冗余和备份:通过创建硬链接,你可以在不同的目录或同一目录中拥有文件的多个访问路径。如果原始文件被删除,硬链接仍然可以访问文件数据。这就意味着,在linux中,如果对文件进行备份,只需要建立硬链接!
- 节省磁盘空间:硬链接不会创建文件的副本,而是共享相同的物理数据块。因此,它们可以节省磁盘空间,特别是在需要多个文件副本的情况下。
- 文件恢复:如果文件被误删除,但文件系统中仍然存在指向该文件的硬链接,那么文件数据仍然可以恢复。这提供了一种额外的数据保护机制。
注意:Linux中,不允许对目录新建硬链接。因为硬链接后的目录,也是可以进入的,那么就会产生环状路径。
相关文章:

【Linux】磁盘文件系统(inode)、软硬链接
文章目录 1. 认识磁盘1.1 磁盘的物理结构1.2 磁盘的逻辑结构 2. 引入文件系统2.1 EXT系列文件系统的分区结构2.2 inode 3. 软硬链接3.1 软链接3.2 硬链接 在讲过了内存文件系统后,我们可以知道文件分为两种: 打开的文件(内存中)未…...

网安加·百家讲坛 | 徐一丁:金融机构网络安全合规浅析
作者简介:徐一丁,北京小西牛等保软件有限公司解决方案部总监,网络安全高级顾问。2000年开始从事网络安全工作,主要领域为网络安全法规标准研究、金融行业安全咨询与解决方案设计、信息科技风险管理评估等。对国家网络安全法规标准…...

九、pico+Unity交互开发——触碰抓取
一、VR交互的类型 Hover(悬停) 定义:发起交互的对象停留在可交互对象的交互区域。例如,当手触摸到物品表面(可交互区域)时,视为触发了Hover。 Grab(抓取) 概念ÿ…...

老机MicroServer Gen8再玩 OCP万兆光口+IT直通
手上有一台放了很久的GEN8微型服务器,放了很多年,具体什么时候买的我居然已经记不清了 只记得开始装修的时候搬家出去就没用了,结果搬出去有了第1个孩子,孩子小的时候也没时间折腾,等孩子大一点的时候,又有…...

jmeter 从多个固定字符串中随机取一个值的方法
1、先新增用户参数,将固定值设置为不同的变量 2、使用下面的函数,调用这写变量 ${__RandomFromMultipleVars(noticeType1|noticeType2|noticeType3|noticeType4|noticeType5)} 3、每次请求就是随机取的值了...

priority_queue (优先级队列的使用和模拟实现)
使用 priority_queue 优先级队列与 stack 和 queue 一样,也是一个容器适配器,其底层通过 vector 来实现的。与 stack 和 queue 不同的是,它的第一个元素总是它所包含的元素中最大或最小的一个。 也就是说,优先级队列就是数据结…...
VisionPro 手部骨骼跟踪 Skeletal Hand Tracking 虚拟首饰
骨骼手部跟踪由XR Hands Package中的Hand Subsystem提供。使用场景中的Hand Visualizer组件,用户可以显示玩家手部的蒙皮网格或每个关节的几何图形,以及用于基于手部物理交互的物理对象。用户可以直接针对Hand Subsystem编写 C# 脚本,以推断骨…...

class 9: vue.js 3 组件化基础(2)父子组件间通信
目录 父子组件之间的相互通信父组件传递数据给子组件Prop为字符串类型的数组Prop为对象类型 子组件传递数据给父组件 父子组件之间的相互通信 开发过程中,我们通常会将一个页面拆分成多个组件,然后将这些组件通过组合或者嵌套的方式构建页面。组件的嵌套…...
Laravel|Lumen项目配置信息config原理
介绍 Laravel 框架的所有配置文件都保存在 config 目录中。每个选项都有说明,你可随时查看这些文件并熟悉都有哪些配置选项可供你使用。 使用 您可以在应用程序的任何位置使用全局 config 辅助函数轻松访问配置值。 可以使用“点”语法访问配置值,其中…...
2024系统分析师考试---论区块链技术及其应用
试题三论区块链技术及其应用 区块链作为一种分布式记账技术,目前已经被应用到了资产管理、物联网、医疗管理、政务监管等多个领域,从网络层面来讲,区块链是一个对等网络(Peer to Peer,P2P),网络中的节点地位对等,每个节点都保存完整的账本数据,系统的运行不依赖中心化节…...
为您的 Raspberry Pi 项目选择正确的实时操作系统(RTOS)
在嵌入式系统设计中,实时操作系统(RTOS)的选择对于确保项目的实时性能和可靠性至关重要。Raspberry Pi,尤其是其最新的RP2040微控制器,为开发者提供了一个功能强大的平台来实现各种实时应用。本文将探讨如何为您的Rasp…...
鸿蒙应用的Tabs 组件怎么使用
鸿蒙应用中的Tabs组件是一个用于通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。以下是Tabs组件的使用方法: 一、基本结构 Tabs组件的页面组成包含两个部分,分别是TabContent和TabBar。TabContent是内容页,TabB…...
第四天 文件操作与异常处理
在Python中,文件操作是处理输入输出的基本操作之一,而异常处理则用于管理潜在的错误情况,确保程序的健壮性和稳定性。下面将介绍Python中的文件操作和异常处理的基本用法。 文件操作 打开文件 使用内置的 open() 函数可以打开一个文件&…...
【密码分析学 笔记】ch3 3.1 差分分析
ch3 分组密码的差分分析和相关分析方法 3.1 差分分析 评估分组密码安全性通用方法可用于杂凑函数和流密码安全性 预备知识: 迭代性分组密码(分组密码一般结构)简化版本 mini-AES CipherFour算法 3.1.1 差分分析原理 现象:密…...
Go:strings包的基本使用
文章目录 string前缀和后缀字符串包含判断子字符串或字符在父字符串中出现的位置字符串替换统计字符串出现次数重复字符串修改字符串大小写修剪字符串分割字符串拼接 slice 到字符串 strconv 本篇主要总结的是go中的string包的一些函数的操作讲解 string 在各个语言中&#x…...

uniapp,获取头部高度
头部自定义时候,设置获取安全区域,可以用 uni.getSystemInfoSync();接口。 <view class"statusBar" :style"{height:statusBarHeightpx}"> let SYSuni.getSystemInfoSync(); let statusBarHeightref(SYS.statusBarHeight) …...
开发面试题-更新中...
探迹科技(腾讯面试官) 1.了不了解循环屏障 2.对于java中的线程冲突有多少了解(我要算1加到1亿) 3.mysql调优怎么调(我跟他讲了explain) 4.type中ref,range,const的区别 5.我有1亿的数据量&…...
【Jmeter】jmeter指定jdk版本启动
背景: 因权限问题,不能修改操作系统的环境变量或者因jmeter启动加载的默认jdk8版本低,需要指定jdk XX版本启动Jmeter 解决办法: 进入jmeter bin目录选择jmeter.bat,记事本编辑jmeter.bat, 在最前面添加 set MINIMAL_…...

数据处理利器:图片识别转Excel表格让数据录入变简单
在现代职场中,手动录入数据是一个耗时且容易出错的过程。无论是纸质文件、照片还是截图,繁琐的输入常常让人感到头疼。如何高效地将这些信息转化为电子表格,是许多职场人士面临的挑战。 为了解决这一问题,我们推出了图片识别转Exc…...
【WPF】中Binding的应用
在 WPF (Windows Presentation Foundation) 中,数据绑定是一种强大的机制,它允许你将用户界面(UI)元素的属性与各种数据源关联起来。这种关联可以是单向的、双向的或一次性的。WPF 的数据绑定支持多种数据源,包括普通对…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...

软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...
Python爬虫实战:研究Restkit库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...

RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...

PLC入门【4】基本指令2(SET RST)
04 基本指令2 PLC编程第四课基本指令(2) 1、运用上接课所学的基本指令完成个简单的实例编程。 2、学习SET--置位指令 3、RST--复位指令 打开软件(FX-TRN-BEG-C),从 文件 - 主画面,“B: 让我们学习基本的”- “B-3.控制优先程序”。 点击“梯形图编辑”…...