实验八:文件系统
练习0:填写已有实验
使用meld可以简单地将前几个lab的代码填入lab8中,其他实验完成的部分基本直接合并即可,部分代码需要做出修改但要结合练习1和练习2的内容,在练习1和练习2中指出
练习1:完成读文件操作的实现
1、ucore文件系统架构
以任一文件作为测试用例,ucore的执行顺序如下,其文件系统架构主要由四部分组成
- 通用文件系统访问接口层:该层提供了一个从用户空间到文件系统的标准访问接口。这一层访问接口让应用程序能够通过一个简单的接口获得ucore内核的文件系统服务
- 文件系统抽象层:向上提供一个一致的接口给内核其他部分(文件系统相关的系统调用实现模块和其他内核功能模块)访问,向下提供一个同样的抽象函数指针列表和数据结构屏蔽不同文件系统的实现细节
- Simple FS文件系统层:一个基于索引方式的简单文件系统实例,向上通过各种具体函数实现以对应文件系统抽象层提出的抽象函数,向下访问外设接口
- 外设接口层:向上提供device访问接口屏蔽不同硬件细节。向下实现访问各种具体设备驱动的接口,比如disk设备接口/串口设备接口/键盘设备接口等
文件系统测试用例
user/*.c
1.通用文件系统访问接口层
write user/libs/file.c
sys_write user/libs/syscall.c
syscall user/libs/syscall.c
sys_write kern/syscall/syscall.c
2.文件系统抽象层Virtual File System
sysfile_write kern/fs/sysfile.c
file_write kern/fs/file.c
vop_write kern/fs/vfs/inode.h
3.文件系统Simple File System
sfs_write kern/fs/sfs/sfs_inode.c
sfs_wbuf kern/fs/sfs/sfs_io.c
4.外部I/O设备接口层
dop_io kern/fs/devs/dev.h
disk0_io kern/fs/devs/dev_disk0.c
硬件驱动
ide_write_secs kern/driver/ide.c
在ucore系统中文件系统架构包含四类主要的数据结构,分别是:
- 超级块(SuperBlock):它主要从文件系统的全局角度描述特定文件系统的全局信息,它的作用范围是整个OS空间
- 索引节点(inode):它主要从文件系统的单个文件的角度它描述了文件的各种属性和数据所在位置,它的作用范围是整个OS空间
- 目录项(dentry):它主要从文件系统的文件路径的角度描述了文件路径中的特定目录,它的作用范围是整个OS空间
- 文件(file),它主要从进程的角度描述了一个进程在访问文件时需要了解的文件标识,文件读写的位置,文件引用情况等信息,它的作用范围是某一具体进程
2、Virtual File System分析
文件系统抽象层是把不同文件系统的对外共性接口提取出来,形成一个函数指针数组,这样,通用文件系统访问接口层只需访问文件系统抽象层,而不需关心具体文件系统的实现细节和接口。
进程在内核中直接访问的文件接口数据结构及文件相关信息数据结构定义在kern/fs/fs.h
和kern/fs/file.h
中
struct proc_struct{ //进程控制块
...
struct files_struct *filesp; //文件接口
};
struct files_struct {
struct inode *pwd; //进程当前执行目录的内存inode指针
struct file *fd_array; //进程打开文件的集合fd_array[]即filemap
int files_count; //打开文件的个数
semaphore_t files_sem; //确保互斥访问
};
struct file {
enum {
FD_NONE, FD_INIT, FD_OPENED, FD_CLOSED,
} status; //文件的当前状态
bool readable; //是否可读
bool writable; //是否可写
int fd; //文件在fd_array[]即filemap中的索引
off_t pos; //访问文件的当前位置
struct inode *node; //该文件对应的inode指针
int open_count; //打开此文件的次数
};
当创建一个进程后,子进程将会初始化或复制父进程的files_struct
,因此在练习0中需要修改do_fork
的部分代码,加上如下代码用以复制文件信息
int
do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) {
...
if(copy_files(clone_flags, proc) !=0){ //复制父进程的file_struct,若出错进入错误处理
goto bad_fork_cleanup_fs;
}
...
bad_fork_cleanup_fs:
put_files(proc);
...
}
VFS中的另一类重要数据结构是inode
,位于内存的索引节点,负责把不同文件系统的特定索引节点信息统一封装,并定义了能够操作此节点的函数,inode
定义在kern/fs/vfs/inode.h
struct inode {
union { //包含不同文件系统特定inode信息的union成员变量
struct device __device_info; //设备文件系统内存inode信息
struct sfs_inode __sfs_inode_info; //SFS文件系统内存inode信息
} in_info;
enum {
inode_type_device_info = 0x1234,
inode_type_sfs_inode_info,
} in_type; //此inode所属文件系统类型
int ref_count; //此inode的引用计数
int open_count; //打开此inode对应文件的个数
struct fs *in_fs; //inode所在的抽象的文件系统,包含访问文件系统的函数指针
const struct inode_ops *in_ops; //抽象的inode操作,包含访问inode的函数指针
};
struct fs {
union {
struct sfs_fs __sfs_info;
} fs_info; //具体文件系统信息,这里只有SFS
enum {
fs_type_sfs_info,
} fs_type; //文件系统类型
int (*fs_sync)(struct fs *fs); //写回修改
struct inode *(*fs_get_root)(struct fs *fs); //返回文件系统的root inode
int (*fs_unmount)(struct fs *fs); //解除挂载的文件系统
void (*fs_cleanup)(struct fs *fs); //清除文件系统
};
struct inode_ops {
unsigned long vop_magic;
int (*vop_open)(struct inode *node, uint32_t open_flags);
int (*vop_close)(struct inode *node);
...
};
3、Simple File System分析
(1)SFS文件系统的基本布局为
| superblock | root-dir inode | freemap | inode/file data/dir data blocks |
struct sfs_fs {
struct sfs_super super; //超级块superblock
struct device *dev; //挂载的设备
struct bitmap *freemap; //空闲区域freemap
bool super_dirty;