lab5学习
作者:互联网
文件系统所涉及的代码文件众多, 此处介绍部分代码文件的主要功能来为大家建立初步的印象。我们将通过 fs/fsformat.c 来创建磁盘镜像,在 fs/fs.c 中实现文件系统的基本功能函数,文件系统进程通过 fs/ide.c 与磁盘镜像进行交互,其进程主要运行在 fs/serv.c 上,并在 fs/serv.c 中通过 IPC 通信与用户进程 user/fsipc.c 内的通信函数进行交互;用户进程在 user/file.c 中实现用户接口,并在 user/fd.c 中引入文件描述符,抽象地操作文件、管道等内容。(注:fs.h 头文件存在于 fs/fs.h 和 include/fs.h 中,其内容并不相同)
一个磁盘块4096字节,一个扇区512字节
文件控制块(File 结构体)
文件服务流程
用户进程调用fd.c的函数read,wirte,seek等函数,fd.c的函数根据fd调用对应的ide的函数,比如ide为file,则file.c的函数调用fsipc.c的函数,fsipc.c中的fsipc_xxx通过设置请求,调用fsipc函数将请求发送到文件进程的REQVA的页面上,文件进程根据请求类型调用不同处理函数
Offset | Effect |
---|---|
0x0000 | Write: Set the offset (in bytes) from the beginning of the disk image. This offset will be used for the next read/write operation. 即设置与磁盘镜像开头的偏移 |
0x0008 | Write: Set the high 32 bits of the offset (in bytes). (*) 设置偏移量的高32位(以字节为单位) |
0x0010 | Write: Select the IDE ID to be used in the next read/write operation 选择要在下一次读/写操作中使用的IDE的ID |
0x0020 | Write: Start a read or write operation. (Writing 0 means a Read operat ion, a 1 means a Write operation.) 写入:启动读取或写操作。(写入0表示读取操作,写入1表示写入操作。) 写入一个字节即可 |
0x0030 | Read: Get status of the last operation. (Status 0 means failure, non-zero means success.) 读取:获取上一次操作的状态。(状态0表示失败,非零表示成功。) |
0x4000-0x41f | Read/Write: 512 bytes data buffer. 读/写:512字节的数据缓冲区。 |
make clean && make &&/OSLAB/gxemul -E testmips -C R3000 -M 64 -d gxemul/fs.img gxemul/vmlinux
磁盘块
struct Block {
uint8_t data[BY2BLK];
uint32_t type;
} disk[NBLOCK]; //block of disk
超级块
struct Super {
u_int s_magic; // Magic number: FS_MAGIC
u_int s_nblocks; // Total number of blocks on disk 1024
struct File s_root; // Root directory node
};
• s_magic:魔数,用于识别该文件系统,为一个常量。
• s_nblocks:记录本文件系统有多少个磁盘块,本文件系统为 1024。
• s_root为根目录,其f_type为FTYPE_DIR,f_name为”/”。
超级块初始化
disk[1].type = BLOCK_SUPER;
super.s_magic = FS_MAGIC;
super.s_nblocks = NBLOCK;
super.s_root.f_type = FTYPE_DIR;
strcpy(super.s_root.f_name, "/");
文件控制块
struct File {
u_char f_name[MAXNAMELEN]; // filename
u_int f_size; // file size in bytes
u_int f_type; // file type
u_int f_direct[NDIRECT];
u_int f_indirect;
struct File *f_dir; // the pointer to the dir where this file is in, valid only in memory.
u_char f_pad[BY2FILE - MAXNAMELEN - 4 - 4 - NDIRECT * 4 - 4 - 4];
};
f_name为文件名称,文件名的最大长度 MAXNAMELEN 值为 128。
f_size为文件的大小,单位为字节。
f_type为文件类型,有普通文件 (FTYPE_REG) 和文件夹 (FTYPE_DIR) 两种。
f_direct[NDIRECT]为文件的直接指针,每个文件控制块设有 10 个直接指针,用来记录文件的数据块在磁盘上的位置。每个磁盘块的大小为 4KB,也就是说,这十个直接指针能够表示最大 40KB的文件,而当文件的大小大于 40KB 时,就需要用到间接指针。
f_indirect指向一个间接磁盘块,用来存储指向文件内容的磁盘块的指针。为了简化计算,我们不使用间接磁
盘块的前十个指针。
f_dir指向文件所属的文件目录。
f_pad则是为了让整数个文件结构体占用一个磁盘块,填充结构体中剩下的字节。
dev
struct Dev {
int dev_id;
char *dev_name;
int (*dev_read)(struct Fd *, void *, u_int, u_int);
int (*dev_write)(struct Fd *, const void *, u_int, u_int);
int (*dev_close)(struct Fd *);
int (*dev_stat)(struct Fd *, struct Stat *);
int (*dev_seek)(struct Fd *, u_int);
};
fd
struct Fd {
u_int fd_dev_id;
u_int fd_offset;
u_int fd_omode;
};
State
struct Stat {
char st_name[MAXNAMELEN];
u_int st_size;
u_int st_isdir;
struct Dev *st_dev;
};
Filefd
struct Filefd {
struct Fd f_fd;
u_int f_fileid;
struct File f_file;
};
Open
struct Open {
struct File *o_file; // mapped descriptor for open file
u_int o_fileid; // file id
int o_mode; // open mode
struct Filefd *o_ff; // va of filefd page
};
磁盘块类型
enum {
BLOCK_FREE = 0,
BLOCK_BOOT = 1,
BLOCK_BMAP = 2,
BLOCK_SUPER = 3,
BLOCK_DATA = 4,
BLOCK_FILE = 5,
BLOCK_INDEX = 6,
};
文件打开类型
/* File open modes */
#define O_RDONLY 0x0000 /* open for reading only */
#define O_WRONLY 0x0001 /* open for writing only */
#define O_RDWR 0x0002 /* open for reading and writing */
#define O_ACCMODE 0x0003 /* mask for above modes */
#define O_CREAT 0x0100 /* create if nonexistent */
#define O_TRUNC 0x0200 /* truncate to zero length */
#define O_EXCL 0x0400 /* error if already exists */
#define O_MKDIR 0x0800 /* create directory, not regular file */
宏定义
宏 | 内容 | 作用 |
---|---|---|
BY2FILE | 256 | 一个文件控制块256字节 |
NINDIRECT | (BY2BLK/4) | 文件拥有磁盘块的最大数目 |
FILE2BLK | (BY2BLK/sizeof(struct File)) | 一个磁盘块中文件控制块的个数 |
BY2BLK | 4096 | 一个磁盘块4096字节 |
MAXNAMELEN | 128 | 文件名最大长度,其值为128,即,文件名不可以超过128个字符。事实上,由于最后一个字符必须是\0 ,因此,“有效”字符串最大长度为127. |
MAXPATHLEN | 1024 | |
NDIRECT | 10 | 文件控制块中直接块指针的数量 |
NINDIRECT | 1024 | 文件控制块中间接块指针可以管理的块数量上限 |
FTYPE_REG | 0 | regular file, 常规文件 |
DISKMAP | 0x10000000 | 磁盘块在内存中的va开始 |
DISKMAX | 0x40000000 | 磁盘块在内存中最多1GB |
INDEX2FD(i) | (FDTABLE+(i)*BY2PG) | 第i个fd在内存中的va |
代码中局部变量名字含义
名字 | 含义 |
---|---|
bno | 系统当前使用的磁盘块号 |
nblk | 文件的所占有磁盘总块数 |
fs.c函数
名字 | 作用 |
---|---|
u_int block_is_mapped(u_int blockno) | 检查磁盘块是否映射到虚拟地址 |
u_int va_is_mapped(u_int va) | 检查va是否被映射到磁盘块(二者一一对应) |
int file_get_block(struct File *f, u_int filebno, void **blk) | 读取文件的第filebo块到内存中,*blk被设置为对应的va |
int block_is_free(u_int blockno) | 通过位图中的特定位来判断指定的磁盘块是否被占用 |
u_int diskaddr(u_int blockno) | 返回磁盘块对应的虚拟地址 |
u_int va_is_dirty(u_int va) | 检查va的脏位 |
u_int block_is_dirty(u_int blockno) | 检查磁盘块是否有脏位 |
int map_block(u_int blockno) | 分配内存中的一个物理页给对应的磁盘块 |
void unmap_block(u_int blockno) | 解除磁盘块在内存中的映射,如果磁盘块被写过则写回磁盘 |
int read_block(u_int blockno, void **blk, u_int *isnew) | 将第blockno个磁盘块读入内存,*blk被设置为对应的va |
void write_block(u_int blockno) | 把在内存中的第blockno个磁盘块写回磁盘 |
int block_is_free(u_int blockno) | 判断第blockno个磁盘块是否空闲 |
void free_block(u_int blockno) | 在位图中设置第blockno个磁盘块为空闲 |
int alloc_block_num(void) | 找到第一个空闲的磁盘块,返回块号,并把这个磁盘块写回磁盘(只能位图先设置为1,再执行这个函数) |
int alloc_block(void) | 分配一个磁盘块,返回块号 |
int file_block_walk(struct File *f, u_int filebno, u_int **ppdiskbno, u_int alloc) | 将*ppdiskbno设置为文件f的第filebno块索引的地址 |
int file_map_block(struct File *f, u_int filebno, u_int *diskbno, u_int alloc) | 将diskbno设置为文件f的第fiebno块对应磁盘块的块号 |
int file_clear_block(struct File *f, u_int filebno) | 释放文件f的第filebno块 |
int file_get_block(struct File *f, u_int filebno, void **blk) | 将文件f的第filebno块读入磁盘,*blk设置为文件f的第filebno块在内存中对应磁盘块的va |
int file_dirty(struct File *f, u_int offset) | 对文件f的第offset / BY2BLK块设置脏位 |
int dir_lookup(struct File *dir, char *name, struct File **file) | 找到dir下对应的名为name的文件,*file设置为对应的文件控制块指针 |
int dir_alloc_file(struct File *dir, struct File **file) | 找到dir下的一个空闲fcb,*file指向这个fcb |
char * skip_slash(char *p) | 跳过'/' |
int walk_path(char *path, struct File **pdir, struct File **pfile, char *lastelem) | 找到path下的文件,*pfile指向这个文件的fcb,*pdir若不为0则指向最后一个目录 |
int file_open(char *path, struct File **file) | *file指向path下最后文件的fcb |
int file_create(char *path, struct File **file) | *file指向创建的文件控制块 |
void file_truncate(struct File *f, u_int newsize) | 调整文件大小,如果比原来小则释放文件块 |
int file_set_size(struct File *f, u_int newsize) | 调整文件大小,把f的目录flush一遍(写回磁盘) |
void file_flush(struct File *f) | 把文件f写回磁盘(f的文件块对应的磁盘块修改过才写回) |
void fs_sync(void) | 所有磁盘块若有脏位则写回磁盘 |
void file_close(struct File *f) | 文件f刷新到磁盘,f的目录也刷新到磁盘 |
int file_remove(char *path) | 把path对应的文件移除(找到文件,文件大小设置为0,刷新文件到磁盘,刷新文件的目录到磁盘) |
fsformat.c
名字 | 作用 |
---|---|
void reverse_block(struct Block *b) | 翻转磁盘块大小端 |
void init_disk() | 初始化磁盘0块,为BLOCK_BOOT;初始化块2开始为位图块,块1位super块 disk[1].type = BLOCK_SUPER; super.s_magic = FS_MAGIC; super.s_nblocks = NBLOCK; super.s_root.f_type = FTYPE_DIR; strcpy(super.s_root.f_name, "/"); |
int file_get_block(struct File *f, u_int filebno, void **blk) | 读取文件的第filebo块到内存中,*blk被设置为对应的va |
int block_is_free(u_int blockno) | 通过位图中的特定位来判断指定的磁盘块是否被占用 |
int next_block(int type) | 设置磁盘块的下一块为类型type,返回磁盘块id |
void flush_bitmap() | 刷新位图,当前磁盘块使用情况全部在位图标记 |
void finish_fs(char *name) | 将内存中的磁盘块写回磁盘 |
void save_block_link(struct File *f, int nblk, int bno) | 设置文件的第nblk块的对应的磁盘块为bno |
int make_link_block(struct File *dirf, int nblk) | 调用save_block_link设置索引,并把文件大小加上4096B |
struct File *create_file(struct File *dirf) | 创建目录下的一个文件,返回这个文件的文件控制块的指针 |
void write_file(struct File *dirf, const char *path) | 写文件到 |
fd.c
名字 | 作用 |
---|---|
int dev_lookup(int dev_id, struct Dev **dev) | 根据devid找到dev,*dev指向对应的dev |
int fd_alloc(struct Fd **fd) | 分配一个文件描述符,*fd指向这个描述符 |
void fd_close(struct Fd *fd) | 解除fd对内存页的映射 |
int fd_lookup(int fdnum, struct Fd **fd) | 找第fdnum个文件描述符,*fd指向它 |
u_int fd2data(struct Fd *fd) | 返回fd对应的文件的va地址 |
int fd2num(struct Fd *fd) | 返回对应的fd是第几个fd |
int num2fd(int fd) | 返回第fd个文件描述符的地址 |
int close(int fdnum) | 关闭第fdnum个文件描述符及其对应的文件 |
void close_all(void) | 关闭所有文件 |
int read(int fdnum, void *buf, u_int n) | 第fdnum个fd对应的文件读n个字节到buf |
int write(int fdnum, const void *buf, u_int n) | 第fdnum个fd对应的文件写n个字节从buf |
int seek(int fdnum, u_int offset) | 设置第fdnum个fd对应的文件的偏移量为offset |
标签:文件,struct,int,File,lab5,学习,file,磁盘 来源: https://www.cnblogs.com/sdjasj/p/16379944.html