文章目录
- 概述
- 认识磁盘
- 了解磁盘的存储结构
- 对磁盘的存储结构进行逻辑抽象
- 操作系统对磁盘的使用
- 宏观认识
- 细节认识
- 再谈目录
- 再谈文件的增删
概述
文件有很多,但是被打开的文件很少,这些没有被打开的文件在磁盘中,这就叫做磁盘文件。每次先打开一个文件,需要先找到这个文件,需要通过文件路劲及文件名先在磁盘中找到这个文件。本篇文章要研究的是磁盘文件,核心问题是如何存取问题。在研究这些问题之前,需要先认识一下硬件–磁盘
认识磁盘
磁盘本质是一个机械设备
计算机只认识二进制,即0和1,在物理层面上有不同的表现
- 盘片:可读可写可擦出,一片两面都可以使用
- 磁头:在磁盘上来回读写,盘片一面一个磁头,磁头和盘片不是挨着的
了解磁盘的存储结构
磁盘是一个机械设备,是一个外设,速度比较慢。
磁盘读写的基本单位是扇区,512字节,4KB
1片=n磁道,1磁道=m扇区
这么多扇区,如何找到指定位置的扇区?
- 找到指定磁头Header
- 磁头移动,找指定的磁道(柱面) Cylinder
- 找到指定的扇区(通过磁盘旋转) Sector
上述称为CHS定址法
所谓把文件存储在磁盘,本质是文件在磁盘中占几个扇区
对磁盘的存储结构进行逻辑抽象
为什么需要把磁盘的存储结构进行逻辑抽象?
一方面如果操作系统直接用CHS地址,硬件改了,那么软件也改了,耦合度过高; 另一方面方便实现内核进行磁盘管理。
在块级别上,磁盘被划分为若干个固定大小的块(通常是几KB或几MB)。文件系统会将文件分割成多个块,并将这些块按需存储到磁盘上。每个块都有一个唯一的地址,文件系统通过记录块的地址和文件的元信息(如文件大小、创建时间等)来管理文件的存储和访问。
最终一个磁盘可以看作是基于扇区的数组,每一个扇区都对应有一个下标来唯一标识。通过这个下标(LBA 逻辑扇区地址),再结合每一面磁道的个数和每一个磁道上扇区的个数就可以定位到该扇区在磁盘上的位置(CHS地址)。
通过逻辑抽象,用户和应用程序可以像操作文件一样操作磁盘上的数据,而不需要了解底层的物理存储细节。文件系统负责将逻辑操作转换为物理操作,并管理数据在磁盘上的存储和检索。这样,文件系统提供了一种方便和可靠的方式来管理和利用磁盘的存储空间。
进一步可得,所谓的文件只需要知道LBA地址,文件=很多个LBA地址(纯硬件)。
操作系统对磁盘的使用
宏观认识
Linux文件系统特点:文件内容和文件属性分开存储
先简单了解一下文件系统:
在每一个分区内部分组,然后写入文件系统的管理数据
Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的
- Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子
- 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。简而言之,描述整个分区(一个分区多大,有多少块组,每个块组使用情况等等)。超级块不是每个分区都有,一个分区也不一定只有一个超级块。
- GDT,Group Descriptor Table:块组描述符,描述块组属性信息,描述一个块组的具体使用情况
- 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用,比特位的位置表示块号,比特位的内容,表示该块是否被占用
- inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用
- i节点表:存放文件属性 如 文件大小,所有者,最近修改时间等,一个正常文件一个inode属性
inode内部不包含文件名,内核层面每一个文件都要有inode_number,我们通过inode号标识一个文件。
通过ll -li
即可查看文件号
- 数据区(Data Blocks):存放文件内容
细节认识
我们在寻找文件的时候,需要找到inode编号
inode编号是分区为单位整体分配的,一个分区内inode编号不可能重复。两个分区的inode编号可能是重复的,因此inode不能跨分区访问。一个分组使用的inode编号,是在一个范围中;例如,第一个分组时1 ~ 10000,第二个分组是 10001 ~ 20000…
在Super Block和GDT中都会记录start_inode和end_inode,这样就能确定inode在哪一个分组里。
datablocks也是如此
再谈目录
目录=文件属性+文件内容 ,目录也有自己的inode属性
通过上述可见,目录和文件的属性结构是一致的
查找一个文件,是根据该文件的文件名在系统中找到该文件对应的inode编号。
因此可以解释一下现象:
- 一个目录下不能建立同名目录
文件名的inode互为键值 - 查找文件的顺序,先根据文件名找到inode编号,然后根据编号在所在的分区确定范围,确定在某个组里面,然后找对应的inode Bitmap和inode Table,确定是合法的然后找到对应的属性,属性找好了之后,对应的大小等都找到了。
- 进入目录需要x权限,目录的r权限本质为是否允许我们读取目录的内容,文件名:inode的映射关系;目录的w权限,新建文件,最后一定要向当前所处的目录中写入文件名和inode映射关系
再谈文件的增删
首先创建文件一定是在一个路径下(目录)进行创建,这个路径就会帮我们定位到一个分区,然后去从第一个分组开始查看当前分组的 GDT 字段,看该分组中 inode 的使用情况,若当前分组中的 inode 还有剩余,接着去读取 inode_Bitmap,获取最近一个未被使用的 inode 编号,然后拿着 inode 编号去 inode_Table 里面找到对应的 inode,将文件的属性信息一填。如果有文件内容,先拿着 inode 编号找到对应的分组,根据写入内容的大小去 Block_Bitmap 中找出对应数量未被使用的块号,然后将这些块号写入到 inode 对应的属性里面,然后拿着块号去 Data blocks 中进行写入。
删除文件只要拿着该文件的 inode 编号,在 inode Table 中找到对应的 indoe,获取到里面的 blocks,即拿到该文件对应的所有块号,然后根据这些块号将 Block Bitmap 中对应的比特位置0(假设 0 表示对应的块未被使用)。最后再根据 inode 编号到 inode Bitmap 中将该 inode 对应的比特位置为0,至此,一个文件就被删除啦。可以发现从头到尾并没有去修改块中的内容,这也是为什么拷贝 4G 的文件很慢,删 4G 的文件很快。所以在理论上,一个被删除的文件,可以根据 inode 将其恢复出来。