【Linux】————磁盘与文件系统

作者主页: 作者主页

本篇博客专栏:Linux

创作时间 :2024年10月17日

一、磁盘的物理结构

磁盘的物理结构如图所示:

其中具体的物理存储结构如下:

磁盘中存储的基本单位为扇区 ,一个扇区的大小一般为512字节或者4kb,这里我们暂且认为是512字节。一般的磁盘,一个扇区都是512字节,同半径所有的扇区构成了一圈磁道

所以我们要读取指定文件数据的时候,要首先根据确定是哪一个盘面,其次再去确定是哪一个磁道,最后根据扇区的编号去定位扇区即可。其中通过磁头、柱面(磁道)、扇区确来定位扇区的方法叫做CHS定位法

一个普通文件包括属性 + 内容,本质上都是数据,占据一个或多个扇区,我们既然能够用 CHS 定位任意一个扇区,就能定位任意多个扇区,从而将文件从硬件角度读取或者写入。

二、磁盘逻辑抽象

我们已经知道如果OS可以得知CHS的地址,就能够访问任意一个扇区。但是由于OS是软件,磁盘是硬件,为了防止硬件发生迭代变化OS也要跟着变化,就要做好OS与硬件的解耦工作,因此OS内部使用的不是CHS的地址。

为了减少进行IO操作的频率,OS与外设进行IO操作的基本单位大小是4KB(可以调整)。就算只需要修改一个字节的数据,也需要把这个数据所在的4KB大小的数据都加载进内存,修改好后再统一写回磁盘,因此我们把磁盘称为块设备。OS需要有一套新的地址来进行块级别的访问。

把磁盘磁道看作一个连续的空间结构:

扇区就相当于连续的数组,此时定位一个扇区就只需要一个数组下标了。由于OS是以4KB为单位进行IO的,所以一个OS级别的文件块要包括8个扇区。OS不关心扇区的概念,计算机常规的访问地址是通过 起始地址 + 偏移量 的方式进行的,因此OS访问数据块时,只需要知道数据块的起始地址 + 4KB 就可以了,把数据块看作一种类型。

所以块的地址本质就是数组的一个下标N,以后就可以采用下标N的方式定位任意一个块了。这种寻址方式被称为 LBA ,即逻辑块地址。

获得 LBA 地址后,通过简单的数学计算就可以转换成磁盘的 CHS 地址。假如已知 LBA = 6500 ,磁盘一个磁面的大小为 5000 ,一个磁道的大小为 1000 。则其对应的地址是第 2 个磁面,第 6 个磁道,第 500 个扇区。

从此之后,对于磁盘的管理就被抽象成了对一个大数组的管理。

三、文件系统

由于磁盘很大,为了更加方便的管理,OS对磁盘块进行了分区。分区后再对每一个磁盘区域进行分组。具体结构如下:

在OS对磁盘进行分区时,会在最开始的位置设置一个Boot Block ,这段区域里面主要保存与OS相关的内容,比如分区表、镜像地址等等。一般而言这个分区存在于 0 号盘面的 0 号磁道的 1 号扇区。当用户开机时,OS会加载磁盘的驱动,读取磁盘的分区表,再从特定分区的开始位置读取到OS所在的地址,并加载OS,此时OS才算真正运行起来。

在之后是OS对每一个分区进行分组形成的诸多 Block group,即块组 。 每一个 Block group 都有上图所示的 6 块区域。

1、Super Block

Super Block****保存的是文件系统的所有的属性信息,包括文件系统的类型、整个分组的情况。记录的信息主要有:block和inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最后一次写入数据的时间,最近一次写入磁盘的时间等其他文件系统的相关信息。

2、Group Descriptor Table

GDT为组描述符,保存该组内的详细统计等属性信息。比如本组内从哪里到哪里是哪部分内容,本组被使用了多少等等。

3、inode Table

一般而言,我们把文件内部所有属性的集合叫做inode节点,一般大小为128字节。一个文件会有一个inode,一个分组内会有大量的文件,也有大量的inode节点,所以在组内会有一个专门的区域来保护这些inode节点,这个区域就叫做**inode Table,**也叫 inode 表。

在分组内部,每个inode表都有自己的inode编号,inode编号本身也属于对应文件的属性,Linux查找一个文件的时候,也是通过inode编号来查找的。

一个inode对应一个文件,该文件的inode属性和该文件对应的数据块是有映射关系的

4、Data Blocks

文件的内容是变化的,用数据块来进行保存。所以要保存一个有效文件的内容,就需要 n 个数据块。如果有多个文件就需要多个数据块。这些数据块所在的区域就是 Data Blocks 。一个数据块的默认大小是 4KB 。

