0
点赞
收藏
分享

微信扫一扫

Apache 网站服务基础

waaagh 2024-06-17 阅读 37

W...Y的主页 😊

代码仓库分享 💕


前言:我们前面的博客中一直提到的是被进程打开的文件,而系统中不仅仅只有被打开的文件还有很多没被打开的文件。如果没有被打开,那么文件是在哪里进行保存的呢?那我们又如何快速定位一个文件的具体位置呢?话不多说,开始我们今天的旅程。

磁盘

说到文件的存储,我们先来了解一下磁盘的构成。

磁盘的机械构成

磁盘是计算机存储设备的一种,它用于存储和读取数据。磁盘的机械构成主要包括以下几个部分:

硬盘的工作原理是通过电机驱动盘片旋转,磁头臂移动读写头到正确的盘片位置,然后读写头通过改变盘片表面的磁性来存储或读取数据。这个过程需要非常精密的机械协调和电子控制。随着技术的发展,固态硬盘(SSD)逐渐取代了传统的机械硬盘,因为它们没有移动部件,读写速度更快,耐用性更高。

磁盘的物理存储

 

磁盘的物理存储主要是指硬盘驱动器(HDD)中数据的物理存储方式。

硬盘驱动器的物理存储方式依赖于磁头和盘片的精确协调。数据的读写是通过改变磁性颗粒的极性来实现的。

虽然说一个磁盘是一个圆形的物体,但是在上面存储的数据并不是杂乱无章的。其实磁盘上有很多同心圆——也叫磁道。而同心圆中的一小段被称作扇区,是磁盘IO的基本单位,但不一定是系统的基本单位,一般情况下大小为4kb或521字节。虽然扇区的面积不同,但是可以通过密度的调整让其扇区的大小都是一样的。

扇区、磁头、盘面、磁道都有自己的唯一编号,所以我们想要访问一个具体的扇区,首先我们先通过磁头定位到哪一个磁道/柱面,然后确认使用哪一个磁头进行读取(本质就是使用哪一个盘面),最后确认到哪一个扇区。这种在硬件层面上定位一个扇区被我们称为——CHS定位法。

磁盘的逻辑存储

磁带我们想必都见过,小学时使用的英语听力一般使用的就是磁带。磁带存储内容就是我们下图所看到的长条。当我们将磁带拉直像不像我们所学的一种数据结构——线性表。

 我们通过磁带来类比磁盘,如果我们将一个个扇区看作一段空间,将他们全部拼接起来不也就是线性表吗!假设一个磁盘有800GB内存,一个扇区所占空间是512字节,那么我们就可以看到下图:

所以我们对磁盘的管理,也就变成了对数组的增删查改!!!
但操作系统觉得一个扇区512字节太小,因为磁盘是一个硬件而硬件的速度是很慢的,磁盘IO太麻烦,所以OS就将文件IO定在4KB。操作系统会选择连续的8个扇区作为数据块,这样操作系统又会形成一个数组,大小为4kb的数据块。

 这样的操作系统也可以将自己的IO转换到磁盘中,4kb等于8个512字节,所以当数据块下标为1时,想要对应磁盘中的扇区只需要,1*8 + [0,1,2,3,4,5,6,7]即可一一对应。我们只需要知道起始扇区+偏移量就可以做到对应。

所以从此往后整个磁盘不会以扇区作为单位,而是以数据块作为单位,我们将数据块的下标叫做LBA地址。

系统对内容的管理

我们都见过Windows中的C盘D盘E盘等等,为什么要分这么多盘呢?因为系统要对我们的内存进行管理,如果800GB放一个盘中会比较大,不好进行管理,而且分盘可以对电脑的性能提升。所以我们要分区/分盘管理,Linux下也是如此。

分盘管理是将大的空间进行缩小化,磁盘的管理方式都是类似相同的,所以我们要把512GB内存管理好从而就进化到管理好256GB内存即可。但是256GB还是有些大,这时操作系统就会做一些我们看不到的事情——分组。

将256GB内存分成10GB左右更小的内存进行管理,这样我们的问题从如何管理好256GB转移到如何管理好10GB内存了。 

作系统中的内存分组是指操作系统将内存划分成多个逻辑组或分区,以便于更有效地管理内存资源。内存分组可以基于不同的标准,例如用途、访问频率、安全性等。

内存分组的好处包括:

  • 提高安全性:通过隔离不同区域的内存,防止恶意程序访问或修改其他程序的内存。
  • 优化性能:通过合理分配内存资源,可以减少内存碎片,提高内存访问速度。
  • 便于管理:分组管理使得操作系统更容易跟踪内存使用情况,简化内存分配和回收的过程。
  • 支持多任务处理:允许多个任务同时运行,每个任务都有自己的内存空间,提高了系统的多任务处理能力。
  • 提高可靠性:当一个程序崩溃时,分组管理可以限制错误的影响范围,减少系统崩溃的风险。

内存分组是操作系统内存管理的一个重要方面,它有助于提高系统的稳定性、安全性和效率。

那问题又来了,操作系统如何管理好分组中的内存呢?

理解文件系统

我们使用ls -l的时候看到的除了看到文件名,还看到了文件元数据。

[root@localhost linux]# ls -l
总用量 12
-rwxr-xr-x. 1 root root 7438 "9月 13 14:56" a.out
-rw-r--r--. 1 root root 654 "9月 13 14:56" test.c

