Author: axeld Date: 2009-10-20 02:29:11 +0200 (Tue, 20 Oct 2009) New Revision: 33675 Changeset: http://dev.haiku-os.org/changeset/33675/haiku Modified: haiku/trunk/src/add-ons/kernel/file_systems/bfs/Inode.cpp haiku/trunk/src/add-ons/kernel/file_systems/bfs/Inode.h Log: * Fixed double indirect ranges again: I've messed them up when I tried to make them more BeOS compatible while still keeping them somewhat flexible. * _GrowStream() did actually not check if the double indirect region was already filled up - this caused it to overwrite innocent memory. This fixes the bug Rudolf showed me on this laptop that happened while copying a large file. * Loosened file size restriction on a heavy fragmented disk: the indirect block does not require a minimum array size anymore; before, you just couldn't let a stream grow into the indirect range if it couldn't allocate NUM_ARRAY_BLOCKS (4) blocks in a row. This considerably reduced the maximum file size in this case. * Removed no longer valid TODO. Modified: haiku/trunk/src/add-ons/kernel/file_systems/bfs/Inode.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/bfs/Inode.cpp 2009-10-20 00:23:53 UTC (rev 33674) +++ haiku/trunk/src/add-ons/kernel/file_systems/bfs/Inode.cpp 2009-10-20 00:29:11 UTC (rev 33675) @@ -1583,12 +1583,13 @@ */ status_t Inode::_AllocateBlockArray(Transaction& transaction, block_run& run, - size_t length) + size_t length, bool variableSize) { if (!run.IsZero()) return B_BAD_VALUE; - status_t status = fVolume->Allocate(transaction, this, length, run, length); + status_t status = fVolume->Allocate(transaction, this, length, run, + variableSize ? 1 : length); if (status != B_OK) return status; @@ -1708,9 +1709,6 @@ // okay, we have the needed blocks, so just distribute them to the // different ranges of the stream (direct, indirect & double indirect) - // TODO: if anything goes wrong here, we probably want to free the - // blocks that couldn't be distributed into the stream! - blocksNeeded -= run.Length(); // don't preallocate if the first allocation was already too small blocksRequested = blocksNeeded; @@ -1720,9 +1718,10 @@ if (data->Size() <= data->MaxDirectRange()) { // let's try to put them into the direct block range int32 free = 0; - for (; free < NUM_DIRECT_BLOCKS; free++) + for (; free < NUM_DIRECT_BLOCKS; free++) { if (data->direct[free].IsZero()) break; + } if (free < NUM_DIRECT_BLOCKS) { // can we merge the last allocated run with the new one? @@ -1754,7 +1753,7 @@ // if there is no indirect block yet, create one if (data->indirect.IsZero()) { status = _AllocateBlockArray(transaction, data->indirect, - NUM_ARRAY_BLOCKS); + NUM_ARRAY_BLOCKS, true); if (status != B_OK) return status; @@ -1875,8 +1874,12 @@ while (run.length != 0) { // get the indirect array block if (array == NULL) { + uint32 block = indirectIndex / runsPerBlock; + if (block >= minimum) + return EFBIG; + array = (block_run*)cached.SetTo(fVolume->ToBlock( - data->double_indirect) + indirectIndex / runsPerBlock); + data->double_indirect) + block); if (array == NULL) return B_IO_ERROR; } @@ -1903,13 +1906,13 @@ // insert the block_run into the array runs[index % runsPerBlock] = run; runs[index % runsPerBlock].length - = HOST_ENDIAN_TO_BFS_INT16(NUM_ARRAY_BLOCKS); + = HOST_ENDIAN_TO_BFS_INT16(minimum); // alter the remaining block_run run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() - + NUM_ARRAY_BLOCKS); + + minimum); run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - - NUM_ARRAY_BLOCKS); + - minimum); } while ((++index % runsPerBlock) != 0 && run.length); } while ((index % runsPerArray) != 0 && run.length); Modified: haiku/trunk/src/add-ons/kernel/file_systems/bfs/Inode.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/bfs/Inode.h 2009-10-20 00:23:53 UTC (rev 33674) +++ haiku/trunk/src/add-ons/kernel/file_systems/bfs/Inode.h 2009-10-20 00:29:11 UTC (rev 33675) @@ -220,7 +220,8 @@ block_run* array, uint32 arrayLength, off_t size, off_t& offset, off_t& max); status_t _AllocateBlockArray(Transaction& transaction, - block_run& run, size_t length); + block_run& run, size_t length, + bool variableSize = false); status_t _GrowStream(Transaction& transaction, off_t size); status_t _ShrinkStream(Transaction& transaction, off_t size);