【MIT 6.S081】2020, 实验记录(9),Lab: file system

目录

    • Task 1:Large files
    • Task 2:Symbolic links
      • 2.1 增加一个系统调用 symlink
      • 2.2 新增文件类型
      • 2.3 新增 NOFOLLOW 标志位
      • 2.4 实现 sys_symlink 系统调用
      • 2.5 修改 sys_open 函数
      • 2.6 测试

Task 1:Large files

现在的 xv6 系统中,一个文件的 data block 的索引目录最多到一级间接索引:

现有的一级间接索引

而这个 task 为了增大可支持的最大文件大小,要求扩展出二级间接索引,如下图:

二级间接索引

代码实现上,主要是扩展 fs.c 文件中的 bmap()itrunc() 函数:

  • bmap():传入相对的 block number(比如这个文件的第一个 block 的相对 block number 就是 0),返回这个 block 的地址。如果没有的话需要分配创建。
  • itrunc():释放一个文件的所有 blocks

直接索引表上有 13 个元素位置,原本是 12 个直接索引 + 1 个一级间接索引,现在需要改成 11 个直接索引 + 1 个一级间接索引 + 1 个二级间接索引。

修改 fs.h 文件中的相关参数:

在这里插入图片描述
相应的修改 dinode 和 inode 中 addrs 的元素数量(因为宏 NDIRECT 数值变了,所以这两个地方需要相应地修改一下):

dinode
inode

bmap() 函数中增加对耳机间接索引的支持:

