序言:

本文主要讲述的是ext2文件系统,ext3和ext4在ext2的基础上增加了日志系统,提升了管理的容量和性能等,但这三个文件系统的核心设计没有变化,我们将先从硬件介绍,再到文件系统。

Ⅰ、磁盘

磁盘作为一种外设,具有便宜,容量大,但读写速度慢的特点。

磁盘通过磁盘的高速旋转,磁头臂带着磁头的来回摆动来定位来通过磁头读取数据。

一、磁盘的存储结构

一个磁盘会有很多个盘面,每个盘面分为不同的磁道,每个磁道又分为不同的扇区,每个扇区可以存储512字节的数据,而磁盘的存储最小的结构不是扇区而是块,块是由八个扇区组成的共4KB(4096字节)。按照纵方向来看磁盘又可以分为不同的柱面。

二、CHS&&LBA

CHS分别是三个单词的首字母柱面(cylinder),磁头(head)和扇区(sector),CHS是磁盘区寻址的一种方式。它的思想是每个扇区要想找到它要靠定位柱面,磁头和扇区,柱面可以确定他在哪个磁道,磁头可以确定他在哪个盘面上,扇区可以确定他在磁道的哪个扇区上。这个我们就可以借助三维空间上描述一个物体的位置要靠x,y,z轴一样。

如果我们把每个柱面破开,变成一个三维数组,如果把每个磁道拼起来的话就变成了一个以为数组

LBA是操作系统看待数据不同的数据地址的一种方式,操作系统可以通过LBA的方式去找到对应的数据地址。当然CHS可以与LBA通过磁盘进行转化,这样操作系统可以给磁盘LBA地址然后磁盘转换成CHS地址去寻找,磁盘也可以把数据的CHS地址转换成LBA地址给操作系统。

这里补充一下:

扇区编号从1开始编号,其他的盘面,磁道,柱面等等都是从0开始编号

CHS转换LBA:

LBA = 柱面号C*(磁头数*每个磁道扇区数)+ 磁头号H*每个磁道扇区数 + 扇区号S -1

LBA转换CHS:

柱面号C = LBA / (磁头数*每个磁道扇区数)

磁头数H = (LBA%(磁头数*每个磁道扇区数))/每个磁道扇区数

扇区号S= (LBA%每个磁道扇区数)+1

有了CHS和LBA的相互转变了以后我们不再需要关心和记录CHS而是直接用LBA地址

Ⅱ、文件系统

在以前的博客里我们说过文件 = 属性 +内容,那么他们是如何去管理和存储的?下面我们先来宏观上理解文件系统,对于一个磁盘的容量都是很大的比如1TB我们应该如何去管理这些空间,我们可以先把他们分为不同的区,但一个区还是太大了,我们可以再把区分为不同的组。如果我们管理好一个组那我们就能管理好整个区,管理好整个区我们就能管理好整个磁盘。那么我们应该如何去管理好一个组的数据呢?那就需要管理部分,整个组被分为了管理部分和数据部分。

在这里我还要去补充一个知识:

我们在之前的博客中就说过inode是用来存储文件的属性信息的,那么这么多的文件管理信息如何去区分呢?其实每个inode都有一个编号来分辨他们。在linux中我们可以用 ls -li 来查看目录下文件的inode。

一、快组的管理信息

1、Inode Table

这里面放的是struct inode的表,inode里面存放的是文件属性(比如修改时间,所属者,文件大小等),每个inode在inode table里都有编号,inode的编号以分区为单位,统一编址,不可跨分区。也就是说在分区1里边有编号100,在分区2也可以有编号100,不同分区inode编号是可以重复的,但同一分区的不同组的inode编号是唯一的。

2、Inode Bitmap

Inode Bitmap是一个位图,它记录的是Inode编号的使用情况,当文件要被存放在磁盘中时,会先把Inode Bitmap先加载到内存把要添加文件的inode编号由0变1,再写回到磁盘中,最后再把数据写到磁盘上。

3、Data Block

这块空间用来存储数据,文件系统给每一个块都有一个编号,在每个分区里是统一编址,这个和inode一样不可跨分区。这里想说明一点LBA是每个扇区都有,而块号只有每个块(8个扇区)才有。它们之间也可以转换:块号 = LBA / 8 ,LBA = 块号 * 8 + 是块内第几个分区。

4、Block Bitmap

这个部分和inode bitmap是类似的,它也是一个位图记录block的使用情况,每次要对data block进行修改的时候先把block bitmap中数据块对应的编号的 bit 位进行修改后再进行对数据的写入。

5、GDT(Group Descriptor Table)

GDT(块描述符表),用来记录快组的属性信息,分区内的每个分组都有一个快描述符表,里面存储分组里各个部分的开始(Data Block,Block Bitmap,Inode Bitmap),记录Block Bitmap,Inode Bitmap还有多少空闲。

6、Super Block

Super Block(超级块),用来记录整个文件系统的属性信息,包括每个分区的inode和block的个数(每个分区的block和inode基本上个数都是一样的),和空闲的inode和block的个数等等。不是每个分组都有超级块,但超级块可能不止一个,每个超级块都是一样的内容一样的大小,为什么超级块不放在分区的前面而是放在分组里面?这是因为超级块存储的是整个文件系统的信息,如果丢失整个文件系统都无法正常工作,所以要对超级块进行备份存放在不同的分组里面,如果损坏可以用备份修复。

二、如何去找到一个文件?

1、路径解析

在inode中没有储存文件名的信息,在我们查文件的信息的时候会看见文件名,那么文件名是存在哪的?答案是存储在目录文件的内容数据中,ext2文件系统把目录文件看成和普通文件一样都有内容和 inode 编号。如果想要去找到一个文件必须要去它的目录文件中去寻找对应的inode编号再去寻找对应的文件。寻找一个文件要从根目录开始寻找起,根目录有固定的文件名和inode编号当开机的时候操作系统就会自动寻找到,那么我们当系统调用函数open的时候也没有把绝对路径写上去文件还是能够正常的打开和创造?因为我们会提供文件名函数内部会判断这个是绝对路径还是相对路径,如果是相对路径,函数会从进程中获取CWD拼接上去。

2、文件缓存

那么我们每一次去打开文件都要从根目录开始解析吗?当然不是这种效率太低了,在操作系统内部会维护路径缓存(一个多叉树),当我们打开一个以前没有打开过新文件的时候这个时候操作系统就会现在路径缓存中寻找如果没有找到,就会从根目录解析。下面我们来看一下struct dentry (路径缓存多叉树的节点)

每个节点不止属于多叉树这一种数据结构,它也属于哈希表,LRU等。

3、挂载分区

我们现在知道可以通过 inode 去确定它的分组和块,那么我们是如何去确定它的分区的呢?分区是文件系统的载体,每个分区只能有一个文件系统。什么叫挂载分区?一个磁盘在装上文件系统了以后我们是无法直接去使用它的,要它与一个目录相关联,这样我们去访问这个目录里面的内容和创建新文件才可以去使用这个磁盘。那么我们通过解析路径的前缀就可以判断它是属于哪个文件系统的从而判断哪个分区。

=========================================================================

本篇关于Linux的文件理解与操作的介绍就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持纠正!!!

Logo

纵情码海钱塘涌,杭州开发者创新动! 属于杭州的开发者社区!致力于为杭州地区的开发者提供学习、合作和成长的机会;同时也为企业交流招聘提供舞台!

更多推荐