OS LAB4 实验报告 发表于 2022-11-01 | 更新于 2023-04-08
| 字数总计: 1.2k | 阅读时长: 6分钟 |
Lab4文件系统 0. 实验前:切换至Lab2分支 在xv6-labs-2021文件夹下运行终端,并且运行以下命令:
1 2 3 $ git fetch $ git checkout fs $ make clean
1. 对 xv6 文件系统添加“大文件”的支持 1.1 Large files 1 Modify bmap() so that it implements a doubly-indirect block, in addition to direct blocks and a singly-indirect block. You'll have to have only 11 direct blocks, rather than 12, to make room for your new doubly-indirect block; you're not allowed to change the size of an on-disk inode. The first 11 elements of ip->addrs[] should be direct blocks; the 12th should be a singly-indirect block (just like the current one); the 13th should be your new doubly-indirect block. You are done with this exercise when bigfile writes 65803 blocks and usertests runs successfully:
1.1.1 解题过程
修改 kernel/fs.h
中的直接块号的宏定义 NDIRECT
为 11;
修改 inode 相关结构体的块号数组,包括 kernel/fs.h
中的磁盘inode 结构体 struct dinode
的 addrs
;
kernel/file.h
中的内存inode 结构体 struct inode
的 addrs
将数组大小也改变为 NDIRECT+2
, 因为 inode 的块号总数没有改变, 但 NDIRECT
减少了 1;
kernel/fs.h
添加宏定义二级间接块号总数NDOUBLYINDIRECT
,可表示的块号为一级间接块号NINDIRECT
的平方;
kernel/fs.c
中bmap()
用于返回inode的相对块号对应的磁盘中的块号,由于 inode 结构中前 NDIRECT
个块号与修改前是一致的, 因此只需要添加对第 NDIRECT
即 13 个块的二级间接索引的处理代码;
修改kernel/fs.c
下的itrunc()
,函数用于释放inode的数据块;
修改kernel/fs.h
中的MAXFILE
。
1.1.2 代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 #define NDIRECT 11 #define NDOUBLYINDIRECT (NINDIRECT * NINDIRECT) #define MAXFILE (NDIRECT + NINDIRECT + NDOUBLYINDIRECT) struct dinode { uint addrs[NDIRECT+2 ]; }struct inode { uint addrs[NDIRECT+2 ] }static uintbmap (struct inode *ip, uint bn) { return addr; } bn -= NINDIRECT; if (bn < NDOUBLYINDIRECT) { 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[bn / NINDIRECT]) == 0 ) { a[bn / NINDIRECT] = addr = balloc(ip->dev); log_write(bp); } brelse(bp); bp = bread(ip->dev, addr); a = (uint*)bp->data; bn %= NINDIRECT; if ((addr = a[bn]) == 0 ) { a[bn] = addr = balloc(ip->dev); log_write(bp); } brelse(bp); return addr; } panic("bmap: out of range" ) }void itrunc (struct inode *ip) { int i, j, k; struct buf *bp , *bp2 ; uint *a, *a2; if (ip->addrs[NDIRECT + 1 ]) { bp = bread(ip->dev, ip->addrs[NDIRECT + 1 ]); a = (uint*)bp->data; for (j = 0 ; j < NINDIRECT; ++j) { if (a[j]) { bp2 = bread(ip->dev, a[j]); a2 = (uint*)bp2->data; for (k = 0 ; k < NINDIRECT; ++k) { if (a2[k]) { bfree(ip->dev, a2[k]); } } brelse(bp2); bfree(ip->dev, a[j]); a[j] = 0 ; } } brelse(bp); bfree(ip->dev, ip->addrs[NDIRECT + 1 ]); ip->addrs[NDIRECT + 1 ] = 0 ; } ip->size = 0 ; iupdate(ip); }
1.1.3 运行结果
1.2 Symbolic links 1 You will implement the symlink(char *target, char *path) system call, which creates a new symbolic link at path that refers to file named by target. For further information, see the man page symlink. To test, add symlinktest to the Makefile and run it. Your solution is complete when the tests produce the following output (including usertests succeeding).
1.2.1 解题过程
分别于kernel/syscall.h
, kernel/syscall.c
, user/usys.pl
和 user/user.h
添加有关symlink
系统调用的定义声明。
添加T_SYMLINK
到kernel/stat.h
中
添加O_NOFOLLOW
到kernel/fcntl.h
中
在kernel/sysfile.c
中实现功能为生成符号链接的sys_symlink()
在kernel/fs.h
定义NSYMLINK
用于表示最大的符号连接深度
在kernel/sysfile.c
中新增函数follow_symlink()
修改kernel/sysfile.c
的 sys_open()
1.2.2 代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 $U/_symlinktest\#define SYS_symlink 22 extern uint64 sys_symlink (void ) ; [SYS_symlink] sys_symlink, uint64 sys_symlink (void ) { char target[MAXPATH], path[MAXPATH]; struct inode *ip ; int n; if ((n = argstr(0 , target, MAXPATH)) < 0 || argstr(1 , path, MAXPATH) < 0 ) { return -1 ; } begin_op(); if ((ip = create(path, T_SYMLINK, 0 , 0 )) == 0 ) { end_op(); return -1 ; } if (writei(ip, 0 , (uint64)target, 0 , n) != n) { iunlockput(ip); end_op(); return -1 ; } iunlockput(ip); end_op(); return 0 ; }static struct inode* follow_symlink (struct inode* ip) { uint inums[NSYMLINK]; int i, j; char target[MAXPATH]; for (i = 0 ; i < NSYMLINK; ++i) { inums[i] = ip->inum; if (readi(ip, 0 , (uint64)target, 0 , MAXPATH) <= 0 ) { iunlockput(ip); printf ("open_symlink: open symlink failed\n" ); return 0 ; } iunlockput(ip); if ((ip = namei(target)) == 0 ) { printf ("open_symlink: path \"%s\" is not exist\n" , target); return 0 ; } for (j = 0 ; j <= i; ++j) { if (ip->inum == inums[j]) { printf ("open_symlink: links form a cycle\n" ); return 0 ; } } ilock(ip); if (ip->type != T_SYMLINK) { return ip; } } iunlockput(ip); printf ("open_symlink: the depth of links reaches the limit\n" ); return 0 ; } uint64sys_open (void ) { if (ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){ iunlockput(ip); end_op(); return -1 ; } if (ip->type == T_SYMLINK && (omode & O_NOFOLLOW) == 0 ) { if ((ip = follow_symlink(ip)) == 0 ) { end_op(); return -1 ; } } if ((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0 ){ if (f) fileclose(f); iunlockput(ip); end_op(); return -1 ; } } entry("symlink" );int symlink (char *target, char *path) ;#define T_SYMLINK 4 #define O_NOFOLLOW 0x004 #define NSYMLINK 10
1.2.3 运行结果
2.实验心得 非常好奇Large files的$bigfile
和 $usertests
的 writebig
到底是多”big”呢,等了快20分钟他的bigbig file,真的很big。
第二个sys_open函数的修改有点复杂,是否递归或者还是直接打开symlink。文件链接是一个iNode储存的的其实是另一个inode的路径,通过前一个inode找下一个inode,然后再查看另一个inode的值,如果仍是一个inode的路径的话,就继续递归找下去。