Linux查找一个文件,首先找到该文件的inode。 在inode结构体内部有一个int blocks[NUM] 数组, 数组内记录了存储该文件内容的数据块的地址。一个分组中,百分之95以上的内容都是 Data Blocks 。

当操作系统要加载一个文件时,只加载该文件的 inode 节点。而 inode 节点中包含该文件内容数据块的映射关系,想要访问哪部分内容,就根据映射关系把哪一部分内容加载到内存中。

5、inode Bitmap

inode Bitmap 是一个位图结构,每个bit表示一个 inode 是否空闲可用。

6、Block Bitmap

Block Bitmap 是一个位图结构,记录着 Data Block 中哪个数据块已经被占用,哪个数据块没

有被占用。

四、Linux下文件系统

在Linux中,使用 ls 指定加上 -i 命令选项,就可以观察到文件的 inode :

1、inode与文件名

Linux系统只认inode值,且inode属性中不会包含文件名,因为文件名只是提供给用户看的

任何一个文件一定存在于目录中,目录其实也是一个文件,也有自己的inode值和对应的数据块,目录的数据库块里保存的是该目录的文件名和inode值对应的映射关系,而且在目录内,文件名与inode编号互为key值

inode number 在一个分区内唯一有效,不能跨分区使用。根据inode number可以确定该文件在当前分区的哪一个分组。

2、文件的增删查改

2.1、查看文件内容

当用户访问一个目标文件的内容时,一定是在特定目录下访问的,具体流程如下:

  1. 先要在当前目录下找到目标文件的 inode number 。
  2. 一个目录也是文件,也隶属于一个分区,在该分区中通过目标文件的 inode number 找到分组,在该组的 inode Table 区域找到目标文件的 inode 。
  3. 通过目标文件的 inode 与对应 Data blocks 的映射关系,找到该文件的数据块,加载到OS,最后显示在显示器上。
2.2、删除文件

当用户删除一个目标文件时,具体流程如下:

  1. 在当前目录下,根据文件名找到目标文件的 inode number 。
  2. 根据 inode number 找到目标文件的 inode ,结合与对应 Data blocks 的映射关系,把 block bitmap 对应的比特位设置为 0 。
  3. 根据 inode number 把 inode bitmap 对应的比特位设置为 0 。
2.3、创建文件

当用户创建一个目标文件时,一定是在一个目录下创建的。具体流程如下:

  1. OS在目录所处的分组里扫描 inode bitmap ,找到空余的位置并设置为 1 ,获得 inode number 。
  2. 把该文件创建出来后的默认属性填充到对应的 inode 中。
  3. 在当前所处的目录文件的 Data blocks 里追加一条新的文件名与 inode number 的映射关系。
2.4、补充内容

上面的内容包括分区、分组、填写系统属性等等,这些工作都是OS做的。分区完成之后,为了让分区能够正常使用,需要对分区做格式化操作,即OS向分区写入文件系统的管理属性信息,并做区域划分工作。如果区域划分之前已经做好了,那么格式化操作把位图结构清空,把属性字段设置为初始状态就可以了。

文件系统给 inode 与 Data blocks 建立映射关系通过数组来完成,由于 Data blocks 很大,为了能够映射的过来,数组采用了直接索引、二级索引、三级索引的方式来完成映射,因为不是重点内容,仅作了解,不作讲解。

文件系统中,有可能出现 inode 没用完,Data blocks 用完了。或者 inode 用完了,但是 Data blocks 还有剩余的情况。比如只建立一个文件,然后不断地往这一个文件中塞入数据,消耗 Data blocks。或者不断地建立空文件,消耗 inode 。这种问题目前是没有办法解决避免的。

五、软硬链接

1、软链接

建立软链接指令:ln -s [目标文件] [软链接文件名称]

使用code-soft 链接了codecode-soft 是一个链接文件

观察到 code-soft 与 code.c的 inode number 不同,这说明**软链接是一个独立的链接文件。有自己的 inode number,必有自己的inode属性和内容。**软链接的内容是自己所指向的文件的路径。可以让用户快速的找到目标文件。

**软链接的具体用法是:**如果一个目标文件的路径非常深,我们每次访问目标文件都要写一遍很长的路径,效率不高。此时就可以使用软链接在工作目录制作一个软链接文件,以方便访问目标文件。类似 Windows 系统中的快捷方式。

2、硬链接

建立硬链接指令:ln [目标文件] [软链接文件名称]

具体操作如下:

使用 code-hard 链接了code.c。 code-hard 是一个普通文件。

