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
posted @ 2022-06-15 21:40  繁华丶人间  阅读(96)  评论(0编辑  收藏  举报