惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
D
Docker
S
SegmentFault 最新的问题
博客园 - 聂微东
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
GbyAI
GbyAI
L
LangChain Blog
Vercel News
Vercel News
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
T
Threat Research - Cisco Blogs
T
Threatpost
Scott Helme
Scott Helme
T
Tailwind CSS Blog
Latest news
Latest news
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
The Register - Security
The Register - Security
罗磊的独立博客
P
Proofpoint News Feed
腾讯CDC
S
Schneier on Security
雷峰网
雷峰网
A
About on SuperTechFans
T
Tenable Blog
F
Full Disclosure
Cyberwarzone
Cyberwarzone
博客园_首页
有赞技术团队
有赞技术团队
K
Kaspersky official blog

文章列表

游戏玩后感:ReLief:献给亲爱的你 我的周边(谷子)分享 游戏玩后感:Kanon 简谱:致真实的你 《Rust中常见的有关生命周期的误解》学习笔记 简谱:StarMap 简谱:かく咲きたらばいと恋ひめやも 简谱:东风 简谱:无法诉说的思念 简谱:Girlish 游戏玩后感:时钟机关的Layline 简谱:风之琶音 简谱:星空的记忆 简谱:因为遇见了你 简谱:月童 番茄简谱脚本转调器 游戏玩后感:青空下的约定:Refine 游戏玩后感:在这苍穹展翅 书籍读后感:控制论与科学方法论 游戏玩后感:恋爱表达式 游戏玩后感:樱之诗 MLIR-tutorial学习笔记 游戏玩后感:潜伏之赤途 游戏玩后感:纯爱咖啡厅:帕露菲重制版 游戏玩后感:智以泪聚 游戏玩后感:初雪樱 游戏玩后感:告别回忆:从今以后 游戏玩后感:梦灯花 游戏玩后感:金辉恋曲四重奏 游戏玩后感:五彩斑斓的世界 昇腾310P使用记录 游戏玩后感:AIR 游戏玩后感:弹丸论破 游戏玩后感:流景之海的艾佩莉亚 Xilinx_HLS上板过程记录 游戏玩后感:告别回忆2 游戏玩后感:恋爱绮谭 Faiss和Rapidsai_Raft使用记录 游戏玩后感:近月少女的礼仪 游戏玩后感:樱色之云,绯色之恋 游戏玩后感:幸运草的约定 游戏玩后感:星之梦、候鸟和丸子与银河龙 游戏玩后感:白色相簿2 Windows上使用VTune分析PyTorchExtension调用的Cpp程序 SpinalHDL上板过程记录 游戏玩后感:仰望夜空的星辰 最简单的算卦方法之一:梅花易数法 游戏玩后感:苍之彼方的四重奏 krkr引擎解包工具介绍 自定义CUDA实现PyTorch算子的四种简单方法 游戏玩后感:星空的记忆 游戏玩后感:9nine 游戏玩后感:AtriMyDearMoments 游戏玩后感:极限脱出 游戏玩后感:魔女的夜宴 SSH实现多跳代理 动漫观后感:向山进发 flv重封装H264、AAC流 动漫观后感:夏日重现 CSP模板 游戏玩后感:海沙风云 动漫观后感:灵能百分百 游戏玩后感:交响乐之雨 游戏玩后感:爱上火车LastRun 游戏玩后感:LittleBustersEX 游戏玩后感:SummerPockets 游戏玩后感:逆转裁判 Ultra96V2开发板简单使用 SpinalWorkshop实验笔记(三) SpinalWorkshop实验笔记(二) SpinalWorkshop实验笔记(一) PYNQ开发板上使用USB声卡+OSS兼容层播放音频 TestOS移植K210开发板 rCore-Tutorial-Book-v3学习笔记(七) 动漫观后感:凉宫春日的忧郁 rCore-Tutorial-Book-v3学习笔记(♭七) rCore-Tutorial-Book-v3学习笔记(六) rCore-Tutorial-Book-v3学习笔记(五) rCore-Tutorial-Book-v3学习笔记(四) rCore-Tutorial-Book-v3学习笔记(三) rCore-Tutorial-Book-v3学习笔记(二) rCore-Tutorial-Book-v3学习笔记(一) 游戏玩后感:RewritePlus MIT-6.S081-2020实验(xv6-riscv64)十一:net MIT-6.S081-2020实验(xv6-riscv64)十:mmap MIT-6.S081-2020实验(xv6-riscv64)八:lock MIT-6.S081-2020实验(xv6-riscv64)七:thread MIT-6.S081-2020实验(xv6-riscv64)六:cow MIT-6.S081-2020实验(xv6-riscv64)五:lazy MIT-6.S081-2020实验(xv6-riscv64)四:traps MIT-6.S081-2020实验(xv6-riscv64)三:pgtbl MIT-6.S081-2020实验(xv6-riscv64)二:syscall 动漫观后感:吹响吧上低音号 MIT-6.S081-2020实验(xv6-riscv64)一:util 快速生成网络mp4视频缩略图技术 用plantuml画图示例 QQ缩略图和大图不同实现 Python制作字符图片 动漫观后感:命运石之门 Unity3D+Post_Processing_Stack_V2自定义后处理效果研究
MIT-6.S081-2020实验(xv6-riscv64)九:fs
VnYzm · 2021-01-11 · via

