Bootstrap

[Linux]文件系统

目录

1.磁盘

磁盘如何存储数据

磁盘的物理存储结构

CHS定位法

2.磁盘存储的逻辑结构

3.文件系统

LBA逻辑块地址

文件系统对于磁盘空间的描述

inode编号

inode Table

Data blocks

inode Bitmap与Block Bitmap

GDT与Super Block

文件名与inode转化

分区的挂载

4.软硬连接


        操作系统的核心管理之一就是文件管理,分为打开文件的管理与磁盘文件的管理两部分内容。那么如何快速的找到想要的文件呢?其实为了方便快速找到文件,在磁盘中的文件都是按一定规律和顺序存放的。

1.磁盘

磁盘如何存储数据

        磁盘属于物理存储的硬件,磁盘的盘面是由无数个微小的磁铁组成的,分为南北级两态对应着0、1,磁头通过充放电的过程改变南北极两态,从而实现了数据写入的操作,也就将数据保存在磁盘中了。

磁盘的物理存储结构

        如图所示,这是磁盘的其中一个面,磁盘中有很多个面,每个面都有一个磁头,也就是说也有很多的磁头。图上一个一个圈称之为磁道;红色阴影部分是扇区,也是磁盘的最小单元,通常是512byte或4KB,磁盘属于块设备,是以块为单位进行I/O操作的。在磁盘中读取数据时也就是按照这个扇区读取的,如果说想修改1个字节,也要把整个扇区加载到内存中进行修改操作。

CHS定位法

        当我们想像一个扇区写入数据的时候,如何找到该扇区呢?CHS定位法,首先选择一个面,也就是选择磁头,之后选择该面上的一个磁道,是通过磁头摆动定位柱面(磁道),最后通过磁片的摆动选择磁道的哪一个扇区。就可以定位到想要写入的扇区了。

2.磁盘存储的逻辑结构

        对磁盘的管理也就变成了对数组的管理了,那么现在记录一个数据的位置,就直接记录整个数据的数组下标以及在扇区的偏移量大小就可以了。例如下表为2334,首先除以柱面(磁盘)个数,算出在哪一个盘面,在除以磁道个数,算出在哪个磁道,最后模上该磁道的扇区个数就可以定位到扇区了。

3.文件系统

        操作系统可以按照扇区为单位进行I/O操作,也可以基于文件系统,以文件块为单位进行I/O操作。通常是以8个扇区(4KB)为一个块,4KB就成为了文件保存内容/属性的一个基本的单元了。那么如何正确的定位文件块呢?

LBA逻辑块地址

        文件块的首地址可以使用LBA地址,LBA地址不在关注柱面、磁道、扇区等概念了,而是转换为4KB的block[n]数组进行管理,系统内置的LBA算法会将CHS定位的地址转化为LBA地址,这个过程我们是不需要啊关注的。

文件系统对于磁盘空间的描述

        如图所示一个500GB的空间先被分成了5个100GB,每一个100GB的空间都称为一个分区;之后又分成了若干个2GB的空间,每一个2GB的空间称为一个块组,对于每一个2GB空间的管理都是一样的,所以文件系统对于大空间管理,变成了把2GB空间管理好,其他的复用就可以了。

        每一个2GB空间内部都有一个Boost Block,它是用来存放一些磁盘的信息的。Block group就是每一个块组。

inode编号

        在命令行中可以使用ls -li显示我们创建的文件对应的inode编号,一个文件一个inode编号,在整个分区中具有唯一性。在Linux内核中,识别文件只和inode有关。

inode Table

        用于存放文件的属性(大小、所有者、修改时间等)。其实保存文件的属性内容是通过inode保存的,每一个文件在分区中都有一个唯一的inode,唯一的inode也对应了一个struct inode结构体,该结构体内部存放了文件的各种属性字段。一个块组中可以存放若干个文件,也就对应了若干个struct inode结构体,所以inode Table就是用来管理若干个inode结构体的一个结构体数组,struct inode_struct[n]。

        因为inode在分区中有唯一性,那么我们在分区中找inode编号为x的文件时,还需要遍历整个分区中的块组吗?不需要,每一个块组的起始位置都会存放该块组的起始inode编号,所以我们只需要找到特定inode编号区间的块组,在其内部的inode Table字段数组中寻找就可以了,不需要遍历整个分区的块组。

Data blocks

        该区域是用来存放文件数据的区域,这里面通常是以4KB的固定大小,将该区域分为若干个块的,并进行编号处理。那么访问文件的时候如何找到该数据在Data blocks的哪里呢?

        inode结构体中有一个int block[n]数组存放着文件内容在哪些数据块。所以首先通过inode编号找到在哪个块组,之后减去该块组的起始inode编号,就找到了该inode在struct_inode的第几个位置存放,最后在inode结构体内部访问block数组,就知道文件存放在Data blocks区域的哪几个数据块中了。

        根据上述描述会有一个问题,如果说一个文件的大小是大于一个块组的大小该怎么存储呢?block结构体通常可以映射15个数据块地址,0~12个属于直接映射,也就是说数组内的位置信息对应的数据块是直接存放的文件的数据,而剩下的属于间接映射,数据块内部存放的不是文件的数据内容,而是保存的块列表,通过访问数据块内部的块列表,就可以访问到更多的数据块了。对于更大的文件可以采用多级映射,也就是说块列表中映射的位置存放的也是块列表。更大的文件的话也可以存放块组编号,从而进行跨组存储和访问了。

        对于目录在Linux中的定义也是一个文件,只不过在Data blocks的数据块内部,目录存放的数据是该目录保存的文件的编号等属性罢了,等到访问目录的时候,通过将目录对应数据块内部的数据进行解析,就直到存放了哪些文件了。

