【linux】linux基础IO(五)深入理解文件系统
小编个人主页详情<—请点击
小编个人gitee代码仓库<—请点击
linux系列专栏<—请点击
倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己!
目录
前言
【linux】linux基础IO(四)(模拟实现c语言文件标准库fopen,fclose,fwrite,fflush)——书接上文 详情请点击<——,本文会在上文的基础上进行讲解,所以对上文不了解的读者友友请点击前方的蓝字链接进行学习
本文由小编为大家介绍——【linux】linux基础IO(五)深入理解文件系统
一、共识原理
- 文件分为打开的文件和没有被打开的文件,在下面的文章中小编讲解了打开的文件
- 【linux】linux基础IO(一)(c语言文件接口、文件系统调用open,write,close、文件fd)详情请点击<——
- 【linux】linux基础IO(二)(文件的重定向,dup2的使用,给shell程序添加重定向,如何理解一切皆文件)详情请点击<——
- 【linux】linux基础IO(三)(用户缓冲区概念与深刻理解)详情请点击<——
- 【linux】linux基础IO(四)(模拟实现c语言文件标准库fopen,fclose,fwrite,fflush)详情请点击<——
- 如果文件没有被打开呢?我们已经知道没有被打开的文件是在磁盘上进行存储,那么我们又该如何研究磁盘上没有被打开的文件呢?通过如下四点
- 路径问题
- 存储问题
- 获取问题(文件属性+文件内容)
- 效率问题
- 文件 = 文件属性 + 文件内容 ——> 那么在磁盘上存储文件的本质就是存储文件的属性和文件的内容
- 文件的属性其实被放置在inode上,文件的内容其实是被放置在数据块上(关于inode和数据块,小编后面会进行讲解),那么我们可以得出linux中的文件在磁盘中进行存储是将文件属性和文件内容分开存储的
- 那么下面我们就来认识一下磁盘
二、认识硬件——磁盘(物理结构)
- 在正式讲解磁盘前,小编先勾起一下大家的回忆,相信不少人和小编一样都是00后,那么大约在08年,09年的时候,相信屏幕面前的大多数人都使用过光盘通过影碟机去放映电影电视剧等
- 如上便是光盘的正反面,光盘的正面通常是印刷的黑白或彩色的图案,光盘的正面不是我们关注的重点,我们关注的重点是光盘的反面,光盘的反面是光滑的,光盘通过影碟机放映电影电视剧,影碟机不能存储数据,存储数据的是光盘,光盘的正面通常是印刷的黑白或彩色的图案无法存储数据,即光盘只有的光滑的这一面是用来存储数据的
- 磁盘是计算机(仅考虑台式计算机,不考虑笔记本)外设(硬件)中唯一的一个机械设备,同时也是一个外设,磁盘是永久性存储介质,下面就是磁盘的一张图,即磁盘的物理结构
- 磁盘是类似于光盘的,只不过磁盘是两面光滑的,一般的磁盘中都会有三张盘片,这三张盘片的两面均是光滑的,也就是说一般的磁盘一共有六面光滑的面,每一面都会对应一个磁头,因此有六个磁头,既然光盘可以存储数据,那么同样的磁盘也可以存储数据,一张磁盘相对于内存价格低,存储空间非常大,有利也有弊,相反的磁盘存储速度效率较低
- 我们继续观察,盘片的中间是主轴,下面有马达,因此在主轴以及马达的运作下,盘片的运动是顺时针或逆时针转动的,本文小编暂时考虑盘片的运动是顺时针转的(三个盘片同时顺时针转动),同时磁头是借助于磁力臂悬浮于盘片的上面,磁力臂控制磁头左右移动(六个磁头同时左右移动),需要特别注意的是虽然盘片看起来好像是光滑的,但是实际上拿放大镜观察盘片的表面是不光滑的,有很多密密麻麻的小突起
- 这些小突起其实是磁性物质,磁盘磁盘那么必然和磁力有关,我们知道计算机的底层只认二进制序列,同时磁盘是计算机的外设,外设要和计算机进行IO,那么也就意味着外设必然也要通过某种方法或手段认识或表征二进制序列,磁盘也是外设,所以磁盘也就必然要表征二进制序列,我们知道上图的吸铁石有南北极SN,那么对于盘片上的磁性物质,我完全可以初始时让盘片上的磁性物质的上表面全部为北极N用来表征二进制序列中的0,如果有需要那么完全可以通过某种电磁手段让盘片上的磁性物质的上表面的通过磁力臂上的磁头更改为南极S用来表征二进制序列中的1,所以此时磁盘就可以通过更改盘片上的磁性物质的南北极来表示二进制序列,二进制序列也就是数据,所以磁盘就因此可以存储数据了
- 因此为了保证磁盘数据不丢失,即保证不破坏盘片表面的磁性物质表征的二进制序列,那么也就必须要保证磁针和盘片不接触,计算机分为台式机和笔记本,笔记本轻巧适合移动,台式机不适宜移动,台式机上是有磁盘的,由于必须保证磁针和盘片不接触,所以台式机天然不适合频繁移动位置,如果台式机经常移动碰撞,那么磁针是左右移动,盘片是顺时针转动,在移动或碰撞的惯性下,那么有几率磁针和盘片是或产生碰撞接触的,那么此时光盘表面的磁性物质就有可能会被更改,缺失等等,那么由于磁性物质表征着二进制序列,这些二进制序列也就是磁盘存储的文件数据,此时大概率电脑开机就会出现上图文件丢失的情况,很麻烦,而笔记本完全不怕,因为笔记本搭载的是SSD固态硬盘,SSD固态硬盘无机械转动部件,抗震动,抗冲击,因此耐用性更好,寿命相较于机械设备磁盘更高,值得注意的是磁盘是机械设备,当我们每次更改删除修改文件的时候,都要对应的使用磁头更改磁盘上盘片的磁性物质的南北极,当更改的次数到达一定限度可能就无法进行更改了,即磁盘失去存储数据的能力,此时磁盘就失效了,但是理论上来讲磁盘的使用寿命在3万小时以上,即5到10年,所以这点我们大可不必担忧
- 由于磁盘价格便宜,存储空间大,大公司里面通常还有会机房,由于大公司里面要存储大量的数据,为了价格考虑,这些机房的存储设备大部分都是磁盘,机房的磁盘设备通常是一旦运行就一直进行运行,直达到磁盘的使用年限或者出现问题的时候磁盘才不再使用,当磁盘不再使用的时候,这时候大公司就需要将磁盘进行销毁,这里的销毁可不是指将磁盘卖掉,因为磁盘上存储的可是用户的数据的,如果直接将磁盘进行卖掉,那么可能会造成用户信息泄漏,通常使用磁盘厂家提供一些技术手段进行软件擦除磁盘数据
三、磁盘的存储构成
- 下面我们具体探索一下磁盘的存储构成
- 通过上图,其实磁盘中的盘片是由一圈一圈的磁道构成,不同盘面上的圆形磁道,同一半径的磁道其实立体来看就形成了柱面,而磁道被划分为很多的扇区,扇区的大小是512字节或者是4KB,本文仅讨论扇区大小是512字节的情况,那么此时我们就可以说:磁盘被访问的最基本单元是扇区
- 此时我们可以将磁盘看作由无数个扇区构成的存储介质
- 如果我们想要将数据存储到磁盘,那么第一个问题就是要找到扇区,要找到扇区就要先找到扇区所在的磁道,要找到磁道就要先找到磁道所在的盘面,而如何定位盘面呢?我们知道一共有六个盘面,每一个盘面都对应有一个磁头,因此定位盘面的就转化为了定位磁头,也就是进行使用某一个磁头的电磁操作盘面,这样就达到了定位盘面
- 因此我们可以总结如何找到扇区?定位哪一个盘面(本质就是定位使用哪一个磁头),定位哪一个磁道(相同半径的磁道组成柱面,本质就是定位哪一个柱面),定位哪一个扇区,因此这种方法通常称作CHS寻址方式(C:Cylinder柱面,H:Heads磁头,S:Sector扇区)
- 此时我们再拿磁盘的物理结构来看就会有新的理解,看一下盘片和磁头的机械运动,磁头进行左右移动本质是定位磁道/柱面,盘片进行顺时针转动本质是定位扇区,并且使用某一个磁头进行电磁操作定位某一个盘面,这样就达到了CHS寻址方式
- 所以这时候针对磁盘的机械运动的干了什么我们就有了新的理解,并且思考一下这种设计模式,如果是要在磁盘上进行存取数据定位扇区,机械运动的越多,那么效率就越低,机械运动的越少,那么效率就越高。所以在软件设计上进行存放数据,设计者一定会有意识的将相关数据放在同一个区域,因为取出这个数据再去取它相关数据的可能性会很大,例如连续访问数据,根据数据下标进行连续访问的情况
四、磁盘的逻辑结构
- 在认识磁盘的逻辑结构前,小编先介绍一下盒式磁带,同样是大多数00后小时候都会接触的盒式录音机,小编记得大概在小编5年纪的时候,小学英语老师就是用盒式录音机给我们放英语听力
- 将盒式磁带放入盒式录音机中可以复刻出声音,我们观察其实盒式磁带中有两个滚轴,这两个滚轴上有卷起的一圈圈的磁带,正是因为有这些磁带,才可以保存数据进而盒式收音机才可以播放声音,即将盒式磁带正面放入收音机播放后,此时磁带就从一个滚轴到了另一个滚轴,那么想要播放一遍之后,如果想要播放第二遍,需要倒带,即将盒式磁带的反面放入盒式录音机,再从盒式磁带富有磁带的滚轮处继续开始播放,其实磁带上保存着数据,滚动滚轮,本质就是让盒式收音机从磁带上获取数据,进行播放,此时小编也完全可以不要这个盒式磁带,将盒式磁带中的磁带全部抽离出来,拿着这个磁带按照磁带的顺序依次按到盒式录音机上读取磁带数据的位置进行播放,这也同样完全可以
- 小编引入上面盒式磁带以及盒式录音机是为了说明什么呢?其实主要是想要讲解到将盒式磁带中的磁带抽离出来,将这个磁带进行拉直成为一条直线,那么此时这个直线上就存储着数据
- 同样的回归到我们讲解的磁盘,以上图为例进行讲解,那么对于磁盘中的盘片,对于盘片,对于一个盘片两面的盘面我们可以看作由无数个一圈一圈半径不同的磁道组成,而盒式磁带中的磁带就是一圈圈缠绕在一个滚轮上,既然小编可以将磁带拉直,那么同样的,小编也可以将一个盘面上一圈一圈半径不同的磁道拉直抽象成一条直线,此时一个盘面我们可以将一圈一圈的磁道抽象成一条直线,那么对于磁盘中的三个盘片对应的六个盘面我们同样可以一并将一圈一圈的磁道拉直拼接形成一个更大的直线
- 小编前面讲过,可以将磁盘看作由无数个扇区组成的存储介质,一个一个的扇区组成一个磁道,既然盘面上的一圈一圈磁道已经被小编抽象成了一条直线,那么小编针对这个直线再细分一下,就可以依据扇区组成磁道,给这个直线继续抽象出来一个一个最基本的单位扇区,扇区的大小是512字节,此时在逻辑上不就类似于基于扇区的一个数组了,此时小编就将磁盘的物理结构进行抽象,小编将磁盘延展开,在逻辑上,我看磁盘是线性的,因此就有了如下的磁盘的逻辑结构图(线性的),并且还可以通过信息进行一系列计算,将逻辑扇区地址转换为物理地址,即将LBA地址转换为CHS地址
五、回归到硬件
- 其实不仅仅CPU有寄存器,其它设备(外设也有),磁盘也有,例如控制寄存器,数据寄存器,地址寄存器,状态寄存器等
- 如果CPU或者操作系统想要与磁盘进行交互,首先需要向磁盘发送一些信号指令,例如向控制寄存器中发送信号,表示进行w,那么此时就是数据从内存写到磁盘上,此时会将内存要写入数据对应区域的起始地址放入磁盘的数据寄存器中,地址寄存器中则存放LBA地址,即逻辑扇区地址,此时在磁盘就会拿到逻辑扇区地址,通过一系列转换算法,将LBA地址转化为CHS地址,进而就可以通过CHS地址定位磁盘的扇区了,即对应哪一个磁头,对应哪一个磁道,对应哪一个扇区了,此时就会向该扇区进行写入数据,此时进行写入数据,磁盘的状态寄存器显示未就绪,此时操作系统就会检测状态寄存器,此时状态寄存器为未就绪,那么此时进程就会等待磁盘进行写入,即此时进程会进入阻塞状态,等待一会儿,磁盘写入成功了,那么磁盘的状态寄存器就为就绪,此时经过操作系统检测磁盘对应状态寄存器的状态为就绪,此时进程就从阻塞状态转为运行状态,那么此时数据就向磁盘中的LBA地址转化后的CHS地址对应的扇区写入成功了
六、文件系统
- 如下便是linux中的虚拟文件系统,通过这个虚拟文件系统就可以将磁盘很好的管理起来,虚拟文件系统的区域对应着前面小编讲解的LBA地址,不同区域对应着不同的LBA地址,通过LBA地址进而可以去访问磁盘,实际上LBA地址对应的逻辑扇区数组中单个数组下标对应的并不是磁盘中的一个扇区,而是8个扇区,一个扇区的大小是512MB,8个扇区的大小是4KB对应一个块
- 前面小编为了大家好理解将LBA地址对应为扇区进行讲解,因此今后我们要知道LBA地址对应的数组下标对应的内容实际上是一个块,这个块的大小是4KB,并且我们在虚拟文件系统的视角看待磁盘的最小单位并不是以扇区为最小单位进行看待,而是以一个一个的块为基本单位组成磁盘,将多个扇区连起来组成一个块为基本单位访问磁盘,这样的好处就是一次性可以访问更多的数据,管理更多的数据,并且提前进行缓存,提高内存缓存效率,因为相关的数据都是被设计者连续放置的,当我们访问数据后,很大概率会访问和他相关的数据,这样做可以提高内存的缓存效率,提高操作系统的效率
- 如何管理?磁盘的存储空间很大,这里小编就假设为800GB,要一下就将800GB直接管理起来很困难,但是我们可以进行间接管理,就像中国一样,虽然中国很大,但是我们可以将中国划分为诸多省份进行管理,省份再进行划分为诸多市进行管理等,同理磁盘的管理也是这样的道理,我们可以通过虚拟文件系统将磁盘管理起来
- 上文我们已经可以通过逻辑结构将磁盘抽象成线性的结构,同样的,这里我们也可以将磁盘的六个盘面抽象成一个线性的结构,虽然磁盘的800GB很难管理,但是我们可以借鉴中国区域划分的管理方式,将磁盘的800GB空间进行划分为不同的区,只要我们将区管理好了,那么这800GB的磁盘空间也就管理好了,如上,小编已经划分为不同的分区了,实际上是使用的一个partion结构体,存储了分区的起始和结束对应的LBA地址,LBA地址是整数级别的,所以可以使用int来存储,此时我们可以使用part结构体将不同分区的partion结构体存储起来进行管理
- 进行划分分区仅仅是在逻辑上进行划分,即使划分的区域跨盘面也无所谓,因为物理空间上盘面并没有改变,我们访问的方式仍然是使用LBA地址转化后的物理地址,即CHS对应的扇区,去进行访问或修改磁盘对应扇区的数据,注意,虽然我们从虚拟文件系统的角度看待磁盘认为磁盘是以块为基本单位进行划分的,但是我们应该知道实际上,磁盘在物理结构上仍然是以扇区为基本单位组成的
- 虽然将800GB进行分区管理了,第一个分区被划分了200GB,对我们来说200GB仍然很大,如何做呢?很简单,再划分不就是了,我们可以将200GB再进行分组,划分为20组10GB的空间进行管理,此时我只需要将一个10GB的空间管理好,那么就可以采用同样的方法去管理剩下的19组10GB的空间,当我将这20组10GB的空间都管理好的时候,那么200GB的空间就管理好了,那么我再使用管理200GB这个分区的方法和手段去管理剩下分区,这样800GB对应的所有的分区就被我管理好了,此时800GB磁盘就被我管理好了
- 此时问题就又来了,如何管理好分组的10GB空间呢?那么此时就需要使用到linux ext2文件系统进行管理了
- 首先看linux ext2文件系统的左上角的Boot Block叫做启动块,它是用来存储磁盘分区信息和启动信息的,接下来看Block group 0到Block group n其实就是我们所划分的组,以第一个Block group0第一个组为例进行讲解
- 首先看最右边的Data blocks数据块,它是用于存文件内容的区域,以块的形式呈现,常见的是4KB大小,同样也是文件系统的块大小,文件系统的所有分区的所有的组都是以块为基本单位组成的,一般而言数据块中只存储当前文件的数据,并不会存储其它文件的数据
- 接下来看数据块的左边的inode table叫做inode表,实际上是一个inode结构体数组,数组中存储的是一个一个的inode,inode是一个结构体,inode是用于存储单个文件的所有属性,大小是128字节,通常来讲是一个文件对应一个inode,在磁盘中有很多文件,因此同样的也有很多的inode,每一个inode都有唯一对应的编号,使用 ls -l -i 中的i选项可以查看文件的inode对应的编号,如下图最左侧的788126就是test.txt的inode对应的唯一编号,在linux中,文件的属性是不包括文件名称的,linux系统中标识文件使用的是inode编号
- 通过inode和数据块我们就可以将文件的属性和数据存储起来,并且也可以印证前面小编提前铺垫的话,linux的文件在磁盘中存储,是将属性和数据分开存储的,可是仅仅是将数据和属性分开存储还不行,数据和属性之间必然有某种关联,换言之,inode和数据块之间必然有某种联系,是的,inode和数据块之间是存在某种联系的,下面就由小编带领大家探索一下,inode和数据块之间的联系
- 如上便是inode和数据块之间的联系,数据块其实空间很大,上图的右下角就是小编放大的数据块图,它里面有一个一个大小为4KB的数据块,每一个数据块都有对应的唯一编号,一个分区内的所有分组的数据块的编号是一整套,即从0开始,到n结束,0对应第一个分组的第一个数据块的下标,n对应最后一个分组的最后一个数据块的下标,数据块很呆,没有自己的思想,别人想访问数据就访问数据,想修改数据就修改数据,别人让数据块做什么数据块就做什么,此时我们看向inode表,inode表中存储着一个一个的inode结构体,inode结构体中有文件的全部属性,inode结构体的大小是128字节,同样也包括inode对应的编号,最重要的是inode中存储着一个数据块编号数组,数据块编号数据中存储着15个数据块编号,0到11共有12个位置,是直接索引,即其中存储的就是存储着文件内容的数据块的下标,通过直接索引可以访问存储着文件内容的数据块,可是如果文件很大,直接索引对应的数据块存储文件的内容存储满了,此时又该如何做呢?
- 答案是继续向下去找二级索引,二级索引对应的数组下标是12,13,二级索引对应数组下标中存储的是存储有数据块块号的数据块,没有听错,数据块中存储着数据块块号,通过数据块中存储的数据块块号找到对应的存储着文件内容的数据块进行访问,小编粗略的给读者友友估算一下,二级索引有12,13两个数组下标对应的存储着数据块编号的数据块,一个数据库的大小是4KB,两个数据块的大小是8KB,数据块编号是整数,一个整数的大小是4字节,那么两个二级索引12,13其中存储的是数据块块号,那么12,13两个二级索引对应的索引的空间大小有8 * 1024 / 4 * 4 * 1024 = 8,388,608字节,此时8,388,608 / 1024 = 8,192 KB,8,192 / 1024 = 8 MB,二级索引有两个12,13,那么也就是一个二级索引可以索引4MB的空间,此时两个二级索引就可以二级索引到8MB的数据块空间进行存储文件内容,可是小编,小编,我要存储的文件真的很大,已经超过了直接索引和二级索引所能存储的文件内容了怎么办,没事,此时小编要请出索引的王了——三级索引,是的你没有听错,三级索引只有一个数据下标14,二级索引中对应的数据块中,由于数据块中存储的是数据块的编号,所以每一个二级索引对应的数据块中存储的每一个数据块编号对应的都是一个一级索引,三级索引虽然只有一个数组下标14对应的存储着块号的数据块,但是三级索引对应存储着块号的数据块中存储的块号对应的数据块每一个都是二级索引,一个二级索引可以索引4MB的空间,那么三级索引虽然只有一个数组下标14对应的存储着块号的数据块,同样的小编还是带领大家粗略的算一下,三级索引对应的数据块只有一个,此时我们计算一下三级索引对应的存储数据块块号的个数,,4 * 1024 / 4 = 1024 个数据块块号,那么1024个数据块的块号每一个块号对应的可都是二级索引啊,一个二级索引对应的可以索引的数据块的存储空间大小是4MB,那么此时1024个二级索引对应的就是4 * 1024 / 1024 = 4GB,足足4GB的空间,给文件内容用4GB的空间通常来讲都是够用的
- 此时小编便为读者友友打通了inode和数据块的关系,每一个分区内的inode的编号都是从0开始的,即不同分区的inode编号很大概率会有重复,如何解决呢?那么就是通过linux中的文件路径进行区分不同分区,类似于windows中的分盘一样,如下图,电脑被分为D盘,E盘,C盘等,其实向底层看,哪有什么D盘,E盘,C盘,仅仅有的是一块存储空间很大的SSD固态硬盘罢了,将SSD固态硬盘进行分盘处理同样也类似于我们linux中对磁盘空间进行管理的虚拟文件系统上进行的分区处理,D盘,E盘,C盘有不同的路径可以进行区分进而访问其中的文件,同样的虽然linux中不同分区的inode编号可能一样,但是通过linux中文件的文件路径进行区分不同分区,进而就可以通过inode编号找到文件对应的inode结构体,从这个inode结构体中访问文件属性,再通过ionde结构体中的数据块数组访问数据块,即访问数据块中存储的文件内容,但是ionde结构体中的文件属性以及数据块中的文件内容仅仅是虚拟文件系统中虚拟出来的,实际的数据,也就是文件的属性以及文件的内容还是存储在磁盘上的指定盘面,指定磁道,指定的扇区上的,如何关联起来,那么就是通过LBA地址,LBA地址对应的是分块的,一个块的大小是4KB,上述linux虚拟文件系统中的种种结构在都可以存储在LBA地址对应的一个一个的块上,也就是说inode以及数据块都有对应的LBA地址范围,我们拿到了LBA地址之后,交给磁盘的地址寄存器进行一系列算法转化为对应的物理地址,即CHS地址就可以去访问指定盘面,指定磁道,指定的扇区上的数据了
- 那么有这么多的数据块,我又该如何知道这些数据块中那些被使用,那些没有被使用呢?
- 那么就通过Block Bitmap数据块位图即可,数据块位图中比特位的位置和数据块块号对应起来,比特位的位置上的内容表示对应的数据块有没有被使用
- 同样的inode编号也很多,我怎么样才能知道inode编号对应的inode有没有被使用呢?一样的道理,通过inode Bitmap即inode位图即可,inode位图中比特位的位置和inode编号映射起来,比特位的位置上的内容表示inode编号是否有效,如果有效那么就去inode表中去找对应inonde进行访问
- 那么当要删除一个文件的时候,要不要将inode中的文件属性置为初始值,将数据块的文件内容清空呢?实际上是没有必要的,因为无论是文件的属性还是数据块的文件内容进行初始化写入的时候都是采用的覆盖写,所以没有必要将将inode中的文件属性置为初始值,将数据块的文件内容清空,那么如何标识这个文件已经被删除了呢?很简单那么从管理inode的inode位图以及管理数据块的数据块位图上下手即可,由于1表示存在,0表示不存在,仅需要将inode位图以及数据块位图上文件的对应比特位的位置上的内容置为0即可,此时文件就被删除了
- Group Descriptor Table块组描述符(GDT),描述着块组的属性信息,通常包括inode table在这个块组中是从哪里开始到哪里结束的,Data blocks在这个块组中是从哪里开始到哪里结束的,块组中的inode以及数据块用了多少个,还有多少个没有等等,这里要注意一点,由于文件可能存储内容,可能不存储内容,文件可能很大的种种因素,由于inode以及数据块的个数是确定的,那么很大概率会出现inode没有使用完,但是数据块已经使用完了,同样的也可能会出现inode使用完了,但是数据块没有使用完的情况等等
- 接下来我们介绍Super Block超级块,超级块中对应的是文件系统的基本信息,其中超级块中包含的是整个分区的基本使用情况,例如:一共有多少组,每个组的大小,每个组的inode数量,每个组的数据块的数量,每个组的起始inode,以及文件系统的类型与名称等等,超级块的存在关乎整个分区,由于种种原因可能超级块会出现异常等原因,超级块肯定是要备份多份的,但是又不能每一个分组里面都有超级块,因为这样太浪费空间了,必将超级块出现异常的情况还是很小的,因此对于超级块并不是分区的每组都有,而是零散分布在少数组中
- 在我们最开始使用磁盘的时候,由于并没有任何文件,那么也就是表示磁盘上并没有存储任何文件,即磁盘上没有存储文件的属性以及文件的数据,此时对应虚拟文件系统上inode位图以及数据块位图都要设置为0,并且对应的超级块以及GDT中的信息也应该被设置,所以每一个分区在被使用之前都必须被初始化,都必须提前将这部分文件系统的属性信息通过LBA地址映射到的CHS地址,去访问磁盘指定盘面,指定磁道,指定的扇区上的数据,将这部分文件系统的属性信息提前设置进对应的分区中,方便我们后续使用这个分区或进行分区的分组
七、如何理解文件的增删查改
- 新建一个文件,系统要干什么?首先系统要给文件分配一个inode用来记录文件的属性,在inode位图对应inode编号的位置处将比特位的位置设置为1用来表示inode编号存在,即inode存在,如果文件有内容,那么根据文件的内容大小分配数据块,将文件的内容写入数据块中,将数据块位图中对应数据块的块号设置为1,表示数据块存在,同时将数据块块号填入inode的数据块块号数组中,将inode与数据块关联起来。
- 删除一个文件,系统要干什么?系统要将文件对应的inode编号以及数据块块号在对应的inode位图以及数据块位图中将对应的位置置为0表示inode以及数据块不存在,即可表示文件删除,因为当我们拿着原有的文件inode编号去inode位图中去找inode编号,此时对应inode位图的比特位位置上的内容为0,表示文件不存在,此时就无法找到文件了,并且文件的属性和内容是采用覆盖式的写入,所以我们不担心原有的inode以及数据块中会有数据残留,因此文件就被删除了
- 同样的我们也应该理解给文件分配的inode编号以及数据块块号可能是不连续的,因为当进行文件删除的时候,就要将文件对应的inode编号以及数据块块号在对应的inode位图以及数据块位图中将对应的位置置为0表示inode以及数据块不存在,这个inode编号或者数据块块号有可能是在整体编号的开头也有可能在中间也有可能在结尾,此时在数据层面上inode编号或者数据块块号就有可能已经不连续了,同样的,系统在进行分配inode编号或者数据块块号的分配规则类似于文件描述符的分配规则一样,系统会在整体编号的0号位置处开始遍历对应的inode位图以及数据块位图,寻找最小的,未被使用过的即对应位图比特位的位置上内容为0的位置,进行分配,所以此时极有可能给文件分配的inode编号以及数据块块号是不连续的
- 查找一个文件,系统要干什么?由于inode属性中并不包含文件名,所以进行查找文件并不能使用文件名,inode中有文件对应的inode编号,所以要首先找到文件名对应的inode编号,使用inode编号先去inode位图中对应比特位的位置上查看内容是否为1,如果内容为0,那么查找结束,文件不存在,如果内容为1,此时就去inode表中找到inode编号对应的inode结构体,从inode结构体中访问文件的属性,同时遍历inode结构体中的数据块块号数组,根据数据块块号找到对应数据块进行访问文件的内容
- 修改一个文件,系统要干什么?进行修改一个文件,首先要确定这个文件存在,如何确定,那么就是使用查找文件的方式确定,当确定了文件存在的时候才可以进行文件的修改,那么使用inode编号在inode表中找到对应的inode结构体进行修改文件的属性,如果还要修改文件内容的话,在inode结构体中找到数据块块号数组,同时遍历inode结构体中的数据块块号数组,根据数据块块号找到对应数据块进行修改文件的内容即可
- linux系统中,一个文件对应一个inode,每一个inode都有自己的inode编号(inode的设置,是以分区为单位,不能跨分区)
- inode结构体中表示文件所有的属性,但是文件名并不属于inode结构体中文件的属性,那么对于使用者来说,我用到从来都是文件名,甚至在未讲解文件系统之前我们都不知道inode,那么进行文件的操作的时候,虽然对于用户来讲使用的是文件名,但是操作系统会将这个文件名对应文件对应的上inode编号,那么使用的文件对应的inode编号又是如何来的呢?下面带领大家理解一下目录,读者友友就理解文件对应的inode编号从哪里来的了
八、如何理解目录
- 首先我们知道,linux下一切皆文件,所以目录也是文件,文件 = 属性 + 内容,很明显根据我们使用的 ls -l -i 指令查看目录dir,目录dir是有inode编号的,即目录是有属性的,可是我们也知道,目录也是文件,文件 = 属性 + 内容,那么你目录要不要有内容?要有内容的。要不要有数据块?目录要有数据块的。
- 那么目录的数据块里面存放着什么呢?其实是存放着该目录下,对应文件的文件名和文件对应的inode的编号的映射关系
- 奥,因此所以我们就知道了,例如我们想要对当前目录下的文件进行操作,首先就要去当前目录下找到文件名与文件对应的inode编号的映射关系,那么如何找到当前目录呢?首先就要找到当前目录对应的inode编号,如何找到当前目录对应的inode编号呢?那么就要去当前目录的上级目录去寻找当前目录的文件名与文件对应的inode编号的映射关系,如何找到上级目录呢?那么就要找到上级目录的inode编号,如何找打上级目录的inode编号呢?那么就要去上上级目录去找上级目录的文件名与文件对应的inode编号的映射关系,那么如何找上上级目录呢?那么就要去找上上级目录对应的inode,那么如何找上上级目录对应的inode呢?那么……,小编,小编你这就有点套娃的感觉了哈,是的,这其实是根据绝对路径向上递归的过程,难道要无线向上递归吗?
- 不是的,因为linux的虚拟文件系统中的文件是多叉树的形式,所有文件的源头是 \\ 根目录,没错,就是 \\ 根目录
- 由于在linux虚拟文件系统中,/ 根目录无法再继续向上递归,因为本身 / 根目录就是递归的起点,没有上级目录,无须向上递归,因此在大多数的linux虚拟文件系统中,通常对 / 根目录的inode编号进行特殊处理,将 / 根目录的inode编号设置为固定的2,使用stat / 可以查看一个目录或文件的属性,其中确实我们看到了 / 根目录的inode编号就为固定的2
- 这样回归刚刚向上递归的过程,当不断向上递归,向上递归到 / 根目录的时候,此时无法向上递归,此时可以得到根目录的inode编号,那么就去根据inode编号去inode表中找对应的inode结构体,inode结构体中有数据块块号数组,遍历数据块块号数组,访问 / 根目录的文件内容,由于 / 根目录的文件内容中存储的是 / 根目录下的子目录以及普通文件的文件名和文件对应的inode编号的映射关系,所以此时我们就可以找到刚刚递归到 / 根目录前的文件名对应的inode编号的映射关系,这样就可以不断向下递归,递归到当前目录的上级目录找到当前目录的文件名与文件对应的inode编号的映射关系,此时当前目录的inode编号就拿到了,那么也就可以根据inode编号找到当前文件的inode结构体,去inode结构体中找数据块块号数组,遍历数据块块号数组,即可访问当前目录的文件内容,也就是当前目录下的文件名与文件对应的inode编号的映射关系,此时我们就可以拿到当前目录下我们想要访问的文件名对应的文件inode编号了,此时就可以根据inode编号对文件进行文件操作了,通过讲解,我们可以看出linux虚拟文件系统的设计是多么的巧妙,不禁感慨,我们是站在巨人的肩膀上前行的
- 但是这种不断向上递归,之后在不断向下递归的方式难免会与磁盘进行IO,磁盘是外设,外设的访问效率很慢,因此为了操作系统的效率,通常会将用户经常访问的文件对应路径上的文件名以及文件对应的inode编号提前缓存起来,这样虽然第一次使用操作系统仍然较慢,但是多次使用操作系统之后,由于路径上对应的文件名以及文件对应的inode编号信息已经被提前缓存起来了,所以多次使用操作系统之后操作系统的访存以及存取效率会更快
- 那么此时我们再来理解几个问题就很好理解了,问题一:为什么同一个目录下不能有同名文件?因为文件名与文件对应的inode编号类似于key-value的模型,一个key对应一个value,如果有相同的文件名对应文件对应的不同的inode编号,此时就会出现相同的key对应同多个文件对应的inode编号,此时就无法进行查找key对应的value了,也就无法维持文件名与文件对应的inode编号的一一对应关系,所以同一个目录下不能有同名文件,只能是不同的文件名对应不同的inode编号,当然除此之外还有特殊情况,同样的其实后面我们会学软硬链接,其中的硬链接就是多个不同的文件名对应同一个inode编号
- 问题二:当前目录下,当前目录没有w读权限,我们为什么无法创建文件?因为当前目录下,当我们想要创建文件的时候,不可获取的一步就是将文件名和文件对应的inode编号映射关系写入到当前目录的数据块中,也就是写入到当前文件的内容中,但是此时当前目录没有w写权限,所以自然也就无法写入文件名和文件对应的inode编号映射关系到当前目录的内容中,进行文件操作的前提就是要找到文件名对应的inode编号,此时连文件名和文件对应的inode映射关系都无法写入存储到当前目录的数据块中,所以自然也就无法创建文件喽
- 问题三: 为什么当前目录下,当前目录没有r权限,我们无法查看文件?因为当前目录下,如果我们没有r读权限,那么将没有办法读取当前目录对应的inode编号对应的inode结构体中的数据块块号数组,所以也就无法遍历数据块块号数组找到对应的数据块块号对应的数据块访问目录的内容了
- 问题四:为什么当前目录下,当前目录没有x可执行权限,我们无法进入这个目录?因为这是权限方面的硬性规定,规定了当前目录如果没有x可执行权限就无法cd进入这个目录,更为准确点来讲当前目录如果没有x可执行权限,就无法修改将当前目录的路径写入到环境变量PWD中,所以也就无法改变当前的工作路径,所以也就自然无法进入这个目录
总结
以上就是今天的博客内容啦,希望对读者朋友们有帮助
水滴石穿,坚持就是胜利,读者朋友们可以点个关注
点赞收藏加关注,找到小编不迷路!