MIT 6.828 Homework: biggers files for xv6

任务概述

在这个作业中,需要增加 xv6 系统允许的文件大小。当前的 xv6 文件大小被限制为 140 扇区 (sectors),因为 xv6 的索引节点 (innode) 包含了 12 个 “直接的” 块 (block) 的序号和一个 “单独间接 (singly-indirect)” 块序号,这个序号指向一个最多可以存储 128 个块号的块。为了增加允许的文件大小,需要修改 xv6 代码在每个索引节点中支持 “双间接 (doubly-indirect)” 块,包含 128 个单间接块的地址,每个块又包含最多 128 个数据块的地址。最终一个文件将会能够包含 11 + 128 + 128 * 128 = 16523 个扇区。

准备工作

  • 修改 Makefile,将 CPUS 设置为:
CPUS := 1
  • 在 QEMUOPTS 前添加:
QEMUEXTRA = -snapshot

上述两个步骤会极大的增加 xv6 创建大文件的速度。

  • 修改 param.h 将 FSSIZE 设置为:
#define FSSIZE 20000  // size of file system in blocks

big.c 添加到 xv6 目录下,将它添加到 UPROGS 列表中,启动 xv6,执行 big 命令,将会在 xv6 中创建一个 xv6 允许情况下最大的文件并报告大小,运行结果应该是 140 sectors。

  • big.c
#include "types.h"
#include "stat.h"
#include "user.h"
#include "fcntl.h"

int
main()
{
  char buf[512];
  int fd, i, sectors;

  fd = open("big.file", O_CREATE | O_WRONLY);
  if(fd < 0){
    printf(2, "big: cannot open big.file for writing\n");
    exit();
  }

  sectors = 0;
  while(1){
    *(int*)buf = sectors;
    int cc = write(fd, buf, sizeof(buf));
    if(cc <= 0)
      break;
    sectors++;
	if (sectors % 100 == 0)
		printf(2, ".");
  }

  printf(1, "\nwrote %d sectors\n", sectors);

  close(fd);
  fd = open("big.file", O_RDONLY);
  if(fd < 0){
    printf(2, "big: cannot re-open big.file for reading\n");
    exit();
  }
  for(i = 0; i < sectors; i++){
    int cc = read(fd, buf, sizeof(buf));
    if(cc <= 0){
      printf(2, "big: read error at sector %d\n", i);
      exit();
    }
    if(*(int*)buf != i){
      printf(2, "big: read the wrong data (%d) for sector %d\n",
             *(int*)buf, i);
      exit();
    }
  }

  printf(1, "done; ok\n"); 

  exit();
}

运行 big 命令结果如下:

$ big
.
wrote 140 sectors
done; ok

一些说明

  • innode 定义在 fs.h 的 struct dinnode 中,关注其中的 NDIRECT, NINDIRECT, MAXFILE, addrs[]。
  • 在磁盘上查找文件数据的代码在 fs.c 的 bmap() 中,在读取和写入文件时,bmap() 都会被调用。
  • bmap() 处理两种块序号,bn 是 “逻辑块号 (logic numbers)”,一个与文件开头部分相关的块号,在 ip->addrs[] 中的块号是 “磁盘块号 (disk block numbers)”

任务要求

修改 bmap(),使它除了实现单间接块和直接块之外还实现了双间接块。单间接块的数目将会由 12 变为 11,多出的一个块将会成为双间接块。ip->addrs[] 的起始 11 个元素应该是直接块,第 12 个元素应该是单间接块,第 13 个元素应该为新的双间接块。

任务实现

  • 修改 fs.h struct dinnode 结构体。
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
#define MAXFILE (NDIRECT + NINDIRECT * 129)

// 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
};
  • 修改 file.h struct innode 结构体。
// 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];
};
  • 修改 fs.c 的 bamp() 函数。
static uint
bmap(struct inode *ip, uint bn)
{
  uint addr, *a;
  struct buf *bp,*dp;

  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);//Allocate a zeroed disk block.
    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 < MAXFILE-NINDIRECT-NDIRECT){
    // Load indirect block, allocating if necessary.
    if((addr = ip->addrs[NDIRECT+1]) == 0)
      ip->addrs[NDIRECT+1] = addr = balloc(ip->dev);//Allocate a zeroed disk block.
    bp = bread(ip->dev, addr);
    a = (uint*)bp->data;
    if((addr = a[bn/NINDIRECT]) == 0){
      a[bn/NINDIRECT] = addr = balloc(ip->dev);
      log_write(bp);
    }
	dp=bread(ip->dev, addr);
	a = (uint*)dp->data;
	if((addr = a[bn%NINDIRECT]) == 0){
      a[bn%NINDIRECT] = addr = balloc(ip->dev);
      log_write(dp);
    }
	brelse(dp);
    brelse(bp);
    return addr;
  }

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

对 xv6 的源代码修改完成

测试结果:

$ big
.....................................................................................................................................................................
wrote 16523 sectors
done; ok
posted @ 2022-12-28 10:34  雪中的茶  阅读(273)  评论(0编辑  收藏  举报