2021 XV6 9: file system

文章详细介绍了对文件系统中inode结构的改进,添加了二级映射功能,类似于页表的概念,用于扩展文件的地址映射。同时,实现了软链接的功能,允许inode存储链接文件的路径,并在打开文件时根据需要进行递归查找。文中还涵盖了bmap函数的修改以支持新的映射机制,以及itrunc函数的更新以正确释放缓冲块和映射。此外,提到了如何通过系统调用添加和处理软链接,并在open系统调用中处理跟踪链接的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个实验有两个任务。

1.Large files

在inode和dinode的数据结构里边是只有直接映射和一级间接映射的,我们的任务是在直接映射里面拿一个位置来放二级映射。和页表有点像,不是么。

首先在改变数据结构:

#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
#define DOUBLENINDIRECT (NINDIRECT * NINDIRECT)
#define MAXFILE (NDIRECT + NINDIRECT + DOUBLENINDIRECT)

// On-disk inode structure
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+1+1];   // Data block addresses
};


// in-memory copy of an inode
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+1+1];
};

接着我们在根据块号找缓冲块地址的bmap中修改按需分配:

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

  if(bn < NDIRECT){
    if((addr = ip->addrs[bn]) == 0)
      ip->addrs[bn] = addr = balloc(ip->dev);
    return addr;
  }
  bn -= NDIRECT;

  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;

  if (bn < DOUBLENINDIRECT)
  {
    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 num = bn / NINDIRECT;// 第一个间接块偏移
    uint off = bn % NINDIRECT;// 第二个间接块偏移
    // 处理第一个间接块
    if ((addr = a[num]) == 0)
    {
      a[num] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    // 处理第二个间接块
    if ((addr = a[off]) == 0)
    {
      a[off] = 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, k;
  struct buf *bp, *bp1;
  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])
      {
        bp1 = bread(ip->dev, a[j]);// 读入第二间接块
        b = (uint*)bp1->data;
        for (k = 0; k < NINDIRECT; k++)
        {
          if (b[k])
            bfree(ip->dev, b[k]);// 释放map上数据块映射
        }
        brelse(bp1);// 释放第二间接块的缓存块
        bfree(ip->dev, a[j]);// 释放map上第二间接块的映射
      }
    }
    brelse(bp);// 释放第一间接块的缓存块
    bfree(ip->dev, ip->addrs[NDIRECT+1]);// 释放第一间接块的映射
    ip->addrs[NDIRECT+1] = 0;
  }
  

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

好像还得改一个FSSIZE

测试通过辣:

2.Symbolic links

软链接的实现是个inode,inode的数据块中存储了链接文件的路径,然后我们在打开一个文件的时候如果指定要追踪,就按照文件链接的路径一直搜索下去,否则就直接返回当前的inode。

系统调用的添加和以前一样,之后就是写系统调用,在系统调用中创建一个文件的inode,然后把路径写入inode的数据块中,由于create里边涉及到inode对应磁盘块的更新,我们用xv6的日志系统括起来,也就是begin_op,logwrite,end_op三个元素:

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;

  // 创建软链接文件inode
  begin_op();
  if ((ip=create(path, T_SYMLINK, 0, 0))==0)
  {
    end_op();
    return -1;
  }
  
  // 将文件路径target写入文件
  if (writei(ip,0,(uint64)target,0,MAXPATH)<0)
  {
    end_op();
    return -1;
  }

  iunlockput(ip);

  end_op();
  return 0;
}

之后在open的系统调用中,当inode类型是软连接,在文件的打开模式表示跟踪的情况下,进行递归查询inode直到查到当前inode不是软链接为止。代码如下所示:

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

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

  // 软链接类型文件
  if (ip->type == T_SYMLINK)
  {
    // 标记O_NOFOLLOW表示直接打开这个文件而不是跟踪软链接
    // 未标记则继续跟踪
    if (!(omode & O_NOFOLLOW))
    {
      int cycle = 0;
      char target[MAXPATH];
      while (ip->type==T_SYMLINK)
      {
        if (cycle == 10)
        {
          iunlockput(ip);
          end_op();
          return -1;
        }
        cycle++;
        memset(target,0,sizeof(target));
        readi(ip,0,(uint64)target,0,MAXPATH);
        iunlockput(ip);
        if((ip = namei(target)) == 0){
          end_op();
          return -1;
        }
        ilock(ip);
      }
      
    }
  }

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

测试通过辣:

usertests也没问题:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值