inode Bitmap与Block Bitmap

        inode Bitmap是一个位图,每一个比特位用来表示一个inode是否处于空闲可用的状态。Block Bitmap也是一个位图,每一个比特位用来记录Data blocks中每个数据块的占用情况。

        新建一个文件的过程:先检测inode Bitmap位图,找到0的位置,将0修改为1,记录偏移量。之后在inode Table中根据偏移量找到对应的inode结构体对象,把文件的各个属性字段写入inode结构体中,之后根据文件的大小,在Block Bitmap中找到n个位置,把n个位置全部修改为1,表示已经被使用了,之后将n个位置的偏移量也就是编号写入inode结构体的block数组内部,最后把数据内容写入到block结构体记录的Data blocks数据块中,最后把inode编号返回给上层,就完成了一个文件的创建操作

        删除一个文件的过程:也就是修改inode Bitmap和Block Bitmap即可,其他的不需要动,有新的文件创建后会将这些地方覆盖的。所以说有了该机制也才提供了数据恢复的功能。

        恢复一个文件的过程:通过上层记录的inode编号找到inode结构体,根据内部block记录的信息恢复Block Bitmap,通过inode编号恢复inode Bitmap,这样也就完成了文件的恢复。

GDT与Super Block

        Group Descriptor Table用来记录的是整个块的属性信息(块组描述符)。

        Super Block是用来记录整个分区的属性信息,主要有分区中块组的使用情况,inode编号的使用情况,一个block的大小,以及inode的总量等信息。所以说如果Super Block被破坏了,那么操作系统就无法读取到该分区中的存储空间使用情况,那么整个分区就无法使用了。所以该字段会有多份保留在多个块组中,但并非每一个块组都有,这样的话会占用空间。

文件名与inode转化

        在Linux中文件名不属于文件的属性,所以在底层的inode结构体中是不会存放文件名的字段的,那么如何通过文件名找到文件的呢?文件是一定存在于目录当中的,而目录在底层的数据块中会存放该目录内部文件的文件名与inode的映射关系,所以通过访问目录的数据块,就可以访问到文件对应的inode编号了。

        那么目录也是文件,目录的inode又是哪里来的呢?目录是文件,那么文件就一定存在于目录当中,那么这样不是循环了吗?但是循环到根目录就好了,根目录也就是分区的最开始,分区会存放着根目录的数据位置信息,从而就能访问到根目录下的文件与inode之间的关系了。接下来的每一层都可以通过目录数据块中的内容将文件名与inode进行转换了。同时对于经常访问的文件路径信息会被记录到缓存当中,也提高了访问文件的效率。

        所以这样的话,根据文件的路径,可以先确定分区,之后根据路径一层一层的进行转换和寻转就可以找到对应的文件了。

分区的挂载

        我们说了每一个分区中的inode是唯一标识的,所以在分区内部可以通过inode找到唯一的一个文件,但是从分区层面来说,每一个分区都可以有一个相同的inode,怎么判断该一个inode编号是哪个分区下的inode编号呢?

        一个磁盘在被分区格式化之后,Linux如果想要使用这个分区,就要把整个分区进行挂载操作mount(sudo mount /dev/sdb/ /mnt)。该操作就相当于把一个分区和一个目录进行关联,让这个目录作为了分区的根目录,当我们访问文件的时候,是一定会带有路径的,那么根据路径的起始位置就可以判断出访问的文件在哪一个分区了。

4.软硬连接

        软连接是一个独立的文件,底层会分配一个inode编号,但是内部的数据块存放的是连接的文件的路径。而硬链接不是一个独立的文件他没有独立的inode编号,实现逻辑是在指定目录内部创建一个文件名与inode的映射关系。

软连接:   ln -s  路径   名称 

硬链接:   ln 路径   名称

删除连接文件:  unlink   连接名称 

        对于一个文件来说,没有文件名和inode之间的映射才算是被真正的删除了,inode当中会有引用计数记录着有几个文件名映射到该文件,当引用计数减少到0的时候,才会真正的删除该文件。

ls -li 

         使用ls -li不仅可以查看inode编号,也可以查看到该文件硬链接的数量。对于一个新建的目录,硬链接的数量会是2,一个是上层目录中保存的自己本身与inode的映射关系,而另一个是该目录下会有一个.目录,该“.”目录的inode和该目录是一样的。所以说硬链接会有两个。

        如果说在新建的目录下在创建一个目录的话,那么硬链接就会变成三个,因为新建的目录下会有一个".."目录指向上一层目录,这个".."目录的inode编号和该目录一样,所以会有三个硬链接。

        硬链接是不可以给目录建立的,因为很容易造成文件系统的层次紊乱。操作系统在进行查找时只有目录文件才会进入下一层,同时会判断文件类型,如果L的话就是软连接文件,如果是软连接的话是不会进入寻找的,而硬链接不一样,他和普通文件一样无法去鉴别,所以会进入硬链接目录中记录寻找,那么就会出问题,如果硬链接指向的是上级目录呢?如图所示就会造成循环,所以不要给目录建立硬链接,操作系统也是不允许的。

;