Commit cd18dd9e authored by tempdragon's avatar tempdragon Committed by /remake
Browse files

* Change the offset divisor to T::CACHE_SZ

* Change short name dot trim to trim only the leading dots
* Updated the FAT tutorial.
Showing with 1231 additions and 152 deletions
+1231 -152
bash-5.1.16/
# cargo config
os/Cargo.lock
user/Cargo.lock
os/src/linker.ld
# IDE config
.idea/
.vscode/
# kernel build
os/target/
# user programs build
user/riscv64/
user/target/
# a copy of user programs debug build in "user/target/*"(for gdb)
os/user/
# developing, should be invisible in main branch
os/src/fs/fatfs/*
# unsorted
os/output.txt
os/logs/
os/src/link_app.S
os/last-*
tools/
user/.ccls-cache/
# Doc .org
Doc/**/*.org
......@@ -21,8 +21,9 @@
## Qemu的多核启动问题
如果你的操作系统我们从Makefile
反之,如果你
如果你的操作系统是不支持多核的,错误的打开可能会导致莫名的崩溃,反之,如果你支持了多核却没有从QEMU上打开多核,你的代码会无法测试.
单核系统下QEMU多核错误打开的
## 内存问题
......
......@@ -121,7 +121,7 @@
}
注意C语言注释提到,Win95将纯扩展名形式的文件名的扩展名的作为文件名,而完全不设"扩展名"
文件名最后一个字符为'.'和文件全局没有出现过一次'.',不存在扩展名
文件名最后一个字符为'.'和文件全局没有出现过一次'.',不存在扩展名
<a id="org7aa5328"></a>
......
Doc/fs/fat.md 0 → 100644
+ 1190
0
View file @ cd18dd9e
This diff is collapsed.
* 前言
本文档遵循GNUDOC协议,用户有权自由使用和传播.
** 简介
这是一份如何从rCore::EasyFS改造出FAT32文件系统"前端"的教程(也就是说本文件系统支持多种后端)
本文假设阅读者对FAT文件系统原理已经有了一定的了解(具体来说,和阅读并理解Tanenbaum的 /Modern Operating System/ FAT部分相当的基础知识), 但对部分技术细节(如短文件名的生成)不完全了解的
** 参考文献
*** 常见
**** 微软的FAT系列文件系统(exFAT除外)技术规格和夏新手机厂技术人员04年的翻译版(网传中文版)
微软的技术资料叫做fatgen103.pdf,基本可以搜索到;
中文翻译文件: FAT32中文版.pdf
注意,后者在一些字段长度上有错,需要配合原版进行阅读
**** 哈佛大学操作系统原理课的课程Slide(PDF)和作业指导
用国外的搜索引擎搜索下列字符串
#+begin_src
FAT32 File Structure
Prof. James L. Frankel
Harvard University
Version of 9:45 PM 24-Mar-2021
#+end_src
*** 不太常见的资料
**** 西北工业大学刘明轩学长的FAT32文件系统代码阅读汇报
**** 日期为20090808,邮箱为gdfgd0218@126.com的大佬提供的FAT32的技术资料
"FAT32文件系统详解.pdf"
*** 上述文献的阅读建议
最正宗的微软的技术规格自然是一切的根本,但不建议直接阅读,毕竟很多的技术规范在实际中不见得有人遵守,
甚至你不实现对于比赛和实际使用的影响也没有想象中大,而且其中也不都是和现代操作系统使用相关的,
而是向下兼容采取的权宜之计;但是,对于实现真正商品级的产品而不是玩具,这些规格必须遵守.
中文版的资料在FAT本身的文件系统的文件分配表(File Allocation Table)的原理上叙述比微软要详细的多,实际上,其用整整几页(Pg9~Pg11)叙述的FAT的文件识别原理
在英文版中几乎一笔带过,还不如你在操作系统课程上学得来的详细,而常见的中文版已经用下划线标出了笔记,所以体验还行.但对于形象的解释,其实后两个"不太常见的资料"也不错
文件目录项部分哈佛的资料还算不错,除了技术规格还讲了很多实现上需要绕过的坑,比技术规格信息多,但技术规格也可看一看
短文件名生成...建议看Linux代码
** 鸣谢
感谢我的指导老师,两位队友对我这种不靠谱的人的理解和支持和(主要是)容忍.
最后,请让我膜拜伟大的THU和Harvard University的各位大佬orz
(虽然可能只是他们一次信手拈来的作业罢了),也感谢这些巨佬和前辈的付出给我们提供了良好的框架和学习的对象
* FAT文件系统布局
出于简单考虑,本文献不考虑多分区/分区表处理
而实际上,如果有需要,可以在原本的SDCard层上再抽象出一个分区对象,然后按照常规思路继续实现.
** FAT32 Layout
*** Reserved Area
**** DBR(Dos Boot Record, not mentioned in FAT32 layout)
In our implementation, BS is used along with BPB.
Besides, the items of the two are mixed instead of separated.
***** (DOS)Boot Sector
marked with BS.
***** BPB
*** FAT Region[(usu. 2)]
*** File and Directory Data Region
* rCore FS/VFS 布局 & 设计
以下资料按照自顶向下的思路写成,结构如下:
** Inode(vfs.rs)
管理索引节点(即文件控制块)数据结构,并实现文件创建/文件打开/文件读写等成员函数来向上支持文件操作相关的系统调用的处理,数据结构只有`Inode`.
** Disk Manager layer(efs.rs)
合并了上述核心数据结构和磁盘布局所形成的磁盘文件系统数据结构,以及创建/打开文件系统的相关处理和磁盘块的分配和回收处理
数据结构只有`EasyFileSystem`
** Disk block allocation layer(bitmap.rs)
数据结构只有`Bitmap`一个,
其对应的函数如下
#+begin_src rustic
pub fn new(start_block_id: usize, blocks: usize) -> Self;
pub fn alloc(&self, block_device: &Arc<dyn BlockDevice>) -> Option<usize>;
pub fn dealloc(&self, block_device: &Arc<dyn BlockDevice>, bit: usize);
pub fn maximum(&self) -> usize;
#+end_src
另外加上一个decomposition,是easy-fs中用于压缩位图的函数,对我们用处不大
** Disk(layout.rs)
Layout磁盘上的超级块、位图、索引节点、数据块、目录项等核心数据结构和相关处理, 这里都是磁盘上的实际操作和磁盘上的数据结构,包括:
`SuperBlock` (文件系统元数据),
`DiskInode` (磁盘上的文件元数据),
`DirEntry` (磁盘上的目录项)
** BlockCache(block_cache.rs)
在内存中建立磁盘上的内容的缓存.主要结构为: `BlockCache` 和 `BlockCacheManager`
** BlockDevice(the Driver)(block_dev.rs)
抽象的块设备,用于从外部储存而非缓存读入内容
* 面向FAT32的需求进行改造
** 块分配(bitmap.rs)
FAT的块分配使用的数据结构为链表,所以其设计应当比easy-fs简单很多,但还是需要重新适配其代码.具体用到的函数有:
** Inode结构的合并和改造
考虑到FAT块分配和块检索是一体的,且其块的读取相对简单,加上easy-fs中的inode本身也基本就是其封装,我们可以将其`DiskInode`和`Inode`两个数据结构合并为一个,从而减少层级.
具体来说,其对外接口应当保留,如
** 目录项
由于历史原因,FAT的目录项相比easy-fs复杂很多,分为长目录项和短目录项,通过一个短目录项和多个长目录项的组合达到常规情况下同构多目录项即可完成的功能.
关于其遍历有多个不同的思路,我们推荐将其通过两层iterator结构视为一层
** 后端的trait化
为了更好地优化,我们建议将FAT32的Cache Manager进行了trait化, 具体来说,
* Inode之争
早期我的,也包括去年一些学校的设计,是将每个
但我们经过对Linux的测试,发现其实
* Short Name generation
本来这个内容应当被归入Layout或者改名/创建文件夹,但考虑到他的难度,计划单列出一节.
这个部分参考资料不多,部分常见的实现是不完整的,某些的生成的尾部数字扩展恒为1,且没有判断重复的能力;哈佛的pdf直接转发微软的技术规格[[fatgen103.pdf]],后者中的资料语焉不详,夏新手机厂中文版的翻译版和英文只是简单的翻译关系.本文献无意重复相关的资料和结果,但是我们可以使用Linux作为参考代码,分析相关内容.本文献的这部分呈现了笔者有关算法的理解和分析
[[https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/fat/namei_vfat.c]]
通过分析函数`vfat_create_shortname`,我们可以得出其具体的情况(该部分由于不属于完整的代码,我们将其放在单独的"Linux下的短目录名生成"文档中)
** 摸Linux过河
Linux的实现和Microsoft似乎有所不同,其是从寻找扩展名开始的序号
*** 需求分析
首先考虑到我们的操作系统暂时不支持,可以只考虑英文的情况因此其代码的UTF8转换可以简化
当前的系统多数使用NT版本而非95的,可以少一些分支.
另外,数字结尾的生成算法过于复杂,可以考虑借鉴Linux写法
*** 具体实现
* 目录树/文件打开表
文件系统中
** unsafe万岁
在队友的建议下,用unsafe裸指针解引用的方式解决编译通过的问题.大致思路如下:
#+begin_src rust
pub fn open_tab(file: OpenTabCmd<T, F>) -> Option<Arc<Self>> {
static mut ORG_LI: usize = 0;
unsafe {
if ORG_LI == 0 {
*(ORG_LI as *mut Mutex<alloc::collections::
BTreeMap<u64, Arc<Self>>>) =
Mutex::new(alloc::collections::BTreeMap::new());
}
//...
None
}
#+end_src
首先,函数是Inode<T,F>的关联函数,在其中使用静态变量`ORG_LI`保持文件打开表.
但是要注意,Rust中由于默认不允许关联函数使用泛型,所有的Inode<T,F>会共用一个open_tab(). 所以如果严谨的方法是利用非静态变量的TypeId(请自行搜索)建立一个BTreeMap然后对各个类型一一对应,但比较麻烦且对我们的两种运行环境没有意义(系统和FUSE模拟),所以完全可以忽略.
另外,初始化的时候,如为多核,理论上Rust不使用原子操作保证其一致性,所以需要先完成初始化再打开第二个核,否则会出现竞争.
然后是之后的命令设计.我们注意到,为了方便处理,此函数使用了OpenTabCmd<T,F>进行文件打开表的命令,其定义为:
#+begin_src rust
pub enum OpenTabCmd<T: CacheManager, F: CacheManager> {
InsertFile(Arc<Inode<T, F>>),
GetFileByInode(u64),
DropFileByInode(u64),
AddInode(u64, u64),
}
#+end_src
但是这种方法我们并没有使用,如果你有需要,可以
* 后续的思路
事实上,由上述分析,EasyFS的代码中的文件系统可以继续抽象,将其Inode继续抽象出来,然后使用泛型
......@@ -127,7 +127,7 @@ impl<T: CacheManager> Fat<T> {
/// n is the ordinal number of the cluster
pub fn this_fat_ent_offset(&self, n: u32) -> usize {
let fat_offset = n * 4;
(fat_offset % (self.byts_per_sec as u32)) as usize
(fat_offset % (T::CACHE_SZ as u32)) as usize
}
/// Assign the cluster entry to `current` to `next`
fn set_next_clus(&self, block_device: &Arc<dyn BlockDevice>, current: u32, next: u32) {
......
......@@ -322,7 +322,9 @@ impl FATDirEnt {
&base[i..]
}
};
let base = base.trim_matches('.');
// not sure if this should be a `trim_matches` or a `trim_start_matches`
let base = base.trim_start_matches('.');
let base = if ext.len() != 0 || base.len() != 0 {
format!("{: <8}", base.split_at(8.min(base.len())).0)
} else {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment