目录
group descriptor table -- 块组描述符表
引入
前面我们已经介绍了磁盘是如何被抽象化成线性结构的:
经过不断分区...我们可以得到了块组这一概念
boot block (启动块)
每个大分区中,除了被分成多个块组,还有一个boot block
- 用于存储开机用的数据(分区表,开机用的程序,属性信息...)
- 每个分区前可能都有一份
- 用于备份
- 前面提到的,硬盘容易被损坏
- 所以为了防止boot block被损坏后让计算机无法启动,就多存储几份来应急
块组
介绍
- 用于在磁盘上组织和管理文件系统的数据,有助于提高文件系统的性能、可靠性和管理效
- 率
- 块组将磁盘的存储空间分成多个较小的块
- 每个块组包含一定数量的数据块、索引块、超级块以及其他与文件系统操作相关的数据结构
super block -- 超级块
- 核心数据块
- 存储了文件系统的元信息
- eg:文件系统的大小、块大小、inode数量、挂载次数等
- 还存储了文件系统的状态信息,以便在系统崩溃或意外关机时进行文件系统检测和修复
也就是说,超级块并不是作用于一个块组,而是用来管理整个文件系统的
为什么将它放在块组中?
- 为了备份,和前面的boot block一样
- 防止这么重要的数据块被损坏后,整个分区都无法使用了
- 所以在很多个块组中,都会存储一个超级块
inode table -- inode表/索引节点表
inode和inode编号
引入
ls指令带上-i选项后可以显示出每个文件的索引节点号 ,也就是inode编号
- 第一列数字就是每个文件的inode编号
介绍
- inode是一个大小为128字节的空间,保存了有关文件或目录的元数据信息,也就是文件属性
- (包括文件类型、权限、所有者、大小、创建时间、修改时间、链接计数、数据块的指针等)
- 而inode编号是每个文件的标识符(唯一性)
- 一般来说,一个文件对应一个inode,一个inode编号
- 文件数据与元数据分离,可以提高文件系统性能并使某些操作更加高效
inode表
顾名思义,它保存了[该块组内所有文件]的inode空间
- inode表是一个数组或表格,每个元素都是一个inode结构
- 通过inode编号,可以在inode表中 查找相应的inode结构
data blocks -- 数据块
块大小的由来 -- 4kb
- 磁盘基本单位是扇区(512字节)
- os和磁盘进行io的基本单位是4kb(也就是8*512字节)
- 内存页面大小一般是4kb
该怎么选择呢?
- 512字节太小了,会导致多次io,效率降低
- 但我们空间其实很大很大,所以尽量用空间换时间
经过多重考虑,许多文件系统选择使用4kb作为块大小
- 4kb块大小与底层硬件(包括内存和存储子系统)很好地对齐,对齐可以带来更高效的 I/O 操作
- 4kb 块大小通常被认为是 I/O 性能的最佳权衡
介绍
- 数据块是用来存储文件内容的基本单位,磁盘也就被叫做块设备
- 文件=内容+属性
- 所以linux在硬盘上存储文件,是将内容和属性分开存储
- 文件系统以数据块的形式将文件的实际内容存储在磁盘上
- data blocks除了可以保存文件实际内容,也可以存其他数据块的块号
一个文件可以和多个数据块对应
之前说到的,inode空间中存放了各种文件属性,它们以结构体的形式组织起来:
其中数据块以数组形式存放在inode中:
假设blocks数组有15个元素的大小,该数组中就可以存放该文件数据对应的数据块编号
如何拿到文件数据
向上面图中那样:
只要拿到inode -> 就可以在inode表中找到对应的inode结构 -> 在inode结构中找到数据块数组 -> 文件数据
文件过大时
我们用数组保存数据块编号 ,但是!!!如果这个文件特别大,超过了数组可以保存的数量怎么办?
所以实际上,数据块也可以保存其他块的编号
- 比如:blocks[12]指向一个数据块
- 该数据块内,存放了一定数量的数据块编号
- 这些编号可以继续指向其他块/编号
- 这样就形成了多叉树的结构,它就可以存放好大好大的文件噜
inode和文件名
引入
- 前面说到,inode是文件的标识符
- 但是,我们在操作文件的时候,似乎根本没有inode的参与,从前我们压根不知道有inode的存在
- 我们一直都使用文件名来标识一个文件
- 但实际在linux下,文件的inode中,根本就没有文件名这样的说法:
那我们的文件名究竟是一个什么东西呢?
文件名存放位置
引入 -- 目录
所有文件都有自己的inode结构,data block啥的
- 那目录文件的inode里肯定会存储它自己的权限,文件类型啥的
- 那它的data block 放啥嘞?(思索.jpg)
介绍
- 前面说到,文件名并不在该文件的inode中
- 所以,真相只有一个,文件名就在 存放该文件的目录文件 的 data block 中
- 目录文件的数据块中会存储 文件名和inode的映射关系
- 以便让我们传入的文件名可以和inode关联
使用 -- 目录权限
引入
还记得之前在权限那里说的,目录的三个权限对应的行为吗?
为什么 新建/移动/删除文件 需要 目录的写入权限?
- 因为新建文件需要向目录的data block中 添加文件名和inode,所以需要写权限
- 移动/删除 同理
为什么 查看目录中的文件信息 需要 目录的读取权限 ?
- 要显示文件名,就得拿到文件名
- 而文件名在目录文件的data block中,所以需要读取目录文件的内容
- 除了文件名,我们也需要查看该目录下文件的其他属性
- 这些属性从哪来?
- 从文件的inode结构中来 -> 需要拿到inode号 -> 要拿inode号,就必须拿到文件名 -> 要文件名,就得读取目录文件
查找文件
而拿到inode编号,依托于目录结构 -> 文件名 -> inode编号
block bitmap -- 块位图
介绍
- 和之前的"将一个int拆分成bit位,每一位对应一个标识符"类似
- 这个块位图用于跟踪该块组中每个数据块的使用情况,用于维护文件系统的空间使用情况
- 块位图中的每一个bit对应一个数据块
- 如果位为1,则表示对应的数据块已被使用
- 如果位为0,则表示对应的数据块为空闲
使用
块分配
当文件系统创建文件或目录时,它会查找块位图以找到可用的数据块,然后将这些数据块分配给新创建的文件或目录
块释放
当文件或目录被删除或大小调整时,相应的数据块会被释放,并在块位图中将相应的位设置为0,表示这些块现在是可用的
inode bitmap -- inode位图
介绍
和块位图一个功能
- 用于跟踪该块组中每个inode的使用情况
- inode位图中的每一位对应一个inode
- 如果位为1,则表示对应的inode已被使用;如果位为0,则表示对应的inode为空闲
使用
inode分配
当文件系统创建文件或目录时,它会查找inode位图以找到可用的inode,然后将这些inode分配给新创建的文件或目录
inode释放
当文件或目录被删除时,相应的inode会被释放,并在inode位图中将相应的位设置为0,表示这些inode现在是可用的
这也是为什么之前关掉标准输出后,再打开某个文件时,分配到的fd是1
group descriptor table -- 块组描述符表
包含有关该块组的元数据信息
如:该块组的大小,inode的数量,已经占用的有多少,还剩多少,块位图的位置,inode位图的位置,空闲块数量....
文件系统的格式化
上面那些用作存储管理信息的模块,统称为文件系统信息
每个块组都这样,整个分区就被写入了文件系统信息
即使没有文件,块组依然被分成那些区域,依然存在管理数据,只不过都是0 -- 格式化