练习#
课后练习#
编程题#
* 扩展easy-fs文件系统功能,扩大单个文件的大小,支持三重间接inode。
* 扩展内核功能,支持stat系统调用,能显示文件的inode元数据信息。
** 扩展内核功能,支持mmap系统调用,支持对文件的映射,实现基于内存读写方式的文件读写功能。
** 扩展easy-fs文件系统功能,支持二级目录结构。可扩展:支持N级目录结构。
*** 扩展easy-fs文件系统功能,通过日志机制支持crash一致性。
问答题#
* 文件系统的功能是什么?
** 目前的文件系统只有单级目录,假设想要支持多级文件目录,请描述你设想的实现方式,描述合理即可。
** 软链接和硬链接是干什么的?有什么区别?当删除一个软链接或硬链接时分别会发生什么?
*** 在有了多级目录之后,我们就也可以为一个目录增加硬链接了。在这种情况下,文件树中是否可能出现环路(软硬链接都可以,鼓励多尝试)?你认为应该如何解决?请在你喜欢的系统上实现一个环路,描述你的实现方式以及系统提示、实际测试结果。
* 目录是一类特殊的文件,存放的是什么内容?用户可以自己修改目录内容吗?
** 在实际操作系统中,如Linux,为什么会存在大量的文件系统类型?
** 可以把文件控制块放到目录项中吗?这样做有什么优缺点?
** 为什么要同时维护进程的打开文件表和操作系统的打开文件表?这两个打开文件表有什么区别和联系?
** 文件分配的三种方式是如何组织文件数据块的?各有什么特征(存储、文件读写、可靠性)?
** 如果一个程序打开了一个文件,写入了一些数据,但是没有及时关闭,可能会有什么后果?如果打开文件后,又进一步发出了读文件的系统调用,操作系统中各个组件是如何相互协作完成整个读文件的系统调用的?
*** 文件系统是一个操作系统必要的组件吗?是否可以将文件系统放到用户态?这样做有什么好处?操作系统需要提供哪些基本支持?
实验练习#
实验练习包括实践作业和问答作业两部分。
理解文件系统比较费事,编程难度适中
实践作业#
硬链接#
硬链接要求两个不同的目录项指向同一个文件,在我们的文件系统中也就是两个不同名称目录项指向同一个磁盘块。
本节要求实现三个系统调用 sys_linkat、sys_unlinkat、sys_stat
。
linkat:
syscall ID: 37
功能:创建一个文件的一个硬链接, linkat标准接口 。
C接口:
int linkat(int olddirfd, char* oldpath, int newdirfd, char* newpath, unsigned int flags)
Rust 接口:
fn linkat(olddirfd: i32, oldpath: *const u8, newdirfd: i32, newpath: *const u8, flags: u32) -> i32
- 参数:
olddirfd,newdirfd: 仅为了兼容性考虑,本次实验中始终为 AT_FDCWD (-100),可以忽略。
flags: 仅为了兼容性考虑,本次实验中始终为 0,可以忽略。
oldpath:原有文件路径
newpath: 新的链接文件路径。
- 说明:
为了方便,不考虑新文件路径已经存在的情况(属于未定义行为),除非链接同名文件。
返回值:如果出现了错误则返回 -1,否则返回 0。
- 可能的错误
链接同名文件。
unlinkat:
syscall ID: 35
功能:取消一个文件路径到文件的链接, unlinkat标准接口 。
C接口:
int unlinkat(int dirfd, char* path, unsigned int flags)
Rust 接口:
fn unlinkat(dirfd: i32, path: *const u8, flags: u32) -> i32
- 参数:
dirfd: 仅为了兼容性考虑,本次实验中始终为 AT_FDCWD (-100),可以忽略。
flags: 仅为了兼容性考虑,本次实验中始终为 0,可以忽略。
path:文件路径。
- 说明:
为了方便,不考虑使用 unlink 彻底删除文件的情况。
返回值:如果出现了错误则返回 -1,否则返回 0。
- 可能的错误
文件不存在。
fstat:
syscall ID: 80
功能:获取文件状态。
C接口:
int fstat(int fd, struct Stat* st)
Rust 接口:
fn fstat(fd: i32, st: *mut Stat) -> i32
- 参数:
fd: 文件描述符
st: 文件状态结构体
#[repr(C)] #[derive(Debug)] pub struct Stat { /// 文件所在磁盘驱动器号,该实验中写死为 0 即可 pub dev: u64, /// inode 文件所在 inode 编号 pub ino: u64, /// 文件类型 pub mode: StatMode, /// 硬链接数量,初始为1 pub nlink: u32, /// 无需考虑,为了兼容性设计 pad: [u64; 7], } /// StatMode 定义: bitflags! { pub struct StatMode: u32 { const NULL = 0; /// directory const DIR = 0o040000; /// ordinary regular file const FILE = 0o100000; } }
实验要求#
实现分支:ch7-lab
实验目录要求不变
通过所有测例
在 os 目录下
make run TEST=1
加载所有测例,test_usertest
打包了所有你需要通过的测例,你也可以通过修改这个文件调整本地测试的内容。你的内核必须前向兼容,能通过前一章的所有测例。
注解
如何调试 easy-fs
如果你在第一章练习题中已经借助 log
crate 实现了日志功能,那么你可以直接在 easy-fs
中引入 log
crate,通过 log::info!/debug!
等宏即可进行调试并在内核中看到日志输出。具体来说,在 easy-fs
中的修改是:在 easy-fs/Cargo.toml
的依赖中加入一行 log = "0.4.0"
,然后在 easy-fs/src/lib.rs
中加入一行 extern crate log
。
你也可以完全在用户态进行调试。仿照 easy-fs-fuse
建立一个在当前操作系统中运行的应用程序,将测试逻辑写在 main
函数中。这个时候就可以将它引用的 easy-fs
的 no_std
去掉并使用 println!
进行调试。
问答作业#
无
实验练习的提交报告要求#
简单总结本次实验与上个实验相比你增加的东西。(控制在5行以内,不要贴代码)
完成问答问题
(optional) 你对本次实验设计及难度的看法。