// (Isnew lets callers like file_get_block clear any memory-only // fields from the disk blocks when they come in off disk.) // intread_block(u_int blockno, void **blk, u_int *isnew) { /* Step 1: 检查 blockno 的合法性 */ if (super && blockno >= super->s_nblocks) { user_panic("reading non-existent block %08x\n", blockno); } /* Step 2: 检查磁盘中块是否有效,如果磁盘块是 free 的,说明里面没东西 */ // Hint: 读之前要先读一下 bitmap 是不是倒进内存里了 // If the bitmap is NULL, indicate that we haven't read bitmap from disk to memory // until now. So, before we check if a block is free using `block_is_free`, we must // ensure that the bitmap blocks are already read from the disk to memory. if (bitmap && block_is_free(blockno)) { user_panic("reading free block %08x\n", blockno); } /* Step 3: 找到待写入的虚拟地址 */ void *va = diskaddr(blockno); /* Step 4: 读入内存,更新 *isnew */ // Hint: 如果已经 mapped 则只更新 isnew,否则先 alloc 页面,再 read if (block_is_mapped(blockno)) { // 已经 mapped if (isnew) { *isnew = 0; } } else { // 未 mapped if (isnew) { *isnew = 1; } syscall_mem_alloc(0, va, PTE_D); // 申请页面 ide_read(0, blockno * SECT2BLK, va, SECT2BLK); // 使用 ide_read 读入页面 } /* Step 5: 赋值 *blk */ if (blk) { *blk = va; } return0; }
这两个函数主要负责管理内存中的 bitmap,带 num 的函数负责申请块,不带的则直接完成了申请+映射
// Overview: // Search in the bitmap for a free block and allocate it. // // Return -E_NO_DISK if we are out of blocks. intalloc_block_num(void) { int blockno; // walk through this bitmap, find a free one and mark it as used, then sync // this block to IDE disk (using `write_block`) from memory. for (blockno = 3; blockno < super->s_nblocks; blockno++) { if (bitmap[blockno / 32] & (1 << (blockno % 32))) { // the block is free bitmap[blockno / 32] &= ~(1 << (blockno % 32)); write_block(blockno / BIT2BLK + 2); // write to disk. return blockno; } } // no free blocks. return -E_NO_DISK; }
// Overview: // Allocate a block -- first find a free block in the bitmap, then map it into memory. intalloc_block(void) { int r, bno; // Step 1: find a free block. if ((r = alloc_block_num()) < 0) { // failed. return r; } bno = r;
// Step 2: map this block into memory. if ((r = map_block(bno)) < 0) { free_block(bno); return r; }
voidread_super(void) { int r; void *blk; /* Step 1: 读取 super 块,blockno = 1 */ if ((r = read_block(1, &blk, 0)) < 0) { user_panic("cannot read superblock: %e", r); } super = blk; // 把 super 块缓存地址所在的指针赋给进程中的变量 super,便于后续使用 /* Step 2: 检查 MAGIC NUMBER */ if (super->s_magic != FS_MAGIC) { user_panic("bad file system magic number %x %x", super->s_magic, FS_MAGIC); } /* Step 3: 检查磁盘大小,超过块缓存允许的大小就会 panic,对应了 Thinking */ if (super->s_nblocks > DISKMAX / BY2BLK) { user_panic("file system is too large"); } debugf("superblock is good\n"); }
// Overview: // Read and validate the file system bitmap. // // Hint: // 把磁盘中表示 bitmap 的几个磁盘块全读取到内存中,并设置一个数组指向它们,代表内存中的 bitmap // For each block i, user_assert(!block_is_free(i))) to check that they're all marked as in use. voidread_bitmap(void) { u_int i; void *blk = NULL; /* Step 1: 计算块数量,并进行 */ u_int nbitmap = super->s_nblocks / BIT2BLK + 1; for (i = 0; i < nbitmap; i++) { read_block(i + 2, blk, 0); }
// Overview: // Mark this block as dirty (cache page has changed and needs to be written back to disk). intdirty_block(u_int blockno) { void *va = diskaddr(blockno); if (!va_is_mapped(va)) { return -E_NOT_FOUND; } if (va_is_dirty(va)) { return0; } return syscall_mem_map(0, va, 0, va, PTE_D | PTE_DIRTY); }
fs_init
这个函数初始化了文件系统.初始化后,super 和 bitmap 都被缓存到了文件管理进程中
// Overview: // Initialize the file system. // Hint: // 1. read super block. // 2. check if the disk can work. // 3. read bitmap blocks from disk to memory. voidfs_init(void) { read_super(); // 缓存 super 块 check_write_block(); // 一个测试函数 read_bitmap(); // 缓存 bitmap 所用块 }
在 MOS 中,描述文件使用文件控制块 File,其定义于 user/include/fs.h,每个控制块的大小为 256 Byte
structFile { char f_name[MAXNAMELEN]; // filename uint32_t f_size; // file size in bytes uint32_t f_type; // file type uint32_t f_direct[NDIRECT]; uint32_t f_indirect; // points to a block contains pointers
structFile *f_dir;// the pointer to the dir where this file is in, valid only in memory. char f_pad[BY2FILE - MAXNAMELEN - (3 + NDIRECT) * 4 - sizeof(void *)]; } __attribute__((aligned(4), packed));
structOpen { structFile *o_file;// mapped descriptor for open file u_int o_fileid; // file id int o_mode; // open mode structFilefd *o_ff;// va of filefd page };
// Overview: // Open "path". // // Post-Condition: // On success set *pfile to point at the file and return 0. // On error return < 0. intfile_open(char *path, struct File **file) { return walk_path(path, 0, file, 0); }
// Overview: // Set *blk to point at the filebno'th block in file f. intfile_get_block(struct File *f, u_int filebno, void **blk) { int r; u_int diskbno; u_int isnew;
// Step 2: 从磁盘中读该磁盘号的数据到 blk 中 if ((r = read_block(diskbno, blk, &isnew)) < 0) { return r; } return0; } // OVerview: // Set *diskbno to the disk block number for the filebno'th block in file f. // If alloc is set and the block does not exist, allocate it. // 完整的封装 intfile_map_block(struct File *f, u_int filebno, u_int *diskbno, u_int alloc) { int r; uint32_t *ptr;
// Step 3: 类似的,给指针赋值 *diskbno = *ptr; return0; } // Overview: // 获取指定文件 f 的指定块在磁盘中的块号,alloc == 1 && NINDIRECT 时需要申请指针块 // // Post-Condition: // Return 0 on success, and set *ppdiskbno to the pointer to the target block. // Return -E_NOT_FOUND if the function needed to allocate an indirect block, but alloc was 0. // Return -E_NO_DISK if there's no space on the disk for an indirect block. // Return -E_NO_MEM if there's not enough memory for an indirect block. // Return -E_INVAL if filebno is out of range (>= NINDIRECT). intfile_block_walk(struct File *f, u_int filebno, uint32_t **ppdiskbno, u_int alloc) { int r; uint32_t *ptr; uint32_t *blk;
// Step 4: 同步自身内容和目录内容至磁盘内 file_flush(f); if (f->f_dir) { file_flush(f->f_dir); }
return0; }
file_sync
啊我整个大的.jpg
对于整个块缓存空间来说,同步所有写入过的块
// Overview: // Sync the entire file system. A big hammer. voidfs_sync(void) { int i; for (i = 0; i < super->s_nblocks; i++) { if (block_is_dirty(i)) { write_block(i); } } }
dir_lookup - Exercise 5.8
遍历目录中的每个文件,查找名称是否相同;同时,遍历的方式是先块后文件,详细可以看代码
// Overview: // 查找当前路径下 dir 中字符串 name 指向的文件,返回文件控制块 file intdir_lookup(struct File *dir, char *name, struct File **file) { int r; /* Step 1: 通过占用块计算目录 dir 大小 */ u_int nblock; /* Exercise 5.8: Your code here. (1/3) */ nblock = dir->f_size / BY2BLK + (dir->f_size % BY2BLK == 0) ? 0 : 1; /* Step 2: 遍历目录中的每个文件: */ // 2.1: 遍历每个文件块 for (int i = 0; i < nblock; i++) { // 获取目录中的每个磁盘块 void *blk; /* Exercise 5.8: Your code here. (2/3) */ file_get_block(dir, i, &blk); structFile *files = (struct File *)blk;