6.828(2018) hw: big file

这个作业主要就是让你熟悉xv6的文件系统,并能做出一些修改,主要的任务是让你增加一个二级页来增加一个文件最大的大小。

准备工作

  1. 修改 Makefile中的 CPUS := 2 为 CPUS := 2,并 在后面加一行 QEMUEXTRA = -snapshot,修改这两项可以让后面的测试更快。

  2. 下载 big.c, 并在Makefile的 UPROGS 加一行 _big\,这个文件主要用来测试。

  3. 修改 param.h 的宏定义为 #define FSSIZE 20000 // size of file system in blocks,增加文件系统的最大块数。

任务

我们的任务是修改bmap函数,使其实现二级页。xv6现有的文件地址结构如图示

xv6 inode

一个文件的inode共有13个地址项,前12个为直接块,最后一个为一级间接块。

在这个文件系统中,一个块为512B,一个地址占4B,所以一个文件最多有12个直接块和(512B / 4B = 128)个一级间接块,共为140个块, 共为140 * 512B = 71680 B,为70KB

任务要求inode大小不变,所以我们要修改成前11个为直接块,第12个为一级间接块,最后一个为二级简洁块。

在修改后的文件系统中,一个文件最多有11个直接块和,128个一级间接块, (128 * 128 = 16384)个二级间接块,共为 16523个块,共为 16523 * 512B = 8459776B,为8MB。

实现

我们只需要修改bmap函数来实现二级间接块的映射,而不需要处理二级间接块的删除。

相关的宏定义在 fs.h 中,修改如下:


#define NDIRECT 11                                    // 直接块个数

#define NINDIRECT (BSIZE / sizeof(uint))              // 一级间接块个数

#define NDINDIRECT (NINDIRECT * NINDIRECT)            // 二级间接块个数

#define MAXFILE (NDIRECT + NINDIRECT + NDINDIRECT)    // 一个文件最大的块数

还要修改下面的dinode结构体

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

最后修改bmap函数

// Inode content
//
// The content (data) associated with each inode is stored
// in blocks on the disk. The first NDIRECT block numbers
// are listed in ip->addrs[].  The next NINDIRECT blocks are
// listed in block ip->addrs[NDIRECT].

// Return the disk block address of the nth block in inode ip.
// If there is no such block, bmap allocates one.
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;

  // support doubly-indirect block
  // 如果块号在二级间接块中
  if (bn < NDINDIRECT) {
    // 如果第一个目录块没有分配,那就分配一个
    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 / (BSIZE / sizeof(uint));
    uint idx2 = bn % (BSIZE / sizeof(uint));
    // 如果第二级索引块没有分配, 那就分配一个
    if((addr = a[idx1]) == 0){
      a[idx1] = addr = balloc(ip->dev);
      log_write(bp);
    }
    // 这里要记得释放掉第一级的块
    brelse(bp);
    // 读入第二级的块
    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;
  }

最后运行make qemu-nox重新编译运行即可,在shell中输入big执行测试。

如 测试提示 panic: balloc: out of blocks, 可能是前面的准备工作中未修改param.h中的FSSIZE,导致没有块可以分配了。如修改了的话还报错,可以试着运行 rm fs.img 删除xv6的文件系统镜像,再重新运行即可。

成功的话会输出下面的信息。
finish

总结

这个实验总的来说不难,只要理解inode地址的结构就可以正确实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值