实验文档

概述

这次实验涉及文件系统,重点是对inode节点的操作。

内容

Large files

这个任务主要目的是支持更大的文件。和内存映射类似,文件系统中也有一个类似“页表”的结构,每个文件(inode)都有自己的一个“页表”,维护自己文件占用的文件块。和内存不同的是,这个“页表”的级别是自定义的,原始的xv6的表有13项,前12项直接包含文件块的地址,第13项是二级表的地址,二级表包含256项,每项都是文件块的地址,所以单个文件最大为12+256个文件块,为了支持更大的文件,需要将直接包含文件块地址的表项中取一项支持三级表,这样单个文件就可以扩大到11+256+256*256块。整体思路还是很清晰的,bmap函数添加:

  bn -= NINDIRECT;

  if(bn < NININDIRECT){
      int lev1 = bn / NINDIRECT, lev2 = bn % NINDIRECT;
    // Load indirect block, allocating if necessary.
    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[lev1]) == 0){
      a[lev1] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if((addr = a[lev2]) == 0){
      a[lev2] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    return addr;
  }
  panic("bmap: out of range");

itrunc函数也做相应的添加:

  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]);
      }
    }
    brelse(bp);
    bfree(ip->dev, ip->addrs[NDIRECT + 1]);
    ip->addrs[NDIRECT + 1] = 0;

这个任务主要实现软符号链接,个人还是觉得有点难度,需要对inode节点的各类操作比较熟悉。首先是给inode和dinode添加一个字符串属性用来存储符号链接中的目标路径,比如dinode:

struct dinode {
  short type;           // File type
  short major;          // Major device number (T_DEVICE only)
  short minor;          // Minor device number (T_DEVICE only)
  short nlink;          // Number of links to inode in file system
  uint size;            // Size of file (bytes)
  uint addrs[NDIRECT+2];   // Data block addresses
  char target[MAXTARGET];
};

主要这个MAXTARGET这个常量是有讲究的,因为dinode是一个一个排布在一个硬盘块里面的,所以硬盘块的大小必须是dinode结构体大小的倍数,硬盘块的大小是常量BSIZE的大小,即1024字节,当没有target属性时,dinode的大小为2*4+4+4*13=64,刚好被1024整除,同时查看param.h可以发现xv6规定的路径长度最大可以为128,所以MAXTARGET还得大于128,因此我取MAXTARGET=192,192+64=256,被1024整除。

然后就是sys_symlink:

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

首先需要注意获得传入系统调用的字符串需要用argstr,不能用argaddr获得地址后自己复制,因为那个地址是用户内存的虚拟地址,现在在内核态,页表已经被换掉了。这里调用了create函数来创建符号文件,因为create函数里没有对inode的target属性赋值,所以需要在这里处理。另外就是create函数返回的有效inode是已经经过iget和ilock的了,所以这里create完就直接赋值target属性并更新到对应的dinode,然后iunlock解锁再iput释放inode指针(合起来是iunlockput函数)。

接着是对open函数的修改,主要就是添加一个沿着符号链接不断查找的过程,经过查找后得到的路径才是需要open的真正路径:

  if(omode & O_CREATE){
      ......
  } else {
      int cnt = 0;
      for (;;) {
          ip = namei(path);
          if (ip == 0) {
              end_op(); return -1;
          }
          ilock(ip);
          if(ip->type != T_SYMLINK || (omode & O_NOFOLLOW)) break;
          memmove(path, ip->target, MAXPATH);
          iunlockput(ip);
          cnt++;
          if (cnt > 9) {
              end_op(); return -1;
          }
      }
      ......

namei得到的inode是经过iget但没ilock的,所以取属性和修改属性需先ilock。另外就是memmove参数的最后一个参数需要是MAXPATH而不是sizeof(ip->target),因为inode的target属性我跟随dinode的target属性都设成192字节的字符串,大小大于MAXPATH即128,所以如果按sizeof来复制会溢出。


由于我使用的是虚拟机,虽然我已经通过使用无桌面版arch linux+ssh控制来尽可能减少CPU和内存的消耗了,但文件读写还是非常难顶。虽然程序单独测试正确,思路也和网上别人通过的程序思路基本一样,最后make grade的时候还是超时了,不得已,把测试脚本里的bigfile和usertests测试时限都改成10分钟才通过(usertests里的writebig好像在这次实验里格外耗时)。估计使用真机或WSL读写真磁盘来完成本实验情况会好一些。