// Ext2BlockCache.cpp // Author: Josh Holtrop // Date: 12/29/05 // Modified: 12/29/05 #include "fs/vfs.h" #include "Ext2BlockCache.h" extern "C" { #include "display/kout.h" } Ext2BlockCache::Ext2BlockCache(Ext2fs *fs, u32_t inum) { myFS = fs; myInum = inum; myInodeDirty = 0; fs->readInode(inum, &myInode); myBlockSize = 1024 << fs->getSuper()->s_log_block_size; for (int i = 0; i < 3; i++) { myCache[i] = new u8_t[myBlockSize]; myCacheAddress[i] = 0; myCacheDirty[i] = 0; } } Ext2BlockCache::~Ext2BlockCache() { for (int i = 0; i < 3; i++) { if (myCacheDirty[i]) myFS->writeBlock(myCacheAddress[i], myCache[i]); delete[] myCache[i]; } if (myInodeDirty) myFS->writeInode(myInum, &myInode); } int Ext2BlockCache::readBlock(u32_t blockNum, void *buf) { u32_t fsblock = getFSBlock(blockNum, 0); if (fsblock == 0) return -1; return myFS->readBlock(fsblock, buf); } int Ext2BlockCache::writeBlock(u32_t blockNum, void *buf) { u32_t fsblock = getFSBlock(blockNum, 1); if (fsblock == 0) return -1; return myFS->writeBlock(fsblock, buf); } void Ext2BlockCache::setCache(u32_t level, u32_t fsblock) { if (myCacheAddress[level] == fsblock) return; if (myCacheDirty[level]) myFS->writeBlock(myCacheAddress[level], myCache[level]); myCacheAddress[level] = fsblock; myCacheDirty[level] = 0; myFS->readBlock(fsblock, myCache[level]); } u32_t Ext2BlockCache::getFSBlock(u32_t blockNum, int create) { if (blockNum < 12) /* direct pointer */ { if (create && myInode.i_block[blockNum] == 0) { myInode.i_block[blockNum] = myFS->allocBlock(); myInodeDirty = 1; } return myInode.i_block[blockNum]; } blockNum -= 12; if (blockNum < myBlockSize) /* i_block[12] */ { if (create && myInode.i_block[12] == 0) { myInode.i_block[12] = myFS->allocBlock(); myInodeDirty = 1; } setCache(0, myInode.i_block[12]); /* blockNum indexes cache 0 */ if (create && myCache[0][blockNum] == 0) { myCache[0][blockNum] = myFS->allocBlock(); myCacheDirty[0] = 1; } return myCache[0][blockNum]; } blockNum -= myBlockSize; if (blockNum < (myBlockSize * myBlockSize)) /* i_block[13] */ { if (create && myInode.i_block[13] == 0) { myInode.i_block[13] = myFS->allocBlock(); myInodeDirty = 1; } setCache(0, myInode.i_block[13]); /* blockNum / myBlockSize indexes cache 0 */ if (create && myCache[0][blockNum / myBlockSize] == 0) { myCache[0][blockNum / myBlockSize] = myFS->allocBlock(); myCacheDirty[0] = 1; } setCache(1, myCache[0][blockNum / myBlockSize]); /* blockNum % myBlockSize indexes cache 1 */ if (create && myCache[1][blockNum % myBlockSize] == 0) { myCache[1][blockNum % myBlockSize] = myFS->allocBlock(); myCacheDirty[1] = 1; } return myCache[1][blockNum % myBlockSize]; } blockNum -= (myBlockSize * myBlockSize); /* i_block[14] */ if (create && myInode.i_block[14] == 0) { myInode.i_block[14] = myFS->allocBlock(); myInodeDirty = 1; } setCache(0, myInode.i_block[14]); /* blockNum / (myBlockSize^2) indexes cache 0 */ if (create && myCache[0][blockNum / (myBlockSize * myBlockSize)] == 0) { myCache[0][blockNum / (myBlockSize * myBlockSize)] = myFS->allocBlock(); myCacheDirty[0] = 1; } setCache(1, myCache[0][blockNum / (myBlockSize * myBlockSize)]); /* blockNum / myBlockSize indexes cache 1 */ if (create && myCache[1][blockNum / myBlockSize] == 0) { myCache[1][blockNum / myBlockSize] = myFS->allocBlock(); myCacheDirty[1] = 1; } setCache(2, myCache[1][blockNum / myBlockSize]); /* blockNum % myBlockSize indexes cache 2 */ if (create && myCache[2][blockNum % myBlockSize] == 0) { myCache[2][blockNum % myBlockSize] = myFS->allocBlock(); myCacheDirty[2] = 1; } return myCache[2][blockNum % myBlockSize]; }