* 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.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33675 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-10-20 00:29:11 +00:00
parent aeb099b317
commit 3637e0e057
2 changed files with 16 additions and 12 deletions
+14 -11
View File
@@ -1583,12 +1583,13 @@ Inode::FillGapWithZeros(off_t pos, off_t newSize)
*/
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 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
// 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 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
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 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
// 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 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
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 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
// 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);
+2 -1
View File
@@ -220,7 +220,8 @@ private:
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);