首页 > 其他分享 >6.S081 lab9 file system

6.S081 lab9 file system

时间:2023-03-13 09:57:14浏览次数:39  
标签:addr ip system bp addrs inode path lab9 S081

#Large files

第一个实验还算比较简单的,不过 测试样例好像不是很严格,刚开始我做完后拿去跑测试样例,过了,但其实代码是有点小问题的,然后这些问题就导致了我第二个实验symlink的部分样例过不了,我花了大量时间debug第二个实验的代码,结果最后发现是第一个实验的代码有问题。

  • bmap函数有两个形参(ipbn),ip是一个inode指针,而bn是逻辑块号。bmap函数的作用是根据逻辑块号,返回在磁盘中物理块号的地址。inode中有一个成员addrs,这个成员记录了NDIRECT个直接块的地址(addrs[0]~addrs[NDIRECT-1])和1个一级索引块的地址(addrs[NDIRECT])

  • 先把思路捋清楚,实验是要求我们增加一个二级索引块,我们要做的就是改bmap函数和itrunc函数。减少一个直接数据块的数目为二级索引块腾出空间,修改宏定义如下图:

    1.png

    修改inodedinodeaddrs的定义,修改后的addrs[NIDRECT+1]为二级索引块

    1.png

  • 修改bmap函数,增加对于二级索引块的处理代码,注意:bn是逻辑块号,核心代码:

    // 需要分配二级索引块的情况
      bn -= NINDIRECT;
      if (bn < N2INDIRECT){
        // 进行两次查找块的操作(二级索引块->中间块->最终块)
        // level2是中间块的逻辑块号,level1是最终块的逻辑块号
        int level2 = bn / NINDIRECT, level1 = bn % NINDIRECT;
        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]) == 0){
          a[level2] = addr = balloc(ip->dev);
          /* printf("第一次分配 %p\n", addr); */
          log_write(bp);
        }
        brelse(bp);
        
        bp = bread(ip->dev, addr);
        a = (uint*)bp->data;
        if ((addr = a[level1]) == 0){
          a[level1] = addr = balloc(ip->dev);
          /* printf("第二次分配 %p\n", addr); */
          log_write(bp);
        }
        brelse(bp);
        return addr;
      }
    
  • 修改itrunc函数,增加对于二级索引块的回收代码。一定要注意:必须回收所有有效块,包括中间块!,核心代码:

      // 清除二级间接块
      if (ip->addrs[NDIRECT + 1]){
        bp = bread(ip->dev, ip->addrs[NDIRECT + 1]);
        a = (uint*)bp->data;
        for (i = 0; i < NINDIRECT; i++){
          // 中间块是否有效?
          if (a[i]){
            bp2 = bread(ip->dev, a[i]);
            a2 = (uint*)bp2->data;
            for (j = 0; j < NINDIRECT; j++){
              // 最终块是否有效?
              if (a2[j])
                bfree(ip->dev, a2[j]);
            }
            // 一定记得回收中间块
            brelse(bp2);
            bfree(ip->dev, a[i]);
          }
        }
        brelse(bp);
        bfree(ip->dev, ip->addrs[NDIRECT + 1]);
        ip->addrs[NDIRECT + 1] = 0;
      }
    

做这个实验之前,建议看一下与目录相关的代码,这里贴一个链接:https://juejin.cn/post/7002183734178873357

  • 软链接是一种特殊的文件,可以把软链接看成windows中的快捷方式,这个文件的内容是一个路径。

  • 加入系统调用号,添加函数原型等操作不再赘述。直接阐述sys_symlink函数的实现方法,这个函数有两个参数:第一个参数是target,表示链接的目标路径,简单来说就是快捷方式指向的文件,第二个参数是path,这个参数指定了链接的存储路径。举个例子,target="/a/b", path="/a/c"就代表在目录a下存在软链接c,此软链接指向了文件b。实现代码如下:

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

    介绍一下所用的xv6 API,第10行的create函数以文件类型T_SYMLINK在路径path处分配了一个inode,如果分配失败则返回0,否则返回一个inode指针。分配了一个新inode之后,应该把target写入这个inode中,writei的工作就是在于此,具体writei的使用方法可以参看详细代码,这里就不过多说明了。需要注意的一点是:create函数返回的是一个上锁的inode,所以最后需要iunlockput函数解锁inode

  • 之后需要修改sys_open函数来处理路径指向软链接的情况。核心代码如下:

      // 处理软链接文件
      int cnt = 0; // 迭代次数
      while(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW) && cnt < 10){
        if (readi(ip, 0, (uint64)path, 0, MAXPATH) != MAXPATH)
          panic("readi error");
        cnt++;
        iunlockput(ip);
        ip = namei(path);
        if (ip == 0){
          end_op();
          return -1;
        }
        ilock(ip);
      }
      // 若迭代次数已达到10次,就认为软链接形成了环状
      if (cnt == 10){
        iunlockput(ip);
        end_op();
        return -1;
      }
    

    O_NOFOLLOW标记为0并且文件类型为T_SYMLINK时,应该迭代进行查找。查找逻辑比较简单:第4行的readi函数与writei函数类似,只不过readi函数是从一个inode读数据到path中。读到软链接所指向的文件后,应该查找此文件所在的inode,第8行的namei函数的目的即在于此,给出路径名path,查找path所在的inode,若查找失败则返回0,此时说明软链接指向的文件不存在,应该返回错误。在迭代过程要特别注意:第7行和第13行,由于第8行需要更新ip,则旧的inode不会再用到了,需要释放。每次读写inode之前,一定要获取inode的锁

    代码的16~20行通过判断迭代次数,来判断软链接是否成环,如果软链接成环,也应返回错误。

标签:addr,ip,system,bp,addrs,inode,path,lab9,S081
From: https://www.cnblogs.com/Kyo-Kyo/p/17210335.html

相关文章