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:
parent
f1d9ec9840
commit
a4f9af2a40
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user