Lab9: file system

Large files

(1). 在fs.h中添加宏定义

  1. #define NDIRECT 11
  2. #define NINDIRECT (BSIZE / sizeof(uint))
  3. #define NDINDIRECT ((BSIZE / sizeof(uint)) * (BSIZE / sizeof(uint)))
  4. #define MAXFILE (NDIRECT + NINDIRECT + NDINDIRECT)
  5. #define NADDR_PER_BLOCK (BSIZE / sizeof(uint)) // 一个块中的地址数量

(2). 由于NDIRECT定义改变,其中一个直接块变为了二级间接块,需要修改inode结构体中addrs元素数量

  1. // fs.h
  2. struct dinode {
  3. ...
  4. uint addrs[NDIRECT + 2]; // Data block addresses
  5. };
  6. // file.h
  7. struct inode {
  8. ...
  9. uint addrs[NDIRECT + 2];
  10. };

(3). 修改bmap支持二级索引

  1. static uint
  2. bmap(struct inode *ip, uint bn)
  3. {
  4. uint addr, *a;
  5. struct buf *bp;
  6. if(bn < NDIRECT){
  7. ...
  8. }
  9. bn -= NDIRECT;
  10. if(bn < NINDIRECT){
  11. ...
  12. }
  13. bn -= NINDIRECT;
  14. // 二级间接块的情况
  15. if(bn < NDINDIRECT) {
  16. int level2_idx = bn / NADDR_PER_BLOCK; // 要查找的块号位于二级间接块中的位置
  17. int level1_idx = bn % NADDR_PER_BLOCK; // 要查找的块号位于一级间接块中的位置
  18. // 读出二级间接块
  19. if((addr = ip->addrs[NDIRECT + 1]) == 0)
  20. ip->addrs[NDIRECT + 1] = addr = balloc(ip->dev);
  21. bp = bread(ip->dev, addr);
  22. a = (uint*)bp->data;
  23. if((addr = a[level2_idx]) == 0) {
  24. a[level2_idx] = addr = balloc(ip->dev);
  25. // 更改了当前块的内容,标记以供后续写回磁盘
  26. log_write(bp);
  27. }
  28. brelse(bp);
  29. bp = bread(ip->dev, addr);
  30. a = (uint*)bp->data;
  31. if((addr = a[level1_idx]) == 0) {
  32. a[level1_idx] = addr = balloc(ip->dev);
  33. log_write(bp);
  34. }
  35. brelse(bp);
  36. return addr;
  37. }
  38. panic("bmap: out of range");
  39. }

(4). 修改itrunc释放所有块

  1. void
  2. itrunc(struct inode *ip)
  3. {
  4. int i, j;
  5. struct buf *bp;
  6. uint *a;
  7. for(i = 0; i < NDIRECT; i++){
  8. ...
  9. }
  10. if(ip->addrs[NDIRECT]){
  11. ...
  12. }
  13. struct buf* bp1;
  14. uint* a1;
  15. if(ip->addrs[NDIRECT + 1]) {
  16. bp = bread(ip->dev, ip->addrs[NDIRECT + 1]);
  17. a = (uint*)bp->data;
  18. for(i = 0; i < NADDR_PER_BLOCK; i++) {
  19. // 每个一级间接块的操作都类似于上面的
  20. // if(ip->addrs[NDIRECT])中的内容
  21. if(a[i]) {
  22. bp1 = bread(ip->dev, a[i]);
  23. a1 = (uint*)bp1->data;
  24. for(j = 0; j < NADDR_PER_BLOCK; j++) {
  25. if(a1[j])
  26. bfree(ip->dev, a1[j]);
  27. }
  28. brelse(bp1);
  29. bfree(ip->dev, a[i]);
  30. }
  31. }
  32. brelse(bp);
  33. bfree(ip->dev, ip->addrs[NDIRECT + 1]);
  34. ip->addrs[NDIRECT + 1] = 0;
  35. }
  36. ip->size = 0;
  37. iupdate(ip);
  38. }

Symbolic links

(1). 配置系统调用的常规操作,如在user/usys.pluser/user.h中添加一个条目,在kernel/syscall.ckernel/syscall.h中添加相关内容

(2). 添加提示中的相关定义,T_SYMLINK以及O_NOFOLLOW

  1. // fcntl.h
  2. #define O_NOFOLLOW 0x004
  3. // stat.h
  4. #define T_SYMLINK 4

(3). 在kernel/sysfile.c中实现sys_symlink,这里需要注意的是create返回已加锁的inode,此外iunlockput既对inode解锁,还将其引用计数减1,计数为0时回收此inode

  1. uint64
  2. sys_symlink(void) {
  3. char target[MAXPATH], path[MAXPATH];
  4. struct inode* ip_path;
  5. if(argstr(0, target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0) {
  6. return -1;
  7. }
  8. begin_op();
  9. // 分配一个inode结点,create返回锁定的inode
  10. ip_path = create(path, T_SYMLINK, 0, 0);
  11. if(ip_path == 0) {
  12. end_op();
  13. return -1;
  14. }
  15. // 向inode数据块中写入target路径
  16. if(writei(ip_path, 0, (uint64)target, 0, MAXPATH) < MAXPATH) {
  17. iunlockput(ip_path);
  18. end_op();
  19. return -1;
  20. }
  21. iunlockput(ip_path);
  22. end_op();
  23. return 0;
  24. }

(4). 修改sys_open支持打开符号链接

  1. uint64
  2. sys_open(void)
  3. {
  4. ...
  5. if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
  6. ...
  7. }
  8. // 处理符号链接
  9. if(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)) {
  10. // 若符号链接指向的仍然是符号链接,则递归的跟随它
  11. // 直到找到真正指向的文件
  12. // 但深度不能超过MAX_SYMLINK_DEPTH
  13. for(int i = 0; i < MAX_SYMLINK_DEPTH; ++i) {
  14. // 读出符号链接指向的路径
  15. if(readi(ip, 0, (uint64)path, 0, MAXPATH) != MAXPATH) {
  16. iunlockput(ip);
  17. end_op();
  18. return -1;
  19. }
  20. iunlockput(ip);
  21. ip = namei(path);
  22. if(ip == 0) {
  23. end_op();
  24. return -1;
  25. }
  26. ilock(ip);
  27. if(ip->type != T_SYMLINK)
  28. break;
  29. }
  30. // 超过最大允许深度后仍然为符号链接,则返回错误
  31. if(ip->type == T_SYMLINK) {
  32. iunlockput(ip);
  33. end_op();
  34. return -1;
  35. }
  36. }
  37. if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
  38. ...
  39. }
  40. ...
  41. return fd;
  42. }