MIT6.828_HW10_Bigger file for xv6
当前 xv6 文件大小限制在 140 个扇区。直接索引节点 12 个, 以及一个一级索引节点,其指向一个 sector,可包含 512/4 = 128个扇区。即总和为12+128 = 140
个扇区。我们需要为xv6的文件节点添加一个二级索引节点,其包含128个一级索引节点的地址,每个一级索引节点又包含了128数据扇区。最终一个文件大小将增加到 16523 个扇区,大约8.5M。
The format of an on-disk inode is defined by struct dinode in fs.h. You’re particularly interested in NDIRECT, NINDIRECT, MAXFILE, and the addrs[] element of struct dinode. xv6 标准 inode 如下图所示。
在读写文件时,会调用 bmap()
(in fs.c)。在写时,bmap 分配存储文件所需的 blocks并且如果需要存储块地址,还会分配一个 indirect block。
bmap() 处理两种页号. The bn argument is a “logical block” – a block number relative to the start of the file. The block numbers in ip->addrs[], and the argument to bread(), are disk block numbers. You can view bmap() as mapping a file’s logical block numbers into disk block numbers.
实现过程
修改 param.h 文件, 将 #define FSSIZE 1000改为
#define FSSIZE 20000
Download big.c into your xv6 directory, add it to the UPROGS list, start up xv6, and run big. It creates as big a file as xv6 will let it, and reports the resulting size. It should say 140 sectors.
做完预处理工作后运行big,应该有以下输出。
$ big
.
wrote 140 sectors
done; ok
You’ll have to have only 11 direct blocks, rather than 12, to make room for your new doubly-indirect block。 之所以这么 arrange, 可以避免我们修改 Inode 结点 addr数组的个数,索引结点总数依然是NDIRECT + 1
。不过后来发现,修改NDIRECT
,程序会更加清晰。即相应需要修改两处
// 1
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
// DOUBLE INDIRECT
#define NDINDIRECT (NINDIRECT * NINDIRECT)
#define MAXFILE (NDIRECT + NINDIRECT + NDINDIRECT)
// 2
// in-memory copy of an inode
struct inode {
...
uint addrs[NDIRECT+ 2];
};
// 3
// On-disk inode structure
struct dinode {
short type; // File type
... // Size of file (bytes)
uint addrs[NDIRECT + 2]; // Data block addresses
};
buf 结构体。
struct buf {
int flags;
uint dev;
uint blockno;
struct sleeplock lock;
uint refcnt;
struct buf *prev; // LRU cache list
struct buf *next;
struct buf *qnext; // disk queue
uchar data[BSIZE];
};
最终实现代码并不难写出,仿照一级索引结点写法使用相应的函数调用。[Note]需要注意 brelse(bp)
的时机。详细过程可以查看注释。
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;
struct buf *bp2;
// 直接索引结点数目 bn= 0~10
if(bn < NDIRECT){
// 创建直接索引
if((addr = ip->addrs[bn]) == 0)
ip->addrs[bn] = addr = balloc(ip->dev);
return addr;
}
bn -= NDIRECT;
// #define NINDIRECT (BSIZE / sizeof(uint)) BSIZE = 512
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 < 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;
if ((addr = a[bn/NINDIRECT]) == 0) {
a[bn/NINDIRECT] = addr = balloc(ip->dev);
log_write(bp);
}
bp2 = bread(ip->dev, addr);
// 二级页表
a = (uint *)bp2->data;
if ((addr = a[bn%NINDIRECT]) == 0) {
a[bn%NINDIRECT] = addr = balloc(ip->dev);
log_write(bp2);
}
brelse(bp2);
brelse(bp);
return addr;
}
panic("bmap: out of range");
}