Lab9: file system
Large files
(1). 在fs.h中添加宏定义
#define NDIRECT 11#define NINDIRECT (BSIZE / sizeof(uint))#define NDINDIRECT ((BSIZE / sizeof(uint)) * (BSIZE / sizeof(uint)))#define MAXFILE (NDIRECT + NINDIRECT + NDINDIRECT)#define NADDR_PER_BLOCK (BSIZE / sizeof(uint)) // 一个块中的地址数量
(2). 由于NDIRECT定义改变,其中一个直接块变为了二级间接块,需要修改inode结构体中addrs元素数量
// fs.hstruct dinode {...uint addrs[NDIRECT + 2]; // Data block addresses};// file.hstruct inode {...uint addrs[NDIRECT + 2];};
(3). 修改bmap支持二级索引
static uintbmap(struct inode *ip, uint bn){uint addr, *a;struct buf *bp;if(bn < NDIRECT){...}bn -= NDIRECT;if(bn < NINDIRECT){...}bn -= NINDIRECT;// 二级间接块的情况if(bn < NDINDIRECT) {int level2_idx = bn / NADDR_PER_BLOCK; // 要查找的块号位于二级间接块中的位置int level1_idx = bn % NADDR_PER_BLOCK; // 要查找的块号位于一级间接块中的位置// 读出二级间接块if((addr = ip->addrs[NDIRECT + 1]) == 0)ip->addrs[NDIRECT + 1] = addr = balloc(ip->dev);bp = bread(ip->dev, addr);a = (uint*)bp->data;if((addr = a[level2_idx]) == 0) {a[level2_idx] = addr = balloc(ip->dev);// 更改了当前块的内容,标记以供后续写回磁盘log_write(bp);}brelse(bp);bp = bread(ip->dev, addr);a = (uint*)bp->data;if((addr = a[level1_idx]) == 0) {a[level1_idx] = addr = balloc(ip->dev);log_write(bp);}brelse(bp);return addr;}panic("bmap: out of range");}
(4). 修改itrunc释放所有块
voiditrunc(struct inode *ip){int i, j;struct buf *bp;uint *a;for(i = 0; i < NDIRECT; i++){...}if(ip->addrs[NDIRECT]){...}struct buf* bp1;uint* a1;if(ip->addrs[NDIRECT + 1]) {bp = bread(ip->dev, ip->addrs[NDIRECT + 1]);a = (uint*)bp->data;for(i = 0; i < NADDR_PER_BLOCK; i++) {// 每个一级间接块的操作都类似于上面的// if(ip->addrs[NDIRECT])中的内容if(a[i]) {bp1 = bread(ip->dev, a[i]);a1 = (uint*)bp1->data;for(j = 0; j < NADDR_PER_BLOCK; j++) {if(a1[j])bfree(ip->dev, a1[j]);}brelse(bp1);bfree(ip->dev, a[i]);}}brelse(bp);bfree(ip->dev, ip->addrs[NDIRECT + 1]);ip->addrs[NDIRECT + 1] = 0;}ip->size = 0;iupdate(ip);}
Symbolic links
(1). 配置系统调用的常规操作,如在user/usys.pl、user/user.h中添加一个条目,在kernel/syscall.c、kernel/syscall.h中添加相关内容
(2). 添加提示中的相关定义,T_SYMLINK以及O_NOFOLLOW
// fcntl.h#define O_NOFOLLOW 0x004// stat.h#define T_SYMLINK 4
(3). 在kernel/sysfile.c中实现sys_symlink,这里需要注意的是create返回已加锁的inode,此外iunlockput既对inode解锁,还将其引用计数减1,计数为0时回收此inode
uint64sys_symlink(void) {char target[MAXPATH], path[MAXPATH];struct inode* ip_path;if(argstr(0, target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0) {return -1;}begin_op();// 分配一个inode结点,create返回锁定的inodeip_path = create(path, T_SYMLINK, 0, 0);if(ip_path == 0) {end_op();return -1;}// 向inode数据块中写入target路径if(writei(ip_path, 0, (uint64)target, 0, MAXPATH) < MAXPATH) {iunlockput(ip_path);end_op();return -1;}iunlockput(ip_path);end_op();return 0;}
(4). 修改sys_open支持打开符号链接
uint64sys_open(void){...if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){...}// 处理符号链接if(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)) {// 若符号链接指向的仍然是符号链接,则递归的跟随它// 直到找到真正指向的文件// 但深度不能超过MAX_SYMLINK_DEPTHfor(int i = 0; i < MAX_SYMLINK_DEPTH; ++i) {// 读出符号链接指向的路径if(readi(ip, 0, (uint64)path, 0, MAXPATH) != MAXPATH) {iunlockput(ip);end_op();return -1;}iunlockput(ip);ip = namei(path);if(ip == 0) {end_op();return -1;}ilock(ip);if(ip->type != T_SYMLINK)break;}// 超过最大允许深度后仍然为符号链接,则返回错误if(ip->type == T_SYMLINK) {iunlockput(ip);end_op();return -1;}}if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){...}...return fd;}
