Fixed a number of issues with double indirect blocks:

* The "index" was not correctly updated when the next indirect block was about
  to be used, which lead the code to write the runs to a wrong block, causing
  slight corruption, as well as the known invalid block_run(0,0,0) problem.
* blocksRequested is now always a multiple of "minimum" as well.
* When the file size grew beyond the max_double_indirect_range, the minimum was
  not adjusted, leading to too many extra allocations that had to be reverted
  afterwards again.
* If an allocation was not a multiple of NUM_ARRAY_BLOCKS, but also smaller than
  this limit (could happen due to the bug above), an endless loop could be
  entered. This was actually a regression introduced in r974.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31767 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-07-26 13:28:43 +00:00
parent f1d9ec9840
commit a4f9af2a40

View File

@ -1633,8 +1633,12 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
bytes = size - data->MaxIndirectRange();
else if (data->Size() < data->MaxDirectRange())
bytes = size - data->MaxDirectRange();
else
else {
// no preallocation left to be used
bytes = size - data->Size();
if (data->MaxDoubleIndirectRange() > 0)
minimum = NUM_ARRAY_BLOCKS;
}
// do we have enough free blocks on the disk?
off_t blocksNeeded = (bytes + fVolume->BlockSize() - 1)
@ -1687,10 +1691,15 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
// the requested blocks do not need to be returned with a
// single allocation, so we need to iterate until we have
// enough blocks allocated
if (minimum > 1) {
// make sure that "blocks" is a multiple of minimum
blocksRequested = round_up(blocksRequested, minimum);
}
block_run run;
status_t status = fVolume->Allocate(transaction, this, blocksRequested,
run, minimum);
if (status < B_OK)
if (status != B_OK)
return status;
// okay, we have the needed blocks, so just distribute them to the
@ -1702,10 +1711,6 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
blocksNeeded -= run.Length();
// don't preallocate if the first allocation was already too small
blocksRequested = blocksNeeded;
if (minimum > 1) {
// make sure that "blocks" is a multiple of minimum
blocksRequested = round_up(blocksRequested, minimum);
}
// Direct block range
@ -1746,7 +1751,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);
if (status < B_OK)
if (status != B_OK)
return status;
data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64(
@ -1800,7 +1805,7 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
if (data->Size() <= data->MaxDoubleIndirectRange()
|| !data->max_double_indirect_range) {
while ((run.Length() % NUM_ARRAY_BLOCKS) != 0) {
if ((run.Length() % NUM_ARRAY_BLOCKS) != 0) {
// The number of allocated blocks isn't a multiple of
// NUM_ARRAY_BLOCKS, so we have to change this. This can happen
// the first time the stream grows into the double
@ -1813,7 +1818,7 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
status = fVolume->Free(transaction,
block_run::Run(run.AllocationGroup(),
run.Start() + run.Length(), rest));
if (status < B_OK)
if (status != B_OK)
return status;
blocksNeeded += rest;
@ -1833,7 +1838,7 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
if (data->double_indirect.IsZero()) {
status = _AllocateBlockArray(transaction,
data->double_indirect);
if (status < B_OK)
if (status != B_OK)
return status;
data->max_double_indirect_range = data->max_indirect_range;
@ -1876,7 +1881,7 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
status = _AllocateBlockArray(transaction,
array[indirectIndex % runsPerBlock]);
if (status < B_OK)
if (status != B_OK)
return status;
}
@ -1900,6 +1905,8 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
} while ((++index % runsPerBlock) != 0 && run.length);
} while ((index % runsPerArray) != 0 && run.length);
if (index == runsPerArray)
index = 0;
if (++indirectIndex % runsPerBlock == 0) {
array = NULL;
index = 0;