其他分享
首页 > 其他分享> > 9. Lab: file system

9. Lab: file system

作者:互联网

https://pdos.csail.mit.edu/6.S081/2021/labs/fs.html

1. Large files (moderate)

1.1 要求

Modify bmap() so that it implements a doubly-indirect block, in addition to direct blocks and a singly-indirect block. You'll have to have only 11 direct blocks, rather than 12, to make room for your new doubly-indirect block; you're not allowed to change the size of an on-disk inode. The first 11 elements of ip->addrs[] should be direct blocks; the 12th should be a singly-indirect block (just like the current one); the 13th should be your new doubly-indirect block. You are done with this exercise when bigfile writes 65803 blocks and usertests runs successfully:

要求扩大 xv6 中文件大小上限。目前 xv6 文件限制为 268 个块,或 268*BSIZE 字节(在 xv6 中 BSIZE 为 1024)。 因为一个 xv6 inode 包含 12 个“直接”块号和一个“单独间接”块号,这是指一个块最多可以容纳 256 个块号,总共 12+256=268 块。
因此需要更改 xv6 文件系统代码以支持每个 inode 中的“双重间接”块,其中包含 256 个单间接块地址,每个块最多可包含 256 个数据块地址。 结果将是一个文件将能够包含多达 65803 个块,或 256*256+256+11 个块(11 个而不是 12 个,因为我们将为双间接块牺牲一个直接块号)
原来的结构如图下:
image.png
修改后的结构应当如下:
image.png
可以看到,有点类似多级页表的思路。

1.2 分析

要注意的点如下:

1.3 实现

#define NDOUBLEINDIRECT (NINDIRECT * NINDIRECT)
#define NDIRECT 11
// 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+2];   // 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+2];
};
static uint
bmap(struct inode *ip, uint bn)
{
  uint addr, *a;
  struct buf *bp, *inbp;
  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;
  // load doublely-indirect block
  if(bn < NDOUBLEINDIRECT){
    if((addr = ip->addrs[NDIRECT + 1]) == 0) 
      ip->addrs[NDIRECT + 1] = addr = balloc(ip->dev); // alloc doublely-indirect block

    // get indirect block index
    inbp = bread(ip->dev, addr);
    a = (uint*)(inbp->data);

    uint in_index = bn / NINDIRECT;
    uint bn_index = bn % NINDIRECT;
    
    // Load indirect block, allocating if necessary.
    if ((addr = a[in_index]) == 0){
      a[in_index] = addr = balloc(ip->dev);
      log_write(inbp);
    }
    brelse(inbp);
    
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if ((addr = a[bn_index]) == 0){
      a[bn_index] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    return addr;
  }

  panic("bmap: out of range");
}
// Truncate inode (discard contents).
// Caller must hold ip->lock.
void
itrunc(struct inode *ip)
{
  int i, j, k;
  struct buf *bp, *inbp;
  uint *a;
  uint *tmp;

  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]){
    inbp = bread(ip->dev, ip->addrs[NDIRECT + 1]);
    a = (uint*)(inbp->data);
    for (j = 0; j < NINDIRECT; j++){
      if (a[j]) {
        bp = bread(ip->dev, a[j]);
        tmp = (uint*)bp->data;
        for(k = 0; k < NINDIRECT; k++){
          if(tmp[k])
            bfree(ip->dev, tmp[k]);
        }
        brelse(bp);
        bfree(ip->dev, a[j]);
        a[j] = 0;
      }
    }
    brelse(inbp);
    bfree(ip->dev, ip->addrs[NDIRECT + 1]);
    ip->addrs[NDIRECT + 1] = 0;
  }

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

2. Symbolic links(moderate)

2.1 要求

You will implement the symlink(char *target, char *path) system call, which creates a new symbolic link at path that refers to file named by target. For further information, see the man page symlink. To test, add symlinktest to the Makefile and run it. Your solution is complete when the tests produce the following output (including usertests succeeding).

实现 symlink 接口,比较简单,与 link 的区别在于,symlink 会创建文件,而 link 接口只是增加目标文件的引用计数,并写入目录。

2.2 分析

实现主要有 2 点:

2.3 实现

inode 结构中增加 char symlinkpath[128];,用于存储目标文件的名字。

uint64 sys_symlink(void)
{
  char path[MAXPATH], target[MAXPATH];
  struct inode *ip;
  if(argstr(0, target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0)
    return -1;

  begin_op();
  if ((ip = namei(path)) == 0){
    ip = create(path, T_SYMLINK, 0, 0);
    if (ip == 0){
      end_op();
      return -1;
    }
  }else if (ip->type != T_SYMLINK){
    end_op();
    return -1;
  }else{
    ilock(ip);
  }

  memset(ip->symlinkpath, 0, MAXPATH);
  memmove(ip->symlinkpath, target, sizeof(target));
  iunlockput(ip);
  end_op();
  return 0;
}

需要注意如果有 O_NOFOLLOW 的 flag,则直接访问链接文件,而不是访问 inode.symlinkpath 的文件。
其次要注意存在链接文件 链接 链接文件的操作,有点套娃,比如 a->b,b->c,c->a,此时如果没有防范措施会无限套娃,因此根据 hints 加了个递归层次限制。

uint64 sys_open(void)
{
  char path[MAXPATH];
  int fd, omode;
  struct file *f;
  struct inode *ip, *symip;
  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;
    }
  }

  int cnt = 0;
  while(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)){
    if (cnt >= 10) {
      iunlockput(ip);
      end_op();
      return -1;
    }

    symip = namei(ip->symlinkpath);
    if (symip) {
      cnt++;
      iunlockput(ip);
      ip = symip;
      ilock(ip);
    }
    else {
      break;
    }
  }

  if (cnt == 0 && ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)){
    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;
}

标签:addr,ip,bn,system,Lab,uint,addrs,file,dev
来源: https://www.cnblogs.com/lawliet12/p/16101528.html