static uint
bmap(struct inode *ip, uint bn)
{
  uint addr, *a;
  struct buf *bp;

  // 检查 bn 是否可以走直接索引
  if(bn < NDIRECT){
    if((addr = ip->addrs[bn]) == 0)  // 如果发现 bn 的 block 还不存在,则 alloc 一个 block
      ip->addrs[bn] = addr = balloc(ip->dev);
    return addr;
  }
  bn -= NDIRECT;

  // 检查 bn 是否可以走一级间接索引
  if(bn < NINDIRECT){
    // Load indirect block, allocating if necessary.
    if((addr = ip->addrs[NDIRECT]) == 0)
      ip->addrs[NDIRECT] = addr = balloc(ip->dev);
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if((addr = a[bn]) == 0){
      a[bn] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    return addr;
  }
  bn -= NINDIRECT;

  // 检查 bn 是否可以走二级间接索引
  if (bn < N_DOUBLE_INDIRECT) {
    if ((addr = ip->addrs[NDIRECT + 1]) == 0) {
      ip->addrs[NDIRECT + 1] = addr = balloc(ip->dev);
    }
    // 先从一级间接索引中找
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    uint level1 = bn / NINDIRECT;  // 在一级索引目录中的 index
    if ((addr = a[level1]) == 0) {
      a[level1] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    // 再从二级间接索引中找
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    uint level2 = bn % NINDIRECT;  // 在二级索引目录中的 index
    if ((addr = a[level2]) == 0) {
      a[level2] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    return addr;
  }

  panic("bmap: out of range");
}

itrunc() 函数中增加对二级间接索引的支持:

void
itrunc(struct inode *ip)
{
  int i, j;
  struct buf *bp;
  uint *a;

  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;
  }

  // 释放二级间接索引目录下的 blocks
  if (ip->addrs[NDIRECT + 1]) {
    // 从直接索引中记录的指针,访问一级间接索引
    struct buf *bp1 = bread(ip->dev, ip->addrs[NDIRECT + 1]);  // 一级间接索引的 block
    uint *a1 = (uint*)bp1->data;
    for(j = 0; j < NINDIRECT; j++) {  // 遍历一级间接索引的所有索引项
      if (a1[j]) {
        // 从一级间接索引中记录的指针,访问二级间接索引
        struct buf *bp2 = bread(ip->dev, a1[j]); // 二级间接索引的 block
        uint *a2 = (uint*)bp2->data;
        for(int k = 0; k < NINDIRECT; k++) {  // 遍历二级间接索引的所有索引项
          if (a2[k])
            bfree(ip->dev, a2[k]);  // 释放这个 data block
        }
        brelse(bp2);
        bfree(ip->dev, a1[j]);   // 释放二级间接索引的 block
      }
      //释放完了二阶指针块,
    }
    brelse(bp1); 
    bfree(ip->dev, ip->addrs[NDIRECT + 1]);  // 释放一级间接索引的 block
    ip->addrs[NDIRECT + 1] = 0;
  }

  ip->size = 0;
  iupdate(ip);
}

测试:

在这里插入图片描述

usertests 的结果:

usertests

Task 2:Symbolic links

这个 task 目标是新增一个系统调用,支持创建符号连接,就是一种新的文件类型,它链接到了另一个实际的文件。实现的思路就是,增加一种新的文件类型 “symlink”,创建 symlink 时,在文件内容中写入实际链接的文件名,这样就可以实现链接过去了。

2.1 增加一个系统调用 symlink

在 syscall.h 中增加一个新的系统调用号:

syscall.h
在 user/usys.pl 中增加一个 entry:

entry
在 user/user.h 中增加声明:

在这里插入图片描述
在 kernel/syscall.c 中的系统调用表中增加这个系统调用:

syscall.c

2.2 新增文件类型

我们需要新增一种 SYMLINK 的文件类型:

SYMLINK

2.3 新增 NOFOLLOW 标志位

按照 lab 官网给出的提示:

Add a new flag to kernel/fcntl.h, (O_NOFOLLOW), that can be used with the open system call. Note that flags passed to open are combined using a bitwise OR operator, so your new flag should not overlap with any existing flags. This will let you compile user/symlinktest.c once you add it to the Makefile.

我们在 kernel/fcntl.h 中增加这个 flag:

NOFOLLOW

2.4 实现 sys_symlink 系统调用

在 kernel/sysfile.c 中,我们实现 sys_symlink() 函数,用来在 path 上创建一个链接到 target 的 SYMLINK 文件:

uint64 sys_symlink(void)
{
  char target[MAXPATH], path[MAXPATH];  // 在 path 上创建一个 symlink 指向 target
  struct inode *dp, *ip;

  // 校验并绑定参数
  if (argstr(0, target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0) {
    return -1;
  }

  begin_op();  // 开始一个文件系统操作

  // 校验 target 是否合法
  if ((ip = namei(target)) != 0 && ip->type == T_DIR) {
    end_op();
    goto bad;
  }

  // 创建 symlink 文件
  dp = create(path, T_SYMLINK, 0, 0);  // 这一步会同时为 inode 加锁
  if (dp == 0) {
    goto bad;
  }

  // 在 symlink 文件中写入 target 信息
  int targetLen = strlen(target);
  if (writei(dp, 0, (uint64)target, 0, targetLen) != targetLen) {
    panic("symlink: writei");  // 模仿 sys_unlink() 函数中的写法
  }

  iunlockput(dp);  // 释放 inode 的 lock
  end_op();
  return 0;

bad:
  end_op();
  return -1;
}

2.5 修改 sys_open 函数

我们需要修改 sys_open() 函数,官网给出的提示是:

  • Modify the open system call to handle the case where the path refers to a symbolic link. If the file does not exist, open must fail. When a process specifies O_NOFOLLOW in the flags to open, open should open the symlink (and not follow the symbolic link).
  • If the linked file is also a symbolic link, you must recursively follow it until a non-link file is reached. If the links form a cycle, you must return an error code. You may approximate this by returning an error code if the depth of links reaches some threshold (e.g., 10).

sys_open
该函数的完整代码如下:

uint64
sys_open(void)
{
  char path[MAXPATH];
  int fd, omode;
  struct file *f;
  struct inode *ip;
  int n;

  if((n = argstr(0, path, MAXPATH)) < 0 || argint(1, &omode) < 0)
    return -1;

  begin_op();

  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);
    if(ip->type == T_DIR && omode != O_RDONLY){
      iunlockput(ip);
      end_op();
      return -1;
    }
  }

  // 当没有 NOFOLLOW 标志时,对于 SYMLINK 文件,默认的行为是打开的链接过去的 target 文件
  if ((omode & O_NOFOLLOW) == 0) {
    struct inode *dp;
    char target[MAXPATH];
    int i;
    for (i = 0; i < 10 && ip->type == T_SYMLINK; i++) {
      // 从 inode 读取数据
      if (readi(ip, 0, (uint64)target, 0, MAXPATH) == 0) {
        iunlockput(ip);
        end_op();
        return -1;
      }
      // 读取 target 的 inode
      dp = namei(target);
      if (dp == 0) {
        iunlockput(ip);
        end_op();
        return -1;
      }
      iunlockput(ip);
      ip = dp;
      ilock(ip);
    }
    // 如果 10 轮循环后也没找到 target 原文件
    if (i == 10) {
      iunlockput(ip);
      end_op();
      return -1;
    }
  }

  if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
    iunlockput(ip);
    end_op();
    return -1;
  }

  if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
    if(f)
      fileclose(f);
    iunlockput(ip);
    end_op();
    return -1;
  }

  if(ip->type == T_DEVICE){
    f->type = FD_DEVICE;
    f->major = ip->major;
  } else {
    f->type = FD_INODE;
    f->off = 0;
  }
  f->ip = ip;
  f->readable = !(omode & O_WRONLY);
  f->writable = (omode & O_WRONLY) || (omode & O_RDWR);

  if((omode & O_TRUNC) && ip->type == T_FILE){
    itrunc(ip);
  }

  iunlock(ip);
  end_op();

  return fd;
}

