首页 > 其他分享 >[MIT 6.S081] Lab: file system

[MIT 6.S081] Lab: file system

时间:2024-02-20 20:44:21浏览次数:27  
标签:addr ip NINDIRECT inode uint file bp S081 MIT

Lab: file system

在这个实现中我们将为 xv6 的文件系统实现二级间接块以支持大文件,与实现文件的软链接。

Large files

在该任务中,我们将为 xv6 的文件系统实现二级间接块,以支持大文件。对于这个功能,我们需要修改 struct inodeaddr 字段的功能。

在实现功能之前,xv6 的 struct inode 已经预先实现了一级间接块功能了。对于 addr 的前 12 个地址,可以直接指向一个具体的数据,这些数据块被叫作直接块。而对于 addr 的最后一个地址,则指向了一个间接块,这个间接块存放着的,是一个个指向数据块的地址,这样实现了文件的基本存储。经过计算可以知道,目前 xv6 的实现使得一个文件最大只能有 \(12 + 256\) 个数据块。

我们的目标就是:以一个直接块的代价,换来一个二级间接块。这样实现后,一个文件最大即可为 \(11 + 256 + 256^2\) 个数据块的空间了。

首先,我们需要修改一下定义,将原来的 \(12\) 个 直接块,改为 \(11\) 个直接块。实验要求我们修改这个地方后不能改变 addr 字段的大小,因此还需将其增加一下。由于构建文件涉及到这个宏,因此我们必须修改这个宏的数字大小才可以构建出一个符合的文件系统,否则会报错。

// kernel/fs.h
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT * NINDIRECT)

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

// kernel/file.h
struct inode {
  uint dev;           // Device number
  uint inum;          // Inode number
  int ref;            // Reference count
  struct sleeplock lock; // protects everything below here
  int valid;          // inode has been read from disk?

  short type;         // copy of disk inode
  short major;
  short minor;
  short nlink;
  uint size;
  uint addrs[NDIRECT+2];
};

现在,我们更改一下 bmap 的实现。因为现在增加了一个二级块,那么只需要检查是否需要的数据块位置在这个二级块内就好了,然后就是延迟分配的问题,等到需要被访问到的时候,才分配一块数据块。要注意的是,第一层数据块存放地址,第二层依然存放地址(其实就是重复一次),访问到第三个块的时候才是文件的数据块。