每行包含7列:

ls -l读取存储在磁盘上的文件信息,然后显示出来 

 其实这个信息除了通过这种方式来读取,还有一个stat命令能够看到更多信息

[root@localhost linux]# stat test.c
File: "test.c"
Size: 654 Blocks: 8 IO Block: 4096 普通文件
Device: 802h/2050d Inode: 263715 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-09-13 14:56:57.059012947 +0800
Modify: 2017-09-13 14:56:40.067012944 +0800
Change: 2017-09-13 14:56:40.069012948 +0800

系统文件 = 属性 + 内容,那内容是可大可小的但是属性都是固定大小,他们被放在一个struct inode的结构体中进行存储,只能说他们的属性内容不同,但是大小一定是相同的,在Linux操作系统下规定固定大小为128字节。所以文件的属性和内容就要分开进行存储。

我们又回到刚才的问题,10GB的内容我们要怎么样管理?我们先来看一张图:

Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分组被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的。

而在系统中标识一个文件用的不是其文件名,而是其inode。

那我们就来认识一下文件系统图中的各个区域的含义:

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

i节点表(inode table):存放文件属性 如 文件大小,所有者,最近修改时间等。
inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。比特位的位置:第几个inode。比特位的内容:表示该inode是否被使用。
数据区(data blocks):存放文件内容。我们可以想象成数据区中是一个特别大的内存,内存中有非常多的4kb数据块,当我们想要存放数据时无非就是数据库使用的多少问题。
块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。比特位的位置:第几个数据块。比特位的内容:表示该数据块是否被使用。
 

那inode属性区怎么与block数据区进行关联呢?在属性结构体struct inode中有一个数组,数组中存放的就是这个文件在数据区中使用数据块的下标。所以无论是内容还是属性,只要找到inode就可以将全部信息获取到。而我们删除一个文件的内容,不会去删除inode table 与data blocks中的内容,只会删除位图中的内容,让后面来的文件进行覆盖即可。

inode是在整个分区内唯一的,而想要寻找一个文件的inode首先我们得确认在哪个分组中。每个分区中都有其起始编号和终止编号,我们只需要将inode进行范围比较即可确认在哪个分组中。然后再减去分组中的起始编号后就可以得到inode table。

现在又有一个问题,inode table中存放文件的属性,而文件的属性中又有一个block[15]数组用来存放数据块的下标,但是有的文件是非常大的15个位置15个数据块是不够的,那怎么办?实际上block数组中0~11是直接保存的数据块的编号,而12~13并不是保存数据块的编号而是保存其他数据块的编号,其他数据块是内容。而14保存的是其他数据块的编号,其他数据块也是指向更多的数据块编号。这样我们就可以存储非常大的文件编号了。

GDT,Group Descriptor Table:块组描述符,描述块组属性信息。
即全局描述符表(Global Descriptor Table),是x86架构的CPU中用于定义不同内存段的一块内存区域。GDT是操作系统用来实现内存保护、分页和多任务处理的关键组成部分。每个条目(Descriptor)在GDT中定义了一个内存段的属性,包括段的基地址、大小、访问权限等。
所以GDT是对一个块组整体做管理的管理数据结构。描述了起始LBA是多少、起始inode编号是多少、一共有多少个inode多少个数据块、已经使用了多少个inode和数据块、下一次怎么分配等等信息。

超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。整个分区是由super block进行管理的。而GDT是管理分区中的一个分组的数据结构。

还有一个Boot Block一般是在第一个分区才有,它是和开机有关系的。当开机时我们首先要识别磁盘,才可以将操作系统加载到内存中。我们可以简单理解为,了解整个磁盘的分区情况并且告诉操作系统在哪个分区中。

而这些文件信息不是在我们分区后就有的,而是在格式化后进行写入的。
我们可以在分区中写入相同或者不同的文件系统,以上的文件系统属于Ext*(2),现在我们用到的一般是Ext*(3)以上,但是核心原理是不变的。

文件系统中最核心的就是super block,所以操作系统在管理文件时就可以将每一个分组的super block加载到内存中建立一个数据结构进行管理,所以对文件的管理就进而转化成对super block的z增删查改工作。

现在我们已经知道文件系统的底层逻辑后,我们创建一个文件的逻辑是什么呢?

1. 存储属性
内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。
2. 存储数据
该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据
复制到300,下一块复制到500,以此类推。
3. 记录分配情况
文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。
4. 添加文件名到目录
新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。

因为目录也算文件,而任何一个文件都在目录中,那目录文件中就存放文件名和inode编号的映射关系,如果目录文件中没有写权限,我们就不能在目录中创建新的文件,因为它要修改目录文件内容。而差一个目录的内容都是从根目录开始的,因为它是从前一个目录中进行查找目录内容的,所以是逆向递归查找的。

一个inode是在一个分区中是唯一的,但是不知道其在哪一个分区。所以这时候我们的路径就出马了。一个文件写入文件系统的分区,要被Linux使用,必须要先把具有系统文件的分区进行“挂载”。一个文件系统所对应的分区挂载到对应的目录中我们才可以访问。所以分区的访问就是所挂载路径的访问。这里我们不讲什么是挂载,有兴趣的可以自己去学习以及mount指令。


以上就是我们本次的全部内容,感谢大家观看!!!

举报

相关推荐

0 条评论