file system 的 Optional challenge 比較簡(jiǎn)單
前面的題解可以參考這篇博客: https://blog.csdn.net/LostUnravel/article/details/121431163
Support triple-indirect blocks.
首先這部分的代碼 其實(shí)和原要求中的第一題非常類似。只是要額外實(shí)現(xiàn)1層,這樣就可以支持更大的文件。
理論上最大可以支持256*256*256+256*256+256+10 個(gè)block, 一個(gè)block 是1KB的情況下,那么可以支持16.8G的文件。
遠(yuǎn)遠(yuǎn)超過(guò)了這個(gè)LAB文件系統(tǒng)的總?cè)萘俊?br>
根據(jù)param.h, 我們可以發(fā)現(xiàn)我們的文件系統(tǒng)是在200MB的大小。
#ifdef LAB_FS
#define FSSIZE 200000 // size of file system in blocks
#else
那么其實(shí)支持了3層的結(jié)構(gòu),其實(shí)第3層頁(yè)只要使用前2個(gè)條目即可。(256 * 256 * 3 < 200 MB)
為了讓代碼更加簡(jiǎn)潔,來(lái)讓我們更容易的拓展到3層。我做了如下改動(dòng):

那么當(dāng)我們需要變?yōu)?層的時(shí)候,我們只要更改
#define INDIR_LAYERS 2這個(gè)變量即可,當(dāng)然要更改MAXFILE的大小去看到效果。
下面變更bmap 和 itrunc 為遞歸寫法,來(lái)避免復(fù)制黏貼 重復(fù)的代碼邏輯。
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;
if(bn < NDIRECT){
if((addr = ip->addrs[bn]) == 0){
addr = balloc(ip->dev);
if(addr == 0)
return 0;
ip->addrs[bn] = addr;
}
return addr;
}
bn -= NDIRECT;
uint prev_base = 1;
for (int in_layer = 0, base = NINDIRECT; in_layer < INDIR_LAYERS; in_layer++, base *= NINDIRECT) {
if (bn < base) {
uint idx = NDIRECT + in_layer;
if((addr = ip->addrs[idx]) == 0){
if ((ip->addrs[idx] = addr = balloc(ip->dev)) == 0)
return 0;
}
for (int j = 0; j <= in_layer; j++, bn %= prev_base, prev_base /= NINDIRECT) {
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
idx = bn / prev_base;
if((addr = a[idx]) == 0){
if((addr = balloc(ip->dev))){
a[idx] = addr;
log_write(bp);
}
}
brelse(bp);
}
return addr;
}
bn -= base;
prev_base = base;
}
panic("bmap: out of range");
}
// Truncate inode (discard contents).
// Caller must hold ip->lock.
void
turnc_recur(uint dev, uint *addr, int layer)
{
struct buf *bp;
uint *a;
bp = bread(dev, *addr);
a = (uint*)bp->data;
int last_layer = (layer == 0);
for(int j = 0; j < NINDIRECT; j++){
if(!a[j]) continue;
if (!last_layer) turnc_recur(dev, &a[j], layer - 1);
else bfree(dev, a[j]);
}
brelse(bp);
bfree(dev, *addr);
*addr = 0;
}
void
itrunc(struct inode *ip)
{
for(int i = 0; i < NDIRECT; i++){
if(ip->addrs[i]){
bfree(ip->dev, ip->addrs[i]);
ip->addrs[i] = 0;
}
}
for (int in_layer = 0, base = NINDIRECT; in_layer < INDIR_LAYERS; in_layer++, base *= NINDIRECT) {
int idx = NDIRECT + in_layer;
if(ip->addrs[idx]){
turnc_recur(ip->dev, &ip->addrs[idx], in_layer);
}
}
ip->size = 0;
iupdate(ip);
}
到這里,我們進(jìn)行測(cè)試,確保LAB 9的用例 依然可以通過(guò)。

下面,我們只需要做一些小改動(dòng),就可以支持triple-indirect blocks.

下面進(jìn)行usertests -q測(cè)試,
我們會(huì)發(fā)現(xiàn)在test writebig:時(shí)會(huì)報(bào) panic: bget: no buffers
原因是因?yàn)槲覀冞@邊單個(gè)文件SIZE達(dá)到200MB,那么這里會(huì)用到valid bit的block 數(shù)為 (200000 / 8096) = 25
也就是這些block, 都會(huì)在bfree的時(shí)候 調(diào)用logwrite 寫進(jìn)log里,但是我們這里是1個(gè)unlock的txn, 所以這些LOG,會(huì)被bpin,這樣就造成這些block bit map 位置在45-69,25個(gè)完全被保留在bcache里
32 (root dir inode)
45 (bit map)
70 (root dir content)
33 (bigfile inode)
46 (bit map)
47 (bit map)
48 (bit map)
49 (bit map)
50 (bit map)
51 (bit map)
52 (bit map)
53 (bit map)
66910 (1st indirect block)
54 (bit map)
55 (bit map)
56 (bit map)
57 (bit map)
58 (bit map)
59 (bit map)
60 (bit map)
61 (bit map)
132704 (2rd indirect block)
62 (bit map)
63 (bit map)
64 (bit map)
65 (bit map)
66 (bit map)
67 (bit map)
68 (bit map)
196441 (3rd direct block)
alloc: 69 (bit map)
根據(jù)上述發(fā)現(xiàn),我們需要把log size 和 buf size 分別調(diào)大1.應(yīng)該就可以跑過(guò)測(cè)試。
#define LOGSIZE 31 // max data blocks in on-disk log
#define NBUF 31 // size of disk block cache
改大1格后測(cè)試順利通過(guò)?;谏鲜銮闆r,正確的做法是要把MAXOPBLOCKS改大

綜上,我們?cè)倥芤淮?code>usertests
