diff --git a/UBIXFS.PAS b/UBIXFS.PAS index ee06b74..f8948a9 100755 --- a/UBIXFS.PAS +++ b/UBIXFS.PAS @@ -304,7 +304,6 @@ function isValidIAddr(iAddr:inodeAddr):boolean; function loadBlock(blockAddr:TBlockRun):pointer; - function markUsedBlocks(blockRun:TBlockRun):integer; function nextAG(AG:uInt32):uInt32; function pathToIAddr(path:PChar):inodeAddr; @@ -769,132 +768,6 @@ dispose(FBL, done); end; // TUbixFS.allocBRun -(* -function TUbixFS.allocBRun; -var - FBL:int8ArrayPtr; // Free Block List array pointer - FBLSize:uInt32; // Free Block List array pointer size - bitOffset:uInt32; - byteOffset:uInt32; - curBlock, baseBlock:uInt32; - freeCount:uInt32; -begin - // Notes: - // 2005-04-27 mji - // allocBRun() will allocate a blockRun that is near to the blockRun - // passed into the function. The AG and Start field of blockRun will be - // the starting point of where to look for free blocks. The len field - // holds how many contiguous blocks we need to allocate. - // We look through the BAT (Block Allocation Table) for a contiguous run that - // fits the requested length. The BAT is a bitfield (used blocks are an - // on (1) bit, free blocks are an off (0) bit) of used/unused logical - // blocks, where the logical block size was set when the device was formatted. - // This shouldn't be confused with the sector size on the device, which - // is always 512 bytes. Block sizes are usually 1k, but can be any power - // of 2 higher than that up to 8k. Since we only need to load one AG section - // out of the BAT at a time, we only allocate one block worth of memory. - // The disk is broken up into Allocation Groups, where each allocation group - // bitfield fits into a single block. This means that for a device with 1k - // blocks an AG will be 8192 blocks long. Small devices (such as a floppy) - // will only have 1 AG. - // To find a free run, we load a starting section of the BAT out of the - // BAT file. The BAT is technically another file on the volume, but unlike - // normal files the BAT inode is referenced inside the superblock, and cannot - // be touched by a normal user (if the volume is grown later, the BAT can be - // grown as well). - // Once the AG block list is loaded, we scan through looking for a contiguous - // set of free blocks that fits our length requirement. In the event this - // AG doesn't meet that requirement, we move to the next AG. When we hit the - // end of the volume, we go back to the beginning of the volume and continue - // scanning until either we find a free run or we end up back where we began. - // In the latter case, the disk would have to either be very fragmented or - // full. If we succeed, we mark the blocks as used and return the blockRun. - - // XXX To do: - // Might want to clear the blocks we allocated to avoid garbage from being present - // We also need to ensure that a run doesn't cross an AG. This is because some - // other pieces of code do not take into account the possibility of moving to the - // next AG (or wrapping around completely). This change will have to be - // coupled with a change in extendFile() to ask for decreasing block counts until one - // is found that fits inside an AG. - - setBlockRun(result, 0, 0, 0); - if (superBlock = NIL) then exit; - if (blockRun.AG > superBlock^.numAGs) then exit; - if (superBlock^.usedBlocks + int64(blockRun.len) > superBlock^.numBlocks) then exit; // should probably give a louder warning - - // we read in one block at a time - FBLSize := superBlock^.blockSize; - GetMem(FBL, FBLSize); - assert(FBL <> NIL); - fillchar(FBL^, FBLSize, 0); // better safe than sorry - assert(readDataStream(superBlock^.BAT, (blockRun.AG shl superblock^.AGShift) shr 3, FBL, FBLSize) = 0); - byteOffset := blockRun.start shr 3; - bitOffset := 7-(blockRun.start and 7); - baseBlock := (blockRun.AG shl superBlock^.AGShift) + blockRun.start; - curBlock := baseBlock; - freeCount := 0; - // an optimization would be to check to see if the byte is -1, thus skipping 8 at a time - // This will need to be implemented (but can be later) - repeat - - inc(curBlock); - - if (FBL^[byteOffset] and (1 shl bitOffset) = 0) then - inc(freeCount) - else - freeCount := 0; - - if (freeCount = blockRun.len) then break; // did we meet our length requirement? - - if (bitOffset = 0) then - begin - bitOffset := 7; - inc(byteOffset); - end - else dec(bitOffset); - - if (byteOffset = superBlock^.blockSize) then - begin - // We scanned through one Allocation Group of blocks. Move to the next one - // XXX - // We have a few options for crossing an AG. - // 1) Reset free count to 0. If there's not a run long enough to handle the requested - // blockRun length, throw it back to extendFile() and let it break up the run into smaller chunks - // 2) Return the longest run we've encountered so far. This would make extendFile() loop until - // all the block requests were accomodated. - // 3) Rewrite this function to use some sort of B^Tree in a similar way to how XFS - // does it. (Not for the faint of heart, and might not be possible). - inc(blockRun.AG); - - // it's possible that we're wrapping back around to the beginning. - if (blockRun.AG = superBlock^.numAGs) then - begin - // We hit the end of the volume and wrapped back around - blockRun.AG := 0; // Back to the beginning AG - curBlock := 0; // curBlock is from the base of the volume - freeCount := 0; // reset this to 0 - end; - // read in the FBL for the AG we're currently on - assert(readDataStream(superBlock^.BAT, (blockRun.AG shl superblock^.AGShift) shr 3, FBL, FBLSize) = 0); - byteOffset := 0; // first byte in this block - bitOffset := 7; // first bit of the first byte - end; // if byteOffset = superBlock^.blocksPerAG - - until curBlock = baseBlock; // repeat until we end up back where we started - - if (freeCount = blockRun.len) then // we found a run - begin - blockRun.AG := (curBlock-blockRun.len) shr superBlock^.AGShift; - blockRun.start := (curBlock-blockRun.len) and (superBlock^.blocksPerAG-1); - markUsedBlocks(blockRun); - result := blockRun; - end - else writeln('Failure in allocBRun()'); - FreeMem(FBL, FBLSize); - -end; // TUbixFS.allocBRun -*) function TUbixFS.allocInode; var inode:PUbixfsInode; @@ -1877,66 +1750,7 @@ dispose(FBL, done); result := 0; // success end; // TUbixFS.freeUsedBlocks -(* -function TUbixFS.freeUsedBlocks; -var - FBL:int8ArrayPtr; - FBLSize:uInt32; - startByte, endByte:uInt32; - bitCount, bitOffset:uInt32; - startBlock:uInt32; - byteOffset:uInt32; -begin - // Notes: - // 2005-04-27 mji - // freeUsedBlocks() will clear bits in the BAT that are associated - // with the blockRun passed in. To do this we load only the portion - // of the BAT we're going to modify. (As a side note, readDataStream() - // will load a minimum of one block anyway, so this may not really be - // much of an optimization). - // XXX - // We *might* want to invalidate blocks in the cache that are marked as - // free. So far it seems to work fine without, but that might change. - - result := -1; - // basic sanity checks - if ((superBlock = NIL) or (blockRun.len = 0)) then exit; - -with blockRun do writeln('---- freeing used blocks: ', AG, ':', start, ':', len); - // Compute how much of the BAT we have to read in. - with blockRun, superBlock^ do - begin - startBlock := (AG shl AGShift) + start; - startByte := startBlock shr 3; // divide by 8 since it's a bitfield - endByte := (startBlock + len) shr 3; // divide by 8 since it's a bitfield - FBLSize := endByte - startByte + 1; - - GetMem(FBL, FBLSize); - assert(readDataStream(BAT, startByte, FBL, FBLSize) = 0); - bitOffset := 7-(startBlock and 7); - byteOffset := 0; - - for bitCount := 1 to len do - begin - FBL^[byteOffset] := FBL^[byteOffset] and not (1 shl bitOffset); - if (bitOffset = 0) then - begin - bitOffset := 7; - inc(byteOffset); - end - else dec(bitOffset); - end; // for bitCount - // save back out the modified block - assert(writeDataStream(BAT, startByte, FBL, FBLSize) = 0); - - FreeMem(FBL, FBLSize); - usedBlocks := usedBlocks - len; - end; // with - - result := 0; -end; // TUbixFS.freeUsedBlocks -*) function TUbixFS.getFileSize; begin result := 0; @@ -2049,58 +1863,6 @@ end; end; // TUbixFS.loadBlock -function TUbixFS.markUsedBlocks; -begin -end; // TUbixFS.markUsedBlocks -(* -function TUbixFS.markUsedBlocks; -var - FBL:uInt8ArrayPtr; - FBLSize:uInt32; - startByte, endByte:uInt32; - bitCount, bitOffset:uInt32; - startBlock:uInt32; - byteOffset:uInt32; -begin - - result := -1; - // basic sanity checks - if ((superBlock = NIL) or (blockRun.len = 0)) then exit; - -with blockRun do writeln('---- marking used blocks: ', AG, ':', start, ':', len); - - // Compute how much of the BAT we have to read in. - with blockRun, superBlock^ do - begin - startBlock := (AG shl AGShift) + start; - startByte := startBlock shr 3; - endByte := (startBlock + len) shr 3; - FBLSize := endByte - startByte + 1; - GetMem(FBL, FBLSize); - fillchar(FBL^, FBLSize, 0); // better safe than sorry - assert(readDataStream(BAT, startByte, FBL, FBLSize) = 0); - - bitOffset := 7-(startBlock and 7); - byteOffset := 0; - for bitCount := 1 to len do - begin - FBL^[byteOffset] := FBL^[byteOffset] or (1 shl bitOffset); - if (bitOffset = 0) then - begin - bitOffset := 7; - inc(byteOffset); - end - else dec(bitOffset); - end; // for bitCount - assert(writeDataStream(BAT, startByte, FBL, FBLSize) = 0); - - FreeMem(FBL, FBLSize); - - usedBlocks := usedBlocks + len; - end; // with - result := 0; -end; // TUbixFS.markUsedBlocks -*) function TUbixFS.nextAG; begin // there's no error we can throw from here if superblock is NIL, @@ -3019,48 +2781,7 @@ writeln('remainderBlocks: ', remainderBlocks); assert(remainderblocks = 0); dispose(FBL, done); - (* - // inode still points to the BAT. Clear out the file in case people decided to - // use quick formatting - for i := 0 to (dword(inode^.blocks.size) div sizeof(sector))-1 do - fs^.writeDataStream(sb^.BAT, i*sizeof(sector), @sector, sizeof(sector)); - setBlockRun(blockRun, 0, 0, 1); - fs^.markusedBlocks(blockRun); // mark superBlock block as used - // mark the journal as used here - fs^.markUsedBlocks(sb^.BAT); // mark the BAT inode as used - // now mark the BAT file blocks as used. Note that if the BAT takes up - // more than one blockRun (unlikely, but not impossible) then this code - // will have to check for that. - writeln('BAT inode blocks.direct[0].len: ', inode^.blocks.direct[0].len); - fs^.markUsedBlocks(inode^.blocks.direct[0]); - // If the number of blocksPerAG doesn't divide evenly into the - // number of logical blocks, mark out all the "remainder" blocks - // We need to mark the blocks as used in the BAT manually because - // if we do it through markUsedBlocks() it will change the usedBlocks - // count. - - remainderBlocks := (fsBATBlocks shl sb^.blockShift) - fsBATSize; - writeln('RemainderBlocks: ', remainderBlocks); - if (remainderBlocks <> 0) then - begin - // check if the remainder blocks are evenly divisible by 8 - if (remainderBlocks and 7 <> 0) then - begin - blockBit := uInt8(1 shl (remainderBlocks and 7)) -1; - fs^.writeDataStream(sb^.BAT, fsBatSize, @blockBit, 1); - blockBit := -1; - for i := fsBatSize+1 to (fsBATBlocks shl sb^.blockShift)-1 do - fs^.writeDataStream(sb^.BAT, i, @blockBit, 1); - end - else - begin - blockBit := -1; - for i := fsBatSize to (fsBATBlocks shl sb^.blockShift)-1 do - fs^.writeDataStream(sb^.BAT, i, @blockBit, 1); - end; - end; -*) fs^.vfs_mkdir('/'); if (fs^.vfs_fExist('/.') = -1) then writeln('Warning! /. doesn''t exist') @@ -3549,8 +3270,6 @@ cacheNode:PCacheNode; dirtyCount:integer; u:uPtr; - f:text; - x:integer; begin sync(); // XXX ToDo: @@ -3567,21 +3286,15 @@ begin dirtyCount := 0; fillchar(u, sizeof(u), 0); -system.assign(f, 'bc1.txt'); -system.rewrite(f); while (blockCache^.getFirstKey(searchRec)) do begin cacheNode := searchRec.value.p; -x := integer(cacheNode^.address); - writeln(f, hex(x)); - assert(cacheNode <> NIL); if (cacheNode^.dirty) then inc(dirtyCount); u.p := cacheNode; blockCache^.Delete(@cacheNode^.address, u); dispose(cacheNode, done); end; -system.close(f); if (dirtyCount <> 0) then writeln('Dirty blocks in cache: ', dirtyCount); dispose(blockCache, done); end;