基于异步块设备驱动实现异步FAT32文件系统。
在写好异步块设备驱动,内核异步运行时,和Rust语言async/await
语法的基础上,异步文件系统的编写方式与传统文件系统的编写方式没有太大区别。
写就完事!
块缓存层主要有两个作用:
- 提高IO性能:一些经常使用的块留在内存里,不必频繁从块设备中读取
- 维护数据一致性:在高并发的场景中多个任务对块设备进行读写操作可能造成数据不一致,块缓存层通过锁机制维护数据一致性。
FAT32 文件系统由 DBR 及其保留扇区,FAT1,FAT2 和 DATA 四个部分组成,这些结构是在分区被格式化时创建出来的。
DBR 及其保留扇区:DBR 的含义是 DOS 引导记录,也称为操作系统引导记录,在 DBR 之后往往会有一些保留扇区。
FAT1:FAT 的含义是文件分配表,FAT32 一般有两份 FAT,FAT1 是第一份,也是主 FAT。
FAT2:FAT2 是 FAT32 的第二份文件分配表,也是 FAT1 的备份。
DATA:数据区,是 FAT32 文件系统的主要区域,其中包含目录区域。
FAT32 文件系统的 DBR 有 5 部分组成:
- 跳转指令:本身占 2 字节,它将程序执行流程跳转到引导程序处
- OEM 代号:这部分占 8 字节,其内容由创建该文件系统的 OEM 产商提供
- BPB:从第 12 个字节开始,占用 79 字节,记录了有关该文件系统的重要信息,前 53 个字节是 BPB,后面 26 个字节是扩展 BPB。各参数解释如下表:
字节偏移 | 字段长度 | 名称 | 定义 |
---|---|---|---|
0x0B | 2 | 扇区字节数 | 硬件扇区的大小,合法的十进制值有 512,1024,2048,4096 |
0x0D | 1 | 每簇扇区数 | 一簇中的扇区数 |
0x0e | 2 | 保留扇区数 | 第一个 FAT 开始之前的扇区数 |
0x10 | 1 | FAT 数 | 该分区上 FAT 的副本数,本字段一般为 2 |
0x11 | 2 | 根目录项数 | FAT32 本字段必须设置为 0 |
0x13 | 2 | 小扇区数 | FAT32 本字段必须设置为 0 |
0x15 | 1 | 媒体描述符 | 提供有关媒体被使用的信息 |
0x16 | 2 | 每 FAT 扇区数 | FAT32 本字段必须设置为 0 |
0x18 | 2 | 每道扇区数 | - |
0x1A | 2 | 磁头数 | - |
0x1C | 4 | 隐藏扇区数 | 该分区上引导扇区之前的扇区数,在没有分区的媒体上它必须总是 0 |
0x20 | 4 | 总扇区数 | 本字段包含 FAT32 分区中总的扇区数 |
0x24 | 4 | 每 FAT 扇区数 | 该分区每个 FAT 所占的扇区数,利用这个数和 FAT 数以及隐藏扇区数来决定根目录从哪开始。从目录的项数决定该分区的用户数据区从哪开始 |
0x28 | 2 | 扩展标志 | - |
0x2A | 2 | 文件系统版本 | - |
0x2C | 4 | 根目录簇号 | 根目录第一簇的簇号,一般为 2 |
0x30 | 2 | 文件系统信息扇区号 | FAT32 分区的保留区中文件系统信息结构的扇区号 |
0x34 | 2 | 备份引导扇区 | 表示该分区保存引导扇区的副本的保留区中的扇区号,一般为 6,建议不使用其他值 |
0x36 | 12 | 保留字段 | - |
0x40 | 1 | 物理驱动器号 | - |
0x41 | 1 | 保留 | FAT32 该字段总是 0 |
0x42 | 1 | 扩展引导标签 | - |
0x43 | 4 | 分区序号 | - |
0x47 | 11 | 卷标 | - |
0x52 | 8 | 系统 ID | FAT32 中一般为"FAT32" |
FAT 表结构及作用:
- FAT32 文件一般有两份 FAT,它们由格式化程序在对分区进行格式化时创建,FAT1 是主,FAT2 是备份
- FAT1 跟在 DBR 之后,其具体地址由 DBR 的 BPB 参数中指定,FAT2 跟在 FAT1 后面
- FAT 表由 FAT 表项组成,每个 FAT 项占用 4 字节
- 每个 FAT 项有个固定的编号,从 0 开始
- FAT 表的前两个项为文件系统保留使用,0 号为介质类型,1 号为文件系统错误标志
- 分区的数据区中每个簇都会映射到 FAT 表中的唯一一个 FAT 项,用户的数据从 2 号 FAT 开始记录
- 如果某个文件占用很多个簇,则第一个 FAT 项记录下一个 FAT 项的编号,如果这个文件结束了,则用
0f ff ff ff
表示 - 分区格式化后,用户文件以簇为单位存放在数据区中,一个文件至少占用一个簇
- FAT 的主要作用是标明分区存储的介质以及簇的使用情况
定位 FAT 绝对位置的方法如下:
- 首先从 MBR 的分区表中得知分区的起始扇区,偏移到此扇区
- 从 DBR 的 BPB 中得知 DBR 的保留扇区数,FAT 表的个数,FAT 表的大小
- 因此 FAT1 = 分区起始扇区 + DBR 保留扇区,FAT2 = 分区起始扇区 + DBR 保留扇区 + FAT1
分析 FAT32 文件系统的数据区
- 定位方法:
- 通过 MBR 中分区表信息得知分区的起始位置
- 通过分区中 DBR 得知 DBR 的保留扇区数以及 FAT 表的大小,FAT 表的个数
- 数据区 = 隐藏扇区数 + DBR 保留扇区
- 数据区的内容主要由三部分组成:根目录,子目录和文件内容
- 数据区中以“簇”为单位进行存储,2 号簇被分配给根目录使用
- 根据簇号得到在 FAT 中的扇区号和偏移:扇区号 = 簇号 * 4/每个扇区的字节数 + 隐藏扇区数 + 保留扇区数,扇区偏移 = (簇号 * 4) % 每个扇区的字节数
- 根据簇号得到起始扇区号:簇号起始扇区:(簇号-2)* 每个簇的扇区数 + 隐藏扇区数 + 保留扇区 + FAT 数 * 每个 FAT 占扇区数
- FAT32 文件系统中,分区根目录下的文件和目录都放在根目录区中,子目录中的文件和目录都放在子目录区中,并且每 32 个字节为一个目录项(FDT),每个目录项记录着一个目录和文件或多个目录项记录一个文件和目录
- FAT32 文件系统中,目录项可以分为四类:
- 卷标目录项
- ./..
- 短文件名目录项
- 长文件名目录项
- FDT 第一个字节表明了该文件的状态,有下面四种取值方式:
- 00h 目录项的空目录
- E5H 表示该目录项曾经使用过,但文件已经被删除
- 2EH 表示子目录下的两个特殊文件 . 或 ..
- 其他任何字符 表示一个文件名或目录名的第一个字符的ASCII码值
- FDT 第 0xB 个字节可以判别式长文件目录项还是短文件目录项
- FAT32 文件目录项第 32 个字节表示一些文件的属性信息,包括文件名,扩展名,权限等
异步FAT32目前以[no_std]库的形式呈现,具体请看async-fat32。
use async_fat32::FAT32;
async {
// 初始化文件系统
let mut fs = FAT32::init().await;
// 列出根目录下的所有文件和目录
let files = fs.list("/");
// 加载第一个文件的二进制数据
let content = fs.load_binary(files[0]).await.unwrap();
// 创建空文件
//
// 指定根目录,文件名,和文件大小
fs.create("/", "test.rs", 500).await;
}