MIT6.828_HW10_Bigger files for xv6

Homework: bigger files for xv6

本节中,我们将增加xv6文件的最大尺寸,xv6的i节点包含12个直接索引节点和一个一级索引节点,因此当前的xv6文件大小限制在512/4=128+12=140个扇区即71680个字节,我们要修改xv6文件系统的代码位每个i节点添加一个二级索引节点,二级索引节点指向的索引块包含128个一级索引节点,每个一级索引节点包含128个条目,每个条目指向一个数据块,这样一个文件的大小限制将拓展到11+128+2^14=16523个扇区(约8.5M)。建议阅读一下xv6讲义的File system部分。

Preliminaries

修改xv6 Makefile中CPUS的定义:

CPUS := 1

在QEMUOPTS之前添加

QEMUEXTRA = -snapshot

当xv6创建大文件时,以上两个步骤能够极大地加速qemu。

mkfs初始化文件系统时,定义其可用数据块少于1000个,而可用数据块太少而无法支持我们将要进行的更改。 修改param.h以将FSSIZE设置为:

#define FSSIZE 20000 //文件系统的大小(以块为单位)

将big.c下载到xv6目录中,将其添加到UPROGS列表中,启动xv6,然后运行big。 它创建的文件与xv6允许的一样大,并且会报告生成的大小,应该是140个扇区。

What to Look At

fs.h中的inode结构体定义了on-disk inode的格式,你可能对NDIRECT,NINDIRECT,MAXFILE和struct dinode的addrs []成员特别感兴趣。 xv6索引节点结构如下所示:
在这里插入图片描述
fs.c中的bmap()函数用于查找文件在硬盘上的数据,阅读该函数并确保你了解它做了啥。当对文件进行读写时会调用bmap函数,bmap()根据需要分配新的块来保存文件内容,并在需要时分配一个间接块来保存块地址。bmap处理两种块,参数bn是相对于文件起始地址的逻辑块号,即ip->addrs[]中的块号,而代入bread的参数是硬盘上的物理块号,你可以把bmap的功能视作将一个文件的逻辑块映射到硬盘的物理块,然后返回对应物理块的地址。

Your Job

修改bmap函数来实现二级间接映射,inode节点应包含11个直接索引节点,1个一级间接索引节点和1个二级间接索引节点,你无需修改xv6来处理删除带有二级间接索引块的文件的情况。如果实现成功,big将报告可以写入16523个扇区。

Hints

1.记得修改NDIRECT时,也要修改file.h中inode->addrs[]及fs.h中dinode->addrs[]的大小(打开文件后会将硬盘上的索引节点复制到内存中,因此要保证二者一致)。
2.修改NDIRECT的定义后,确保创建一个新的fs.img,因为mkfs会使用NDIRECT来构建初始的文件系统,如果删除了fs.img,在Unix(而非xv6)下make会为你构建一个新的。
3.对每个调用bread()读取的块都要记得使用brelse()。

参考代码中实现一级索引节点的代码后实现起来还是比较简单的,实现代码如下:
fs.h

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

fs.c:

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

  if(bn < NDIRECT){ //小于NDIRECT的逻辑块号应用直接映射
    if((addr = ip->addrs[bn]) == 0)
      ip->addrs[bn] = addr = balloc(ip->dev);
    return addr;
  }
  bn -= NDIRECT;

  if(bn < NINDIRECT){ //大于等于NDIRECT,小于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); // Return a locked buf with the contents of the indicated block.
    a = (uint*)bp->data; //a指向为索引块分配的缓冲区数据起始地址(缓冲区中保存了对应块的内容)
    if((addr = a[bn]) == 0){ //查找对应条目对应数据块是否存在,不存在则分配一块
      a[bn] = addr = balloc(ip->dev);
      log_write(bp);
    }
    brelse(bp);
    return addr;
  }
  bn -= NINDIRECT;
  if(bn < NSECONDINDIRECT) //大于等于NINDIRECT,小于NSECONDINDIRECT的逻辑块号应用二级间接映射
  {
	if((addr = ip->addrs[NDIRECT+1]) == 0) 
		ip->addrs[NDIRECT+1] = addr = balloc(ip->dev); //分配一个索引块
	bp = bread(ip->dev, addr); 
	a = (uint*)bp->data;		//a指向一级索引块的缓冲区数据的起始地址(缓冲区中保存了对应块的内容)
	if((addr = a[bn/NINDIRECT]) == 0) 
	{
		a[bn/NINDIRECT] = addr = balloc(ip->dev); //为一级索引块中的二级索引节点分配一个索引块
		log_write(bp);
	}
	brelse(bp);
	bp = bread(ip->dev, addr); 
	a = (uint*)bp->data;		//a指向二级索引块缓冲区数据的起始地址(缓冲区中保存了对应块的内容)
	if((addr = a[bn%NINDIRECT]) == 0){ //查找对应条目对应数据块是否存在,不存在则分配一块
      a[bn%NINDIRECT] = addr = balloc(ip->dev);
      log_write(bp);
    }
	brelse(bp);
	return addr;
  }
	
  panic("bmap: out of range");
}

实现bmap的时候太粗心了,bn/NINDIRECT和bn%NINDIRECT中的NINDIRECT都写成了NDIRECT,程序在写入几个扇区后就一直阻塞,找了好久错误才发现。
测试通过:
在这里插入图片描述

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值