文件系统1(Linux中)
1 “块”的概念
前面讲过可以通过LBA,来找到对应的扇区进行访问,一个一个扇区的访问是不是效率有点太低了,其实硬盘就是典型的“块”设备,块的大小一般都是八个扇区也就是4KB,是不可更改的,“块”也就是文件存取的最小单位。
通过LBA地址也可以确定对应的“块”号,即:块号=LBA/8。
2 “分区”的概念
已经划分出来这么多“块”号,就需要将这些“块”进行管理,所以就有了分区的概念,这里可以通过windows下,我看到自己电脑被分为C盘,D盘,其实这就是分区(并不是有两块物理盘哦)。
柱面是分区的最小单位
我们可以利用参考柱面号码的方式来进行分区,其本质就是设置每个区的起始柱面和结束柱面号码。
此时我们可以将硬盘上的柱面(分区)进行平铺,将其想象成⼀个大的平面,如下图所示:
3 inode的概念
之前一直强调,文件=内容+属性,可以通过ls -l查看具体细节。
这里还可以通过stat命令进行查看:
stat test.c
继续思考,这里文件有属性,那这里的属性存放在那里?这是候inode(也叫“索引节点”)就闪亮登场,这是一个结构体,用来存放文件元信息(属性信息),比如问件的创建者、文件的创建日期、文件的大小等等。(inode大小一般为128字节,还有个细节:就是文件名并未存放在inode结构体中,后面会有讲解)inode中有一个成员是inode number是用来标识文件唯一性的。
4 文件系统(ext2)
我们想要在硬盘上储文件,必须先把硬盘格式化为某种格式的文件系统,才能存储文件。文件系统的目的就是组织和管理硬盘中的文件。
linux中早期中,比较常见的就是ext2文件系统,那ext2是如何管理的呢?
ext2文件系统将整个分区划分成若干个同样大小的块组(Block Group)。只要能管理⼀个分区就能管理所有分区,也就能管理所有磁盘文件。
启动块(BootBlock/Sector)的大小是确定的,为1KB,由PC标准规定,用来存储磁盘分区信息和启动信息,任何文件系统都不能修改启动块。启动块之后才是ext2文件系统的开始。每个分区又被划分为block group(组块)。
4.1 块组内部构成
4.1.1 超级块(Super Block)
存放文件系统本身的结构信息,描述整个分区的⽂件系统信息。记录的信息主要有:bolck和inode的总量,未使用的block和inode的数量,⼀个block和inode的大小,最近⼀次挂载的时间,最近⼀次写入数据的时间,最近⼀次检验磁盘的时间等其他文件系统的相关信息。
这个超级块每个块组中都有一份:原因是Super Block的信息被破坏,可 以说整个文件系统结构就被破坏了,为了保证文件系统在磁盘部分扇区出现物理问题的情况下还能正常工作,可以通过其他块组中super block恢复出来。
通过下面部分成员可以看到:
4.1.2 GDT(Group Descriptor Table)
块组描述符表,描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描 述符存储⼀个块组的描述信息,从哪里开始到哪里结束是描述block bitmap,inode bitmap,inode Table,Data Blocks,以及空闲的inode和数据块还有多少个。
4.1.3 Data Block
数据区:存放文件内容,也就是⼀个⼀个的Block。
Block 号按照分区划分,不可跨分区。用来存放文件信息的,分为一个一个4KB的块。
4.1.4 块位图(Block Bitmap)
Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用(就是通过位图结构来表示,可以理解为0就是未占用,1就是占用,第几个比特位就表示第几个块)。
4.1.5 i节点表(Inode Table)
当前分组所有Inode属性的集合。
inode编号以分区为单位,整体划分,不可跨分区。
4.1.6 inode位图(Inode Bitmap)
和block bitmap效果一样,每个bit位表示⼀个inode是否被占用。
4.2 文件的创建和删除
4.2.1 文件的创建
首先需要确定的是,一个文件无论有没有内容,一定要有文件的属性,所以一定会创建一个inode结构体,再在inode bitmap位图中,找到未占用的inode,再在inode table中加入该结构体,填入对应的文件属性,如果需要进行对文件有内容,那个就还需要在block bitmap中找到未被使用的Data block,再在Data block中写入文件内容,最后在inode结构体中,有一张映射表(本质是数组),将块进行映射,填入表中。
4.2.2 文件的删除
我们一定有过这样的经历,就是下载一个几个G的视频可能要下载十多分钟,但是删除它时间就短短几秒就好了,这是为什么呢?其实是,在删除时,并未对Data block中的内容进行清空,也并未对inode table中对应的inode 进行清空,而是将inode bitmap对应bit位的1改为0,block bitmap进行同样的操作,将对应的bit位由1改为0,即可,等到要创建新的文件时,就直接对这部分内容进行覆盖就可以了。
(当你误删除一些文件之后,往往可以通过某些修复软件,来进行文件修复,就是这样做到的,但是误操作之后,就不要再去创建新的文件,一旦将要修复的文件,覆盖掉后就很难再找回了)
4.3 目录与文件名
我们一直说“Linux下一切皆文件”,所以理所当然目录也是文件,因此目录文件也应该有文件属性+文件内容,那目录文件中的内容存放的是什么呢?前面有提到文件名并没有存放在inode结构体中哦,其实目录文件内容,就是用来存放文件名和inode号的映射关系的。
但是用户使用的都是直接使用文件名,所以,访问文件必须要知道当前工作目录,本质是必须能打开当前工作目录文件,查看目录文件的内容!
/home/iu/code/study/test
例如:如果test目录下有一个文件test.c,要访问test下的文件,就必须要知道test(当前工作路径)才能获取到对应的inode进而对test.c文件进行访问。
4.3.1 路径解析
刚刚说到要打开文件,就必须要找到工作路径(目录文件),那目录文件是不是也有对应的目录,这样一层一层向上就会来到根目录‘/’。
实际上任何文件,都有路径,访问目标文件,都要从根目录开始,依次打开每⼀个目录,根据目录名,依次访问每个目录下指定的目录,直到访问到test.c。这个过程叫做Linux路径解析。
注意两点:
访问文件必须要有目录+文件名=路径的原因
根目录固定文件名,inode号,无需查找,系统开机之后就必须知道
新的问题出现:谁来提供路径?
访问文件时:都是指令/工具访问,本质是进程访问,进程有CWD!进程提供路径。
使用open函数时:需要传入一个参数就是文件路径。
最开始的路径来自哪里?
其实linux下为什么会存在根目录,根目录下存在那么多缺省参数,还有为什么有家目录,用户自己也可创建目录。
本质就是在磁盘文件系统中,新建目录文件。而你新建的任何文件,都在你或者系统指定的目录下新建,这不就是天然就有路径了!
4.3.2 路径缓存
前面说到,打开一个文件需要路径解析,要从根目录开始解析,那我访问大量的文件,每一次都从根目录开始解析,这样是不是太慢了?
所以Linux会缓存历史路径结构,打开的文件是目录的话,由OS自己在内存中进行路径维护。
Linux中,在内核中维护树状路径结构的内核结构体叫做: struct dentry
1.每个文件其实都要有对应的dentry结构,包括普通文件。这样所有被打开的文件,就可以在内存中形成整个树形结构
2.整个树形节点也同时会隶属于LRU(Least Recently Used,最近最少使用)结构中,进行节点淘汰
3.整个树形节点也同时会隶属于Hash,方便快速查找
更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何文件,都在先在这 棵树下根据路径进行查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry 结构,缓存新路径。