观察到 code-hard 与code.c的 inode number 相同,这说明硬链接与原文件是同一个文件,硬链接只是建立了新的文件名与老的inode number的映射关系,只修改了当前目录的内容。

code-hard 与 code.c 的硬链接数都变成了 2 。意思是此时有两种方法可以找到该文件,分别对应两个文件名。硬链接数,本质是一种引用计数。

现在我们使用指令 unlink 来删除硬链接:

此时文件的硬链接数又变成了 1

接下来我们再创建一个目录文件,观察硬链接数:

可以看到目录文件的默认硬连接数是 2 。这是因为目录文件天生拥有两个硬链接,一个是它本身的名字,另一个是在该目录内部的 " . " 符号。如果目录文件的内部还有目录文件,那么该目录文件的硬链接数就变成了 3 :本身的名字、该目录内部的 " . " 符号、该目录内部的目录内的 " .. " 符号:

Linux中不允许对目录进行硬链接

3、为什么要有硬链接

一、文件备份与冗余

  1. 提供额外的文件访问路径:创建硬链接后,多个文件名可以指向同一个文件的 inode(索引节点)。这意味着可以通过不同的路径名来访问同一个文件内容。如果一个路径名被意外删除或损坏,仍然可以通过其他硬链接路径访问文件,起到了一种备份的作用。
  2. 增加文件的可靠性:在一些关键应用场景中,通过创建硬链接可以确保文件在多个位置都能被访问,降低了因单个文件名丢失或损坏而导致数据丢失的风险。

二、文件管理与组织

  1. 方便文件共享:多个用户或程序可以通过不同的硬链接路径同时访问同一个文件,无需复制文件内容,节省了磁盘空间和时间。例如,在一个团队项目中,不同的成员可以通过各自的工作目录中的硬链接来访问共享的文件,实现文件的协同操作。
  2. 简化文件结构:可以使用硬链接来组织文件系统,使得相关的文件可以通过多个路径进行访问。这对于一些复杂的文件系统结构或需要灵活访问文件的情况非常有用。

三、与传统文件系统的兼容性

  1. 与旧有系统和工具的兼容性:许多传统的文件系统工具和应用程序都能够理解和处理硬链接。这使得在从旧系统迁移到 Linux 或在不同的文件系统环境中工作时,能够继续使用熟悉的文件管理方式。
  2. 稳定性和可靠性:硬链接的实现基于文件系统的底层结构,相对稳定可靠。不像某些高级文件系统特性可能会在不同的操作系统版本或文件系统实现中存在差异,硬链接在大多数情况下都能提供一致的行为。

六、动静态库

动静态库的本质就是可执行程序的"半成品"。
一段代码生成一个可执行程序需要以下的四个步骤:

  1. 预处理:完成头文件的展开,去掉注释,宏替换,条件编译等,最终形成xx.i文件
  2. 编译:完成语法分析,词法分析,语义分析,符号汇总,检查无误后将代码编译成汇编指令,最终形成xx.s文件
  3. 汇编:将汇编指令转换成二进制文件,xx.o文件
  4. 链接:将生成的各个.o文件进行链接,最终形成可执行程序

详细内容在下一篇文章中......

最后:

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1.一个冷知识:
屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。

2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。
正所谓:君子可内敛不可懦弱,面不公可起而论之。

3.成年人的世界,只筛选,不教育。

4.自律不是6点起床,7点准时学习,而是不管别人怎么说怎么看,你也会坚持去做,绝不打乱自己的节奏,是一种自我的恒心。

5.你开始炫耀自己,往往都是灾难的开始,就像老子在《道德经》里写到:光而不耀,静水流深。

最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!

相关推荐
运维老司机3 分钟前
Jenkins修改LOGO
运维·自动化·jenkins
D-海漠19 分钟前
基础自动化系统的特点
运维·自动化
我言秋日胜春朝★27 分钟前
【Linux】进程地址空间
linux·运维·服务器
繁依Fanyi1 小时前
简易安卓句分器实现
java·服务器·开发语言·算法·eclipse
C-cat.1 小时前
Linux|环境变量
linux·运维·服务器
yunfanleo1 小时前
docker run m3e 配置网络,自动重启,GPU等 配置渠道要点
linux·运维·docker
m51271 小时前
LinuxC语言
java·服务器·前端
运维-大白同学1 小时前
将django+vue项目发布部署到服务器
服务器·vue.js·django
糖豆豆今天也要努力鸭2 小时前
torch.__version__的torch版本和conda list的torch版本不一致
linux·pytorch·python·深度学习·conda·torch
烦躁的大鼻嘎2 小时前
【Linux】深入理解GCC/G++编译流程及库文件管理
linux·运维·服务器