【Linux】磁盘与文件系统

news/2024/11/26 0:33:15/

目录

一、磁盘的物理结构

二、磁盘逻辑抽象

三、文件系统

1、Super Block

2、Group Descriptor Table

3、inode Table

4、Data Blocks

5、inode Bitmap

6、Block Bitmap

四、Linux下文件系统

1、inode与文件名

2、文件的增删查改

2.1、查看文件内容

2.2、删除文件

2.3、创建文件

2.4、补充内容

五、软硬链接

1、软链接

2、硬链接


一、磁盘的物理结构

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

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

 

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

 我们要读取指定数据,就需要先根据磁头编号确定使用哪一个盘面,再确定读取哪一个磁道,最后根据扇区的编号定位扇区即可。其中通过磁头(head)、柱面(磁道)(cylinder)、扇区(sector) 来定位扇区的方法称为 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 保存的是文件系统的所有属性信息,包括文件系统的类型、整个分组的情况。记录的信息主要有: bolck inode 的总量,未使用的 block inode 的数量,一个 block inode 的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。
 后面每一个 Block group 中可能都有一个这样的超级块,并且每一个超级快存储的数据都完全相同,统一更新。这样做的目的是防止超级块区域坏掉,如果出现故障,整个分区不可再被使用,因此要做好备份。

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下文件系统

使用 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 [目标文件] [软链接文件名称]

具体操作如下:

 使用 my-soft 链接了 myfile.txt  my-soft 是一个链接文件。

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

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

2、硬链接

建立硬链接指令:

ln [目标文件] [软链接文件名称]

 具体操作如下:

 使用 my-hard 链接了 myfile.txt  my-hard 是一个普通文件。

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

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

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

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

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

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


  现在查看一下根目录的硬链接数:

 硬链接数为 19 。根目录下的内容如下:

 一般来说,一个目录文件的硬链接数 -2 就是该目录下的目录个数


需要注意的是,用户无法自主给一个目录文件建立硬链接

 显示不能给目录建立硬链接。这是因为如果可以给目录建立硬链接,容易造成环路路径问题。OS没有把这个权限放给用户。


关于文件系统的相关内容就讲到这里,希望同学们多多支持,如果有不对的地方欢迎大佬指正,谢谢!


http://www.ppmy.cn/news/49100.html

相关文章

在poetry虚拟环境下打包exe

本博客介绍了在poetry虚拟环境下打包exe的流程,包含两个部分 打包的基本流程打包过程中遇到的问题 打包的基本流程 copy打包工具到本地,(share:\公用共享\芯片部\乔羽\img_generate\系统部提供的打包exe工具) 用poetry搭建虚拟环境 在打包…

延迟渲染 Deferred Rendering

前向渲染 先计算光照再裁剪。 前向渲染是现在最基础,也是最多引擎使用的标准。前向渲染的流程是给定一个几何体,引擎对其进行从顶点到像素着色器的一系列计算,然后输出到最终的图像缓冲区。场景中有多个几何体时,引擎就是对其挨个…

learn C++ NO.1——命名空间域、输入输出、函数重载

前言 什么是C C(c plus plus)是一种计算机高级程序设计语言,由C语言扩展升级而产生,最早于1979年由本贾尼斯特劳斯特卢普在AT&T贝尔工作室研发。C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的…

【react】react18的学习(四)--复合组件通信

上一篇:【react】react18的学习(三)–hooks组件 1、父子通信:props、ref 父传子:props 传给子组件状态数据;特殊地,props.children:将元素内容传给子组件;所以不要手动…

如何使用 Python 爬虫抓取动态网页数据

如何使用 Python 爬虫抓取动态网页数据 随着 Web 技术的不断发展,越来越多的网站采用了动态网页技术,这使得传统的静态网页爬虫变得无能为力。本文将介绍如何使用 Python 爬虫抓取动态网页数据,包括分析动态网页、模拟用户行为、使用 Seleni…

PID原理

PID控制器(比例-积分-微分控制器),由比例单元(P)、积分单元(I)和微分单元(D)组成。 可以通过调整这三个单元的增益Kp,Ki和Kd来调定其特性,PID控制…

注释和关键字

注释 注释概念 ●注释是在程序指定位置添加的说明性信息 ●简单理解:对代码的一种解释说明,方便我们程序员更好的去阅读代码 例如: public class HelloWorld {//这是通过class定义了一个类,类名叫HelloWorld public static voi…

学会这些Jmeter插件,才能设计出复杂性能测试场景

为什么要使用jmeter线程组插件呢? jmeter自带的线程组插件模拟的压测场景非常有限,当需要模拟复杂压测场景的时候,推荐大家使用jmeter线程组插件。 如何下载jmeter线程组插件呢? 早期版本的jmeter可以针对我们需要的扩展功能&a…