2.6 测试

完成以上代码实现后,测试就可以跑通过了:

symlinktest

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/466351.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基础:TCP三次握手做了什么,为什么要握手?

1. TCP 三次握手在做些什么 1. 第一次握手 &#xff1a; 1&#xff09;握手作用&#xff1a;客户端发出建立连接请求。 2&#xff09;数据处理&#xff1a;客户端发送连接请求报文段&#xff0c;将SYN位置为1&#xff0c;Sequence Number为x;然后&#xff0c;客户端进入SYN_S…

Swagger Array 使用指南:详解与实践

Swagger 允许开发者定义 API 的路径、请求参数、响应和其他相关信息&#xff0c;以便生成可读性较高的文档和自动生成客户端代码。而 Array &#xff08;数组&#xff09;是一种常见的数据结构&#xff0c;用于存储和组织多个相同类型的数据元素。数组可以有不同的维度和大小&a…

几个精品声音模型

AI技术提取某位歌手的音色&#xff0c;再用其替换另一位歌手音色的方式&#xff0c;可以实现接近歌手本人翻唱的逼真效果。无需学习其他伪音技巧&#xff0c;即可实现实时男女声音互换等等。 使用 RVC 及模型工具&#xff0c;可以实现以下几个功能&#xff1a; 音乐干声分离&…

【兔子机器人】实现从初始状态到站立

一、遥想星空up主的方法 由于我有卡位结构&#xff0c;无法做到劈腿&#xff0c;而且底盘也不一样&#xff0c;无法使用此方法 但是其代码思想是可以借鉴的。 参考视频&#xff1a; 【【开源啦&#xff01;】无刷轮腿平衡机器人】 【精准空降到 01:16】 https://www.bilibili…

uniapp 对video视频组件嵌套倍速按钮

这次接了需求是要求有倍速功能&#xff0c;去看了文档发现并没有倍速按钮的属性&#xff0c;想着手写一个吧 可最后发现原生层级太高&#xff0c;无论怎么样都迭不上去&#xff0c;就只能去找插件看看咯 找了好多插件发现都不可用&#xff0c;因为我这是app端&#xff0c;有些视…

旅游管理系统|基于SpringBoot+ Mysql+Java+Tomcat技术的旅游管理系统设计与实现(可运行源码+数据库+设计文档+部署说明+视频演示)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 用户功能 管理员功能登录前台功能效果图 系统功能设计 数据库E-R图设计 lunwen参考 …

深度学习——数据预处理

一、数据预处理 为了能用深度学习来解决现实世界的问题&#xff0c;我们经常从预处理原始数据开始&#xff0c; 而不是从那些准备好的张量格式数据开始。 在Python中常用的数据分析工具中&#xff0c;我们通常使用pandas软件包。 像庞大的Python生态系统中的许多其他扩展包一样…

【JVM篇】类的生命周期

文章目录 &#x1f354;类的生命周期概述⭐加载⭐连接⭐初始化⭐类的卸载 &#x1f354;类的生命周期概述 Java类的生命周期包括加载&#xff08;Loading&#xff09;、验证&#xff08;Verification&#xff09;、准备&#xff08;Preparation&#xff09;、解析&#xff08;R…

TrueNAS怎么设置中文,最新2024版本安装详细说明

首先我们做好安装前的准备工作 1&#xff0c;ISO镜像安装包 2&#xff0c;虚拟机&#xff08;建议使用ESXI虚拟机环境&#xff09; 如果是物理机安装&#xff0c;建议先给底层安装虚拟机系统esxi&#xff0c;再在上面安装方便以后的管理&#xff0c;如果你想物理机直接安装&a…

【Redis】缓存穿透

