新版文件系统重构完成 (#198)

1.重构:VFS
2. 重构:ProcFS
3. 重构:DevFS
4. 重构:FAT32
5. 重构:AHCI驱动
6. 新增:RamFS
7. 新增:MountFS
8. 新增:FAT12
9. 新增:FAT16
10. 重构:设备抽象

Co-authored-by: guanjinquan <1666320330@qq.com>
Co-authored-by: DaJiYuQia <88259094+DaJiYuQia@users.noreply.github.com>
This commit is contained in:
login
2023-03-12 22:36:11 +08:00
committed by GitHub
parent 17041e0e30
commit 004e86ff19
109 changed files with 11258 additions and 7486 deletions

View File

@ -1,24 +0,0 @@
# devFS 设备文件系统
&emsp;&emsp;devfs是一种基于内存的伪文件系统设备可注册到devfs中。对上层模块及应用程序而言每个设备都是可操作的文件。
## 原理
&emsp;&emsp;由于每个设备被抽象为文件,因此对于驱动程序而言,只需实现文件的操作接口,上层的应用程序以及其他系统组件即可操作文件操作接口来控制硬件设备。
## 目录结构
&emsp;&emsp;按照设备的主类型的不同将多种设备放置在devfs的不同文件夹下.请注意,同一设备可以出现在不同的文件夹下。
- `char` 字符设备
- `block` 块设备
- `usb` usb设备
- stdio等设备放置在devfs的根目录下
## 设备注册
&emsp;&emsp;驱动程序可使用`devfs_register_device()`函数将设备注册到devfs之中。
## 设备卸载
&emsp;&emsp;【尚未实现】

View File

@ -1,216 +0,0 @@
# FAT32文件系统
## 简介
&emsp;&emsp;FAT32文件系统是一种相对简单的文件系统。
&emsp;&emsp;FAT32文件系统实现在`kernel/filesystem/fat32/`中。
---
## 相关数据结构
### struct fat32_BootSector_t
&emsp;&emsp;fat32启动扇区结构体
```c
struct fat32_BootSector_t
{
uint8_t BS_jmpBoot[3]; // 跳转指令
uint8_t BS_OEMName[8]; // 生产厂商名
uint16_t BPB_BytesPerSec; // 每扇区字节数
uint8_t BPB_SecPerClus; // 每簇扇区数
uint16_t BPB_RsvdSecCnt; // 保留扇区数
uint8_t BPB_NumFATs; // FAT表数量
uint16_t BPB_RootEntCnt; // 根目录文件数最大值
uint16_t BPB_TotSec16; // 16位扇区总数
uint8_t BPB_Media; // 介质描述符
uint16_t BPB_FATSz16; // FAT12/16每FAT扇区数
uint16_t BPB_SecPerTrk; // 每磁道扇区数
uint16_t BPB_NumHeads; // 磁头数
uint32_t BPB_HiddSec; // 隐藏扇区数
uint32_t BPB_TotSec32; // 32位扇区总数
uint32_t BPB_FATSz32; // FAT32每FAT扇区数
uint16_t BPB_ExtFlags; // 扩展标志
uint16_t BPB_FSVer; // 文件系统版本号
uint32_t BPB_RootClus; // 根目录起始簇号
uint16_t BPB_FSInfo; // FS info结构体的扇区号
uint16_t BPB_BkBootSec; // 引导扇区的备份扇区号
uint8_t BPB_Reserved0[12];
uint8_t BS_DrvNum; // int0x13的驱动器号
uint8_t BS_Reserved1;
uint8_t BS_BootSig; // 扩展引导标记
uint32_t BS_VolID; // 卷序列号
uint8_t BS_VolLab[11]; // 卷标
uint8_t BS_FilSysType[8]; // 文件系统类型
uint8_t BootCode[420]; // 引导代码、数据
uint16_t BS_TrailSig; // 结束标志0xAA55
} __attribute__((packed));
```
### struct fat32_FSInfo_t
&emsp; &emsp;该扇区存储了FAT32文件系统的一些参考信息。
```c
struct fat32_FSInfo_t
{
uint32_t FSI_LeadSig;
uint8_t FSI_Reserved1[480];
uint32_t FSI_StrucSig;
uint32_t FSI_Free_Count;
uint32_t FSI_Nxt_Free;
uint8_t FSI_Reserved2[12];
uint32_t FSI_TrailSig;
} __attribute__((packed));
```
**FSI_LeadSig**
&emsp;&emsp;FS info扇区标志符 数值为0x41615252
**FSI_Reserved1**
&emsp;&emsp;保留使用全部置为0
**FSI_StrucSig**
&emsp;&emsp;FS_Info扇区的另一个标志符数值为0x61417272
**FSI_Free_Count**
&emsp;&emsp;上一次记录的空闲簇数量,这是一个参考值
**FSI_Nxt_Free**
&emsp;&emsp;空闲簇的起始搜索位置,这是为驱动程序提供的参考值.
**FSI_Reserved2**
&emsp;&emsp;保留使用全部置为0
**FSI_TrailSig**
&emsp;&emsp;FS_Info扇区结束标志数值为0xaa550000
### struct fat32_Directory_t
&emsp;&emsp;短目录项结构体。
```c
struct fat32_Directory_t
{
unsigned char DIR_Name[11];
unsigned char DIR_Attr;
unsigned char DIR_NTRes;
unsigned char DIR_CrtTimeTenth;
unsigned short DIR_CrtTime;
unsigned short DIR_CrtDate;
unsigned short DIR_LastAccDate;
unsigned short DIR_FstClusHI;
unsigned short DIR_WrtTime;
unsigned short DIR_WrtDate;
unsigned short DIR_FstClusLO;
unsigned int DIR_FileSize;
} __attribute__((packed));
```
**DIR_Name**
&emsp;&emsp;目录项名称。前8bytes为基础名后3bytes为扩展名
**DIRAttr**
&emsp;&emsp;目录项属性。可选值有如下:
> - ATTR_READ_ONLY
>
> - ATTR_HIDDEN
>
> - ATTR_SYSTEM
>
> - ATTR_VOLUME_ID
>
> - ATTR_DIRECTORY
>
> - ATTR_ARCHIVE
>
> - ATTR_LONG_NAME
**DIR_NTRes**
&emsp;&emsp;该项为Windows下特有的表示区域通过该项的值表示基础名和扩展名的大小写情况。该项的值为`EXT|BASE`组合而成,其中,具有以下定义:
> BASE:LowerCase(8),UpperCase(0)
> EXT:LowerCase(16),UpperCase(0)
**DIR_CrtTimeTenth**
&emsp;&emsp;文件创建的毫秒级时间戳
**DIR_CrtTime**
&emsp;&emsp;文件创建时间
**DIR_CrtDate**
  文件创建日期
**DIR_LastAccDate**
&emsp;&emsp;文件的最后访问日期
**DIR_FstClusHI**
&emsp;&emsp; 文件起始簇号高16bit
**DIR_WrtTime**
&emsp;&emsp;最后写入时间
**DIR_WrtDate**
&emsp;&emsp;最后写入日期
**DIR_FstClusLO**
&emsp;&emsp; 文件起始簇号低16bit
**DIR_FileSize**
&emsp;&emsp;文件大小
### struct fat32_partition_info_t
&emsp;&emsp;该数据结构为FAT32分区的信息结构体并不实际存在于物理磁盘上。这个结构体在挂载文件系统时被创建作为文件系统的超级块的私有信息的一部分。
### struct fat32_inode_info_t
&emsp;&emsp;该结构体是VFS的inode结构体的私有信息部分的具体实现。
---
## 已知问题
1. 对目录项名称的检查没有按照标准严格实现
2. 当磁盘可用簇数量发生改变时未更新FS_Info扇区
3. 未填写目录项的时间字段
---
## TODO
- 完全实现VFS定义的文件接口
- 性能优化
---
## 参考资料
[FAT32 File System Specification - from Microsoft](http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc)

View File

@ -3,11 +3,11 @@
DragonOS的文件系统模块由VFS虚拟文件系统及具体的文件系统组成。
todo: 由于文件系统模块重构文档暂时不可用预计在2023年4月10日前补齐。
.. toctree::
:maxdepth: 1
:caption: 目录
vfs/index
fat32/index
rootfs/index
devfs/index

View File

@ -1,7 +0,0 @@
# rootFS 根文件系统
&emsp;&emsp;rootFS是DragonOS开启后挂载的第一个文件系统,它是一个基于内存的伪文件系统。rootfs的功能主要是在具体的磁盘文件系统被挂载之前为其他的伪文件系统提供挂载点使得系统能被正确的初始化。
&emsp;&emsp;rootfs的初始化将与VFS一同初始化。rootfs将为系统的各项文件系统的挂载创建dentry使得其他的文件系统如`devfs`等,能在磁盘文件系统被挂载之前被正确的初始化。
&emsp;&emsp;当磁盘根文件系统被挂载后,将调用`rootfs_umount()`函数。该函数将会把原本挂载在rootfs上的各种伪文件系统迁移到磁盘根文件系统上。当迁移完成后将会释放rootfs所占用的资源。

View File

@ -6,242 +6,6 @@
&emsp;&emsp;与VFS相关的系统调用有open(), read(), write(), create()等。
### dentry对象
## **TODO**
&emsp;&emsp;dentry的全称为directory entry是VFS中对于目录项的一种抽象数据结构。当读取具体文件系统时将会由创建dentry对象。dentry对象中包含了指向inode的指针。
&emsp;&emsp;dentry对象为真实文件系统上的目录结构建立了缓存一旦内存中存在对应路径的dentry对象我们就能直接获取其中的信息而不需要进行费时的磁盘操作。请注意dentry只是为提高文件系统性能而创建的一个缓存它并不会被写入到磁盘之中。
### inode对象
&emsp;&emsp;inode的全称叫做index node即索引节点。一般来说每个dentry都应当包含指向其inode的指针。inode是VFS提供的对文件对象的抽象。inode中的信息是从具体文件系统中读取而来也可以被刷回具体的文件系统之中。并且一个inode也可以被多个dentry所引用。
&emsp;&emsp;要查找某个路径下的inode我们需要调用父目录的inode的lookup()方法。请注意,该方法与具体文件系统有关,需要在具体文件系统之中实现。
### 文件描述符对象
&emsp;&emsp;当一个进程试图通过VFS打开某个文件时我们需要为这个进程创建文件描述符对象。每个文件对象都会绑定文件的dentry和文件操作方法结构体还有文件对象的私有信息。
&emsp;&emsp;文件描述符对象中还包含了诸如权限控制、当前访问位置信息等内容以便VFS对文件进行操作。
&emsp;&emsp;我们对文件进行操作都会使用到文件描述符具体来说就是要调用文件描述符之中的file_ops所包含的各种方法。
---
## 注册文件系统到VFS
&emsp;&emsp;如果需要注册或取消注册某个具体文件系统到VFS之中则需要以下两个接口
```c
#include<filesystem/vfs/VFS.h>
uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs);
uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs);
```
&emsp;&emsp;这里需要通过`struct vfs_filesystem_type_t`来描述具体的文件系统。
### struct vfs_filesystem_type_t
&emsp;&emsp;这个数据结构描述了具体文件系统的一些信息。当我们挂载具体文件系统的时候将会调用它的read_superblock方法以确定要被挂载的文件系统的具体信息。
&emsp;&emsp;该数据结构的定义在`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_filesystem_type_t
{
char *name;
int fs_flags;
// 解析文件系统引导扇区的函数为文件系统创建超级块结构。其中DPTE为磁盘分区表entryMBR、GPT不同
struct vfs_superblock_t *(*read_superblock)(void *DPTE, uint8_t DPT_type, void *buf, int8_t ahci_ctrl_num, int8_t ahci_port_num, int8_t part_num);
struct vfs_filesystem_type_t *next;
};
```
**name**
&emsp;&emsp;文件系统名称字符串
**fs_flags**
&emsp;&emsp;文件系统的一些标志位。目前DragonOS尚未实现相关功能。
**read_superblock**
&emsp;&emsp;当新的文件系统实例将要被挂载时,将会调用此方法,以读取具体的实例的信息。
**next**
&emsp;&emsp;指向链表中下一个`struct vfs_filesystem_type_t`的指针。
---
## 超级块(superblock)对象
&emsp;&emsp;一个超级块对象代表了一个被挂载到VFS中的具体文件系统。
### struct vfs_superblock_t
&emsp;&emsp;该数据结构为超级块结构体。
&emsp;&emsp;该数据结构定义在`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_superblock_t
{
struct vfs_dir_entry_t *root;
struct vfs_super_block_operations_t *sb_ops;
void *private_sb_info;
};
```
**root**
&emsp;&emsp;该具体文件系统的根目录的dentry
**sb_ops**
&emsp;&emsp;该超级块对象的操作方法。
**private_sb_info**
&emsp;&emsp;超级块的私有信息。包含了具体文件系统的私有的、全局性的信息。
### struct vfs_super_block_operations_t
&emsp;&emsp;该数据结构为超级块的操作接口。VFS通过这些接口来操作具体的文件系统的超级块。
&emsp;&emsp;该数据结构定义在`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_super_block_operations_t
{
void (*write_superblock)(struct vfs_superblock_t *sb);
void (*put_superblock)(struct vfs_superblock_t *sb);
void (*write_inode)(struct vfs_index_node_t *inode); // 将inode信息写入磁盘
};
```
**write_superblock**
&emsp;&emsp;将superblock中的信息写入磁盘
**put_superblock**
&emsp;&emsp;释放超级块
**write_inode**
&emsp;&emsp;将inode的信息写入磁盘
---
## 索引结点(inode)对象
&emsp;&emsp;每个inode对象代表了具体的文件系统之中的一个对象目录项
### struct vfs_index_node_t
&emsp;&emsp;该数据结构为inode对象的数据结构与文件系统中的具体的文件结点对象具有一对一映射的关系。
&emsp;&emsp;该数据结构定义在`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_index_node_t
{
uint64_t file_size; // 文件大小
uint64_t blocks; // 占用的扇区数
uint64_t attribute;
struct vfs_superblock_t *sb;
struct vfs_file_operations_t *file_ops;
struct vfs_inode_operations_t *inode_ops;
void *private_inode_info;
};
```
**file_size**
&emsp;&emsp;文件的大小。若为文件夹,则该值为文件夹内所有文件的大小总和(估计值)。
**blocks**
&emsp;&emsp;文件占用的磁盘块数(扇区数)
**attribute**
&emsp;&emsp;inode的属性。可选值如下
> - VFS_IF_FILE
>
> - VFS_IF_DIR
>
> - VFS_IF_DEVICE
**sb**
&emsp;&emsp;指向文件系统超级块的指针
**file_ops**
&emsp;&emsp;当前文件的操作接口
**inode_ops**
&emsp;&emsp;当前inode的操作接口
**private_inode_info**
&emsp;&emsp;与具体文件系统相关的inode信息。该部分由具体文件系统实现包含该inode在具体文件系统之中的特定格式信息。
### struct vfs_inode_operations_t
&emsp;&emsp;该接口为inode的操作方法接口由具体文件系统实现。并与具体文件系统之中的inode相互绑定。
&emsp;&emsp;该接口定义于`kernel/filesystem/vfs/VFS.h`中,结构如下:
```c
struct vfs_inode_operations_t
{
long (*create)(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode);
struct vfs_dir_entry_t *(*lookup)(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry);
long (*mkdir)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry, int mode);
long (*rmdir)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry);
long (*rename)(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry);
long (*getAttr)(struct vfs_dir_entry_t *dEntry, uint64_t *attr);
long (*setAttr)(struct vfs_dir_entry_t *dEntry, uint64_t *attr);
};
```
**create**
&emsp;&emsp;在父节点下创建一个新的inode并绑定到dest_dEntry上。
&emsp;&emsp;该函数的应当被`sys_open()`系统调用在使用了`O_CREAT`选项打开文件时调用从而创建一个新的文件。请注意传递给create()函数的`dest_dEntry`参数不应包含一个inode也就是说inode对象应当被具体文件系统所创建。
**lookup**
&emsp;&emsp;当VFS需要在父目录中查找一个inode的时候将会调用lookup方法。被查找的目录项的名称将会通过dest_dEntry传给lookup方法。
&emsp;&emsp;若lookup方法找到对应的目录项将填充完善dest_dEntry对象。否则返回NULL。
**mkdir**
&emsp;&emsp;该函数被mkdir()系统调用所调用用于在inode下创建子目录并将子目录的inode绑定到dEntry对象之中。
**rmdir**
&emsp;&emsp;该函数被rmdir()系统调用所调用用于删除给定inode下的子目录项。
**rename**
&emsp;&emsp;该函数被rename系统调用尚未实现所调用用于将给定的目录项重命名。
**getAttr**
&emsp;&emsp;用来获取目录项的属性。
**setAttr**
&emsp;&emsp;用来设置目录项的属性
&emsp;&emsp;VFS的设计与实现讲解