当前位置: 首页 > news >正文

MIT6.S081-lab8

MIT6.S081-lab8

1. Large files

从 lecture 我们可以知道,我们目前的单个文件的最大大小很小,这是因为我们能够索引的索引块范围很小,实际上,目前的索引只有直接索引和一级索引,而这个实验就是需要我们去实现二级索引,我们通过阅读 bmap 和 itrunc 可以发现,我们的一级索引实际上是通过分配一个数据块来进行索引了,所以我们二级索引也需要利用这个思路。

hint 没啥太重要的,这个 lab 很简单,但是依旧需要我们去根据 hint 做一些微操:

struct inode {uint dev;           // Device numberuint inum;          // Inode numberint ref;            // Reference countstruct sleeplock lock; // protects everything below hereint valid;          // inode has been read from disk?short type;         // copy of disk inodeshort major;short minor;short nlink;uint size;// 此处修改为 + 2 ,增加索引位。uint addrs[NDIRECT+2];
};

fs.h

// 这里根据 hint 需要修改为 11
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
// 修改最大文件的大小
#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT * NINDIRECT)// On-disk inode structure
struct dinode {short type;           // File typeshort major;          // Major device number (T_DEVICE only)short minor;          // Minor device number (T_DEVICE only)short nlink;          // Number of links to inode in file systemuint size;            // Size of file (bytes)// 修改,理由同 file.huint addrs[NDIRECT+2];   // Data block addresses
};

然后,根据我们之前的前置知识,我们可以知道,我们文件的数据的地址都是通过 bmap 来索引的,而我们还可以通过 hint 来知道,我们需要对 itrunc 进行操作,所以剩下的就是直接对我们的 bmap 和 itrunc 进行操作了,我们的二级索引会先分配一个数据块,然后这个数据块的每一位又会分配一个数据块,最后一级的数据块才是真正存放地址的数据,这就叫二级索引,所以按着这个思路,这里纯爽局,直接跟着抄就行了,:

static uint
bmap(struct inode *ip, uint bn)
{uint addr, *a;struct buf *bp;if(bn < NDIRECT){if((addr = ip->addrs[bn]) == 0){addr = balloc(ip->dev);if(addr == 0)return 0;ip->addrs[bn] = addr;}return addr;}bn -= NDIRECT;if(bn < NINDIRECT){// Load indirect block, allocating if necessary.if((addr = ip->addrs[NDIRECT]) == 0){addr = balloc(ip->dev);if(addr == 0)return 0;ip->addrs[NDIRECT] = addr;}bp = bread(ip->dev, addr);a = (uint*)bp->data;if((addr = a[bn]) == 0){addr = balloc(ip->dev);if(addr){a[bn] = addr;log_write(bp);}}brelse(bp);return addr;}bn -= NINDIRECT;if(bn < NINDIRECT * NINDIRECT) {// 分配数据块作为索引if((addr = ip->addrs[NDIRECT + 1]) == 0) {addr = balloc(ip->dev);if(addr == 0) {return 0;}ip->addrs[NDIRECT + 1] = addr; }// 第一层索引bp = bread(ip->dev, addr);a = (uint*)bp->data;if((addr = a[bn / NINDIRECT]) == 0) {addr = balloc(ip->dev);if(addr) {a[bn / NINDIRECT] = addr;log_write(bp);}} brelse(bp);// 第二层索引bn %= NINDIRECT;bp = bread(ip->dev, addr);a = (uint*)bp->data;if((addr = a[bn]) == 0) {addr = balloc(ip->dev);if(addr) {a[bn] = addr;log_write(bp);}}brelse(bp);return addr;}panic("bmap: out of range");
}// Truncate inode (discard contents).
// Caller must hold ip->lock.
void
itrunc(struct inode *ip)
{// 这里加上 k,bp2 和 bint i, j, k;struct buf *bp, *bp2;uint *a, *b;for(i = 0; i < NDIRECT; i++){if(ip->addrs[i]){bfree(ip->dev, ip->addrs[i]);ip->addrs[i] = 0;}}if(ip->addrs[NDIRECT]){bp = bread(ip->dev, ip->addrs[NDIRECT]);a = (uint*)bp->data;for(j = 0; j < NINDIRECT; j++){if(a[j])bfree(ip->dev, a[j]);}brelse(bp);bfree(ip->dev, ip->addrs[NDIRECT]);ip->addrs[NDIRECT] = 0;}// 修改的地方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]);b = (uint*)bp2->data;for(k = 0; k < NINDIRECT; k ++) {if(b[k]) {bfree(ip->dev, b[k]);}}brelse(bp2);bfree(ip->dev, a[j]);}}brelse(bp);bfree(ip->dev, ip->addrs[NDIRECT + 1]);ip->addrs[NDIRECT + 1] = 0;}ip->size = 0;iupdate(ip);
}

完成。


2. Symbolic links

这个实验也不是很难,我们的目的是实现一个 symlink 的系统调用,传入 target 和 path 的参数,其中,当我们使用了这个 symlink 系统调用之后,我们再次 open 其中的 path 的时候,会直接打开 target 对应的文件,这就是我们的链接。

由 hint 可知,我们先需要做一些准备工作:

kernel/stat.h

#define T_DIR     1   // Directory
#define T_FILE    2   // File
#define T_DEVICE  3   // Device
// 添加的,这里随便写啥,只需要不重复
#define T_SYMLINK 4   // LAB 8

kernel/fcntl.h

#define O_RDONLY  0x000
#define O_WRONLY  0x001
#define O_RDWR    0x002
#define O_CREATE  0x200
#define O_TRUNC   0x400
// 这里只要换成二进制不和上面重复就可以了
#define O_NOFOLLOW 0x004

如果你希望在 xv6 启动的时候调试:

makefile

UPROGS=\$U/_cat\$U/_echo\$U/_forktest\$U/_grep\$U/_init\$U/_kill\$U/_ln\$U/_ls\$U/_mkdir\$U/_rm\$U/_sh\$U/_stressfs\$U/_usertests\$U/_grind\$U/_wc\$U/_zombie\#添加这里$U/_symlinktest\

usys.pl

entry("symlink");

user.h

int symlink(char *target, char *path);

syscall.h

#define SYS_symlink 22

syscall.c

extern uint64 sys_symlink(void);static uint64 (*syscalls[])(void) = {
[SYS_fork]    sys_fork,
[SYS_exit]    sys_exit,
[SYS_wait]    sys_wait,
[SYS_pipe]    sys_pipe,
[SYS_read]    sys_read,
[SYS_kill]    sys_kill,
[SYS_exec]    sys_exec,
[SYS_fstat]   sys_fstat,
[SYS_chdir]   sys_chdir,
[SYS_dup]     sys_dup,
[SYS_getpid]  sys_getpid,
[SYS_sbrk]    sys_sbrk,
[SYS_sleep]   sys_sleep,
[SYS_uptime]  sys_uptime,
[SYS_open]    sys_open,
[SYS_write]   sys_write,
[SYS_mknod]   sys_mknod,
[SYS_unlink]  sys_unlink,
[SYS_link]    sys_link,
[SYS_mkdir]   sys_mkdir,
[SYS_close]   sys_close,
// 添加这一行
[SYS_symlink] sys_symlink,
};

最后,我们可以在 sysfile.c 中编写我们的代码,首先,关于这个系统调用,由于它原本并不会存在,所以我们需要先创建这个文件,并且存储我们的 target ,如何存储?通过 hint 可以知道,我们可以将这个 target 存储到文件的数据块中:

uint64 sys_symlink(void) {char target[MAXPATH], path[MAXPATH];struct inode *ip;argstr(0, target, MAXPATH);argstr(1, path, MAXPATH);begin_op();ip = create(path, T_SYMLINK, 0, 0);if(ip == 0) {end_op();return -1;}if (writei(ip, 0, (uint64)target, 0, strlen(target)) < 0) {end_op();return -1;}iunlockput(ip);end_op();return 0;
}

这里需要注意的就是事务的开启和关闭,通过之前的前置学习我们可以知道,通过 writei 可以将数据写入数据块中,这样我们就算是成功链接了。

最后,我们在 open 系统调用的时候,需要能够识别这个文件是一个链接文件,同时,需要保证能够递归查找一定的深度,这里我们可以直接仿照原本的 open 使用 namei 去获取对应的 fd ,然后通过 readi 获取链接的 target。

uint64
sys_open(void)
{...if(omode & O_CREATE){ip = create(path, T_FILE, 0, 0);if(ip == 0){end_op();return -1;}} else {if((ip = namei(path)) == 0){end_op();return -1;}ilock(ip);// 修改的部分int depth = 0;// 如果对应的 inode 是链接类型并且没有 NOFOLLOW 标志位while(ip->type == T_SYMLINK && (omode & O_NOFOLLOW) == 0) {// 如果递归过多层,及时退出if(++depth > 10) {iunlockput(ip);end_op();return -1;}// 注意,这里不清空数据,我们的测试样例过不了!memset(path, 0, MAXPATH);if(readi(ip, 0, (uint64)path, 0, MAXPATH) < 0) {iunlockput(ip);end_op();return -1;}iunlockput(ip);// 读取这个文件对应的 inodeif((ip = namei(path)) == 0){end_op();return -1;}ilock(ip);}//此处跳出了循环,代表找到了最终的文件// 以上为修改的部分if(ip->type == T_DIR && omode != O_RDONLY){iunlockput(ip);end_op();return -1;}}...return fd;
}

最后,我们可以通过所有的测试:

== Test running bigfile == 
$ make qemu-gdb
running bigfile: OK (139.0s) 
== Test running symlinktest == 
$ make qemu-gdb
(1.2s) 
== Test   symlinktest: symlinks == symlinktest: symlinks: OK 
== Test   symlinktest: concurrent symlinks == symlinktest: concurrent symlinks: OK 
== Test usertests == 
$ make qemu-gdb
usertests: OK (188.3s) 

相关文章:

  • 创建第一个简单cesium程序
  • Vscode+git笔记
  • 什么是 Redis?
  • PCIe | TLP | 报头 / 包格式 / 地址转换 / 配置空间 / 寄存器 / 配置类型
  • 叠层阻抗线框
  • MNN 支持 DeepSeekVL
  • Docker安装Ollama及使用Ollama部署大模型
  • 解析机器人 2.0.2 | 支持超过50种短视频平台的链接解析,无水印提取,多功能下载工具
  • deepSeek论文写作提示词指令大全(覆盖选题、写作、润色到投稿全流程)
  • 测试基础笔记第十八天
  • linux下,ollama会把模型文件保存在哪里?
  • Python Cookbook-6.17 NuIl对象设计模式的实现
  • 归并排序【逆序对】
  • Day04 新增套餐
  • 【堆】最大堆、最小堆以及GO语言的实现
  • 【Java Lambda表达式详解】
  • bellard.org‌ : QuickJS 如何使用 qjs 执行 js 脚本
  • 一种实波束前视扫描雷达目标二维定位方法——论文阅读
  • 搭建一个 gRPC 服务端和客户端
  • 青少年ctf练习平台--做题wp(2)
  • 2类药物别乱吃,严重可致肝肾衰竭!多人已中招
  • 《开始推理吧3》:演员没包袱,推理更共情
  • 新华每日电讯“关爱青年成长”三连评:青春应有多样的精彩
  • 国铁集团:全国铁路旅客发送量连续3天同比增幅超10%
  • 魔都眼|咖啡节上上海小囡忍不住尝了咖啡香,母亲乐了
  • 今年4月上海一二手房成交面积同比增21%,二手房成交2.07万套