问题发生背景&#xff1a;客户端请求的数据再缓存中和数据库中都不存在。 导致的问题&#xff1a;缓存永远不会生效&#xff0c;这些请求都会去请求数据库—导致数据库压力增大。 解决方案&#xff1a; 1.缓存空对象 在Redis中缓存空对象&#xff0c;告诉客户端数据库中没有该值…

zookeeper快速入门五:用zookeeper实现服务注册与发现中心

系列&#xff1a; zookeeper快速入门一&#xff1a;zookeeper安装与启动-CSDN博客 zookeeper快速入门二&#xff1a;zookeeper基本概念-CSDN博客 zookeeper快速入门三&#xff1a;zookeeper的基本操作 zookeeper快速入门四&#xff1a;在java客户端中操作zookeeper-CSDN博客…

【Python】线程—GIL—asyncio

文章目录 一、Python 线程二、threading 模块三、例程3.1 基本用法3.2 同步3.21 Lock&#xff08;锁&#xff09;3.22 RLock&#xff08;递归锁&#xff09;3.23 Condition&#xff08;条件变量&#xff09;3.24 Semaphore&#xff08;信号量&#xff09; 四、GIL4.1 简述4.2 详…

MySQL教程-SQL

SQL(Structured Query Language)结构化查询语言&#xff0c;操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库统一标准。 语法 SQL语句可以单行或多行书写&#xff0c;以;为结束标记SQL可以使用空格或缩进来增强语句的可读性SQL分单行注释(-- 注释内容 或 …

跨境电商应该用什么样的服务器?多大带宽?

跨境电商在选择服务器 和带宽时&#xff0c;需要考虑多个因素&#xff0c;包括业务规模、用户数量、网站流量、地理位置等。下面是一些关键考虑因素&#xff1a; 1、服务器类型 跨境电商通常会选择使用云服务器&#xff0c;因为云服务器具有灵活性、可扩展性和高可用性。云服务…

做户用光伏代理赚钱吗

随着全球能源危机的加剧和环境问题的日益严重&#xff0c;清洁能源的开发和利用成为了一个重要的议题。光伏发电作为一种绿色、可再生的能源&#xff0c;在全球范围内得到了广泛的关注和应用。 一、代理农村光伏项目挣钱吗 随着国家对光伏发电的政策支持和补贴&#xff0c;以及…

关 于 重 燃 学 习 的 热 情

3月1日是我回学校的第一天。经历了长达8个月在家的昏暗时刻&#xff0c;我这10天的感觉和在家的感觉发生了翻天覆地的变化&#xff0c;最明显的莫过于学习状态的改变。 倒不是说在家学的不好&#xff0c;而是说在学校&#xff0c;我对学习的整体感觉&#xff0c;以及专注程度&…

鸿蒙开发学习:【驱动子系统】

OpenHarmony驱动子系统采用C面向对象编程模型构建&#xff0c;通过平台解耦、内核解耦&#xff0c;兼容不同内核&#xff0c;提供了归一化的驱动平台底座&#xff0c;旨在为开发者提供更精准、更高效的开发环境&#xff0c;力求做到一次开发&#xff0c;多系统部署。 为了缩减…

避雷!又新增一本SCI被标记On Hold,共16本!

毕业推荐 IEEE&#xff08;CCF-C类&#xff09; • 计算机医学类&#xff0c;7.5-8.0&#xff0c;JCR1区&#xff0c;中科院2/1区&#xff08;TOP&#xff09; • 3-4个月左右录用 SCIE&#xff1a; • 计算机类&#xff0c;6.5-7.0&#xff0c;JCR1区&#xff0c;中科院2…

关于udp能跨局域网传输的问题

UDP&#xff08;用户数据报协议&#xff09;以其独特的传输特性在多种应用场景中都有着极其重要的作用。然而&#xff0c;关于UDP是否能跨局域网&#xff08;LAN&#xff09;进行传输&#xff0c;以及这一传输过程中的优缺点&#xff0c;一直是网络技术领域讨论的热点。本文将详…

气液分离器的概念和原理

气液分离器也叫低压储液器&#xff0c;在热泵或制冷系统中使用&#xff0c;主要是将出蒸发器、进压缩机气流中的液滴分离出来&#xff0c;防止压缩机发生液击&#xff0c;用于工质充注量较大、压缩机进气可能带液且压缩机对湿压缩较敏感的情况 。 液击主要出现在活塞式压缩机中…