// kernel/fs.c
static uint
bmap(struct inode *ip, uint bn)
{
  ...
  bn -= NINDIRECT;

  if (bn < NINDIRECT * 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;

    uint idx1 = bn / NINDIRECT;
    if ((addr = a[idx1]) == 0) {
      a[idx1] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    
    uint idx2 = bn % NINDIRECT;
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if ((addr = a[idx2]) == 0) {
      a[idx2] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);

    return addr;
  }

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

最后是对这个二级块实现增加一个回收机制,也就是一个二重循环,先将最里面的释放后,才将次层释放。

void
itrunc(struct inode *ip)
{
  if (ip->addrs[NDIRECT + 1]) {
    bp = bread(ip->dev, ip->addrs[NDIRECT + 1]);
    a = (uint*)bp->data;

    for (int j = 0; j < NINDIRECT; j ++) {
      if (a[j]) {
        struct buf *bp2 = bread(ip->dev, a[j]);
        uint *ad = (uint*)bp2->data;
        for (int k = 0; k < NINDIRECT; k ++) {
          if (ad[k]) 
            bfree(ip->dev, ad[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);
}

现在我们要增加一个软链接功能,类似于 ln 命令,多个位置的文件都指向一个实际的文件,但在这个当中不能出现链接层数过多或者循环链接的问题。

首先我们依然是要为其添加一下系统调用,就像之前的系统调用添加一样的操作,然后按照实验要求将两个类型定义的宏加上。在读取好 sys_symlink 的参数之后,我们要先为这个链接存放的地址创建一个 inode ,让它作为一个链接文件类型,接着向这个 inode 写入要链接的目标地址。

// kernel/sysfile.c
uint64 sys_symlink(void) {
  char target[MAXPATH], path[MAXPATH];

  if (argstr(0, target, sizeof(target)) < 0 || argstr(1, path, sizeof(path)) < 0) {
    return -1;
  }

  begin_op();

  struct inode *i_target = create(path, T_SYMLINK, 0, 0);
  if (i_target == 0) {
    end_op();    
    return -1;
  }

  if (writei(i_target, 0, (uint64)target, 0, sizeof(target)) < sizeof(target)) {
    end_op();
    return -1;
  }
  
  iunlockput(i_target);

  end_op();

  return 0;
}

接着是处理 sys_open 在打开链接文件时候的问题。当打开的文件是一个链接类型的文件时,我们需要找到其真正的文件。但在这里要注意一下,实验要求链接层数不能过多,提供了一个 \(10\) 层作为极限的建议。因此,我们也可以预先定义一个 LINK_LIMIT 宏,作为链接层数的限制。剩下问题就是判断一下这个文件是不是链接文件,是链接文件的话再看看现在的打开模式是不是限制了不能跟踪,如果能跟踪的话,我们再通过迭代尝试找到目标文件,如果找到了就直接退出迭代,出错误了直接 \(-1\) 。如果迭代结束了,那么意味着超过了我们的警戒线,可以直接认为是错误。

uint64
sys_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)) { 
    int loop;
    for (loop = 0; loop < LINK_LIMIT; loop ++) {
      if (readi(ip, 0, (uint64)path, 0, sizeof(path)) != sizeof(path)) {
        iunlockput(ip);
        end_op();
        return -1;
      }

      iunlockput(ip);
      if ((ip = namei(path)) == 0) {
        end_op();
        return -1;
      }

      ilock(ip);
      if (ip->type != T_SYMLINK) {
        break;
      }
    }

    if (loop == LINK_LIMIT) {
      iunlockput(ip);
      end_op();
      return -1;
    }
  }

  if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
  ...
}

标签:addr,ip,NINDIRECT,inode,uint,file,bp,S081,MIT
From: https://www.cnblogs.com/FlandreScarlet/p/18024005

相关文章

  • dockerfile中安装软件时需要选择地区的问题
     一个例子FROMubuntu:20.04WORKDIR/rootCOPY./sources.list/etc/apt/sources.listCOPY./cron-start.sh/opt/cron-start.shARGDEBIAN_FRONTEND=noninteractiveENVTZ=Asia/ShanghaiRUNapt-getupdate&&\apt-getinstall-ypython3python3-pipv......
  • err code 90030,err msg webhook over limit
    钉钉群机器人发文本消息提示"webhookoverlimit"从2024.02.01钉钉修改了自定义机器人推送政策,免费额度,由之前的不限制,改为:目前钉钉已经限制了免费版的发送次数每个企业每月5000条(之前创建的外部群不限制,但是已经不能新增机器人了。)。钉钉收费版是9800元每年,然后每月5w条(如果......
  • G. Vlad and Trouble at MIT
    原题链接题解细节很多的树形dp,请看代码code#definelllonglong#include<bits/stdc++.h>usingnamespacestd;llsit[100005]={0};llf[100005]={0};vector<ll>G[100005];charstr[100005];inlinevoidread(ll&x){x=0;llflag=1;charc=......
  • [GIT] GIT Commit Message 规范
    1概述本文主要用于总结自己的一套GitCommitMessage。1.1GitCommitMessage是什么?每次基于Git提交代码,都要写Commitmessage(提交说明),否则就不允许提交。$gitcommit-m"helloworld"-m参数:指定commitmesage1.2规范的提出背景软件工程团队多人协作时,c......
  • java中file转字符串,字符串输出为文件
     读取文件转为字符串: //输入文件File类型,输出字符串 publicstaticStringfileToString(Filefile){ InputStreamis=null; ByteArrayOutputStreambos=newByteArrayOutputStream(); byte[]buffer=newbyte[1024]; inttemp=-1; try{ is=newFi......
  • Filezilla 使用教程
    FileZilla是一款免费开源的FTP客户端软件,虽然它是免费软件,可性能却一点也不含糊,比起那些共享软件来有过之而无不及,具备大多数的FTP软件功能。其可控性、有条理的界面和管理多站点的简化方式、特别是它的传输速度,简直是出神入化,也是它最大的特色。总的来说是它一款出类拔萃的......
  • FileZilla 免费的FTP软件工具下载与使用教程
    FileZilla是一个免费并且全平台可用的FTP软件,借助FileZilla可以方便的通过FTP实现文件的上传与下载。FileZilla是VPSGO一直在使用的,所以今天就把这个工具介绍给大家,包括FileZilla下载、FileZilla安装,以及简单的FileZilla教程。一、FileZilla下载FileZilla官网:https:/......
  • FileZilla 服务器 报Warning: FTP over TLS is not enabled, users cannot securely l
    FileZilla服务器报Warning:FTPoverTLSisnotenabled,userscannotsecurelylogin.1.登录至FTP服务器 2.选择编辑->设置->SSL/TLS设置->。。。。。[看图操作],注:证书导出路径不能有中文字符 3.选择编辑->设置->SSL/TLS设置->选择上一步操作导出的证书,注意导出......
  • Filezilla Server 使用教程
    FilezillaServer使用教程FileZillaServer是一款免费开源的FTP服务器端架设程序,使用FileZillaServer你可以轻轻松松在你的服务器开设ftp,下面演示用FileZillaServer来建立服务器上各网站的ftp。步骤1、首先下载好FilezillaServer软件,点进去下载即可,如图所示: 将下载好的Fil......
  • Git操作 :从一个分支cherry-pick多个commit到其他分支
    在branch1开发,进行多个提交,这是切换到branch2,想把之前branch1分支提交的commit都【复制】过来,怎么办?首先切换到branch1分支,然后查看提交历史记录,也可以用sourceTree查看,也可以用命令gitlog例如我的gitlog如下:commit1xxx_id1commit2xxx_id2commit3xxx_id3我想把comm......