bfs: Factor the code to add a block_run to a data_stream out of _GrowStream()
This is done so the code can be reused when moving the file stream. Change-Id: I4c31c14492904cf8d490ec3720450e3b54f00cbf Reviewed-on: https://review.haiku-os.org/c/haiku/+/927 Tested-by: Commit checker robot <[email protected]> Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
Axel Dörfler
parent
e93c2b5609
commit
f6829b6ccf
@@ -1715,6 +1715,254 @@ Inode::_AllocateBlockArray(Transaction& transaction, block_run& run,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Adds \a run to \a data, allocating indirection blocks if necessary.
|
||||||
|
If the block run cannot be added as is, due to constraints on block run
|
||||||
|
size in the double indirect range, \a rest is set to the number of blocks
|
||||||
|
that need to be shaved off the run and the function returns.
|
||||||
|
|
||||||
|
If the physical stream size ends up larger than \a targetSize, the stream
|
||||||
|
size is set to the target file size.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
Inode::_AddBlockRun(Transaction& transaction, data_stream* data, block_run run,
|
||||||
|
off_t targetSize, int32* rest, off_t beginBlock, off_t endBlock)
|
||||||
|
{
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
if (rest)
|
||||||
|
*rest = 0;
|
||||||
|
|
||||||
|
bool cutSize = targetSize < data->Size()
|
||||||
|
+ (run.Length() << fVolume->BlockShift());
|
||||||
|
// if adding this block_run means overshooting the target stream size,
|
||||||
|
// we need to set data->size to targetSize.
|
||||||
|
|
||||||
|
// Direct block range
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
if (data->direct[free].IsZero())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (free < NUM_DIRECT_BLOCKS) {
|
||||||
|
// can we merge the last allocated run with the new one?
|
||||||
|
int32 last = free - 1;
|
||||||
|
if (free > 0 && data->direct[last].MergeableWith(run)) {
|
||||||
|
data->direct[last].length = HOST_ENDIAN_TO_BFS_INT16(
|
||||||
|
data->direct[last].Length() + run.Length());
|
||||||
|
} else
|
||||||
|
data->direct[free] = run;
|
||||||
|
|
||||||
|
data->max_direct_range = HOST_ENDIAN_TO_BFS_INT64(
|
||||||
|
data->MaxDirectRange()
|
||||||
|
+ run.Length() * fVolume->BlockSize());
|
||||||
|
data->size = cutSize ? HOST_ENDIAN_TO_BFS_INT64(targetSize)
|
||||||
|
: data->max_direct_range;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indirect block range
|
||||||
|
|
||||||
|
if (data->Size() <= data->MaxIndirectRange()
|
||||||
|
|| !data->MaxIndirectRange()) {
|
||||||
|
CachedBlock cached(fVolume);
|
||||||
|
block_run* runs = NULL;
|
||||||
|
uint32 free = 0;
|
||||||
|
off_t block;
|
||||||
|
|
||||||
|
// if there is no indirect block yet, create one
|
||||||
|
if (data->indirect.IsZero()) {
|
||||||
|
status = _AllocateBlockArray(transaction, data->indirect,
|
||||||
|
NUM_ARRAY_BLOCKS, true);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
data->max_indirect_range = data->max_direct_range;
|
||||||
|
// insert the block_run in the first block
|
||||||
|
status = cached.SetTo(data->indirect);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
runs = (block_run*)cached.Block();
|
||||||
|
} else {
|
||||||
|
uint32 numberOfRuns = fVolume->BlockSize() / sizeof(block_run);
|
||||||
|
block = fVolume->ToBlock(data->indirect);
|
||||||
|
|
||||||
|
// search first empty entry
|
||||||
|
int32 i = 0;
|
||||||
|
for (; i < data->indirect.Length(); i++) {
|
||||||
|
status = cached.SetTo(block + i);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
runs = (block_run*)cached.Block();
|
||||||
|
for (free = 0; free < numberOfRuns; free++)
|
||||||
|
if (runs[free].IsZero())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (free < numberOfRuns)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == data->indirect.Length())
|
||||||
|
runs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runs != NULL) {
|
||||||
|
// try to insert the run to the last one - note that this
|
||||||
|
// doesn't take block borders into account, so it could be
|
||||||
|
// further optimized
|
||||||
|
cached.MakeWritable(transaction);
|
||||||
|
|
||||||
|
int32 last = free - 1;
|
||||||
|
if (free > 0 && runs[last].MergeableWith(run)) {
|
||||||
|
runs[last].length = HOST_ENDIAN_TO_BFS_INT16(
|
||||||
|
runs[last].Length() + run.Length());
|
||||||
|
} else
|
||||||
|
runs[free] = run;
|
||||||
|
|
||||||
|
data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64(
|
||||||
|
data->MaxIndirectRange()
|
||||||
|
+ (run.Length() << fVolume->BlockShift()));
|
||||||
|
data->size = cutSize ? HOST_ENDIAN_TO_BFS_INT64(targetSize)
|
||||||
|
: data->max_indirect_range;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double indirect block range
|
||||||
|
|
||||||
|
if (data->Size() <= data->MaxDoubleIndirectRange()
|
||||||
|
|| !data->max_double_indirect_range) {
|
||||||
|
// We make sure here that we have this minimum allocated, so if
|
||||||
|
// the allocation succeeds, we don't run into an endless loop.
|
||||||
|
uint16 doubleIndirectBlockLength;
|
||||||
|
if (!data->max_double_indirect_range)
|
||||||
|
doubleIndirectBlockLength = _DoubleIndirectBlockLength();
|
||||||
|
else
|
||||||
|
doubleIndirectBlockLength = data->double_indirect.Length();
|
||||||
|
|
||||||
|
if ((run.Length() % doubleIndirectBlockLength) != 0) {
|
||||||
|
// The number of allocated blocks isn't a multiple of
|
||||||
|
// 'doubleIndirectBlockLength', so we return and let the caller
|
||||||
|
// change this. This can happen the first time the stream grows
|
||||||
|
// into the double indirect range.
|
||||||
|
if (rest) {
|
||||||
|
*rest = run.Length() % doubleIndirectBlockLength;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the caller didn't expect rest
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is no double indirect block yet, create one
|
||||||
|
if (data->double_indirect.IsZero()) {
|
||||||
|
status = _AllocateBlockArray(transaction,
|
||||||
|
data->double_indirect, _DoubleIndirectBlockLength());
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
data->max_double_indirect_range = data->max_indirect_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the index where to insert the new blocks
|
||||||
|
|
||||||
|
int32 runsPerBlock;
|
||||||
|
int32 directSize;
|
||||||
|
int32 indirectSize;
|
||||||
|
get_double_indirect_sizes(data->double_indirect.Length(),
|
||||||
|
fVolume->BlockSize(), runsPerBlock, directSize, indirectSize);
|
||||||
|
if (directSize <= 0 || indirectSize <= 0)
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
off_t start = data->MaxDoubleIndirectRange()
|
||||||
|
- data->MaxIndirectRange();
|
||||||
|
int32 indirectIndex = start / indirectSize;
|
||||||
|
int32 index = (start % indirectSize) / directSize;
|
||||||
|
int32 runsPerArray = runsPerBlock * doubleIndirectBlockLength;
|
||||||
|
|
||||||
|
// distribute the blocks to the array and allocate
|
||||||
|
// new array blocks when needed
|
||||||
|
|
||||||
|
CachedBlock cached(fVolume);
|
||||||
|
CachedBlock cachedDirect(fVolume);
|
||||||
|
block_run* array = NULL;
|
||||||
|
uint32 runLength = run.Length();
|
||||||
|
|
||||||
|
while (run.length != 0) {
|
||||||
|
// get the indirect array block
|
||||||
|
if (array == NULL) {
|
||||||
|
uint32 block = indirectIndex / runsPerBlock;
|
||||||
|
if (block >= doubleIndirectBlockLength)
|
||||||
|
return EFBIG;
|
||||||
|
|
||||||
|
status = cached.SetTo(fVolume->ToBlock(
|
||||||
|
data->double_indirect) + block);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
array = (block_run*)cached.Block();
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
// do we need a new array block?
|
||||||
|
if (array[indirectIndex % runsPerBlock].IsZero()) {
|
||||||
|
cached.MakeWritable(transaction);
|
||||||
|
|
||||||
|
status = _AllocateBlockArray(transaction,
|
||||||
|
array[indirectIndex % runsPerBlock],
|
||||||
|
data->double_indirect.Length());
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = cachedDirect.SetToWritable(transaction,
|
||||||
|
fVolume->ToBlock(array[indirectIndex
|
||||||
|
% runsPerBlock]) + index / runsPerBlock);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
block_run* runs = (block_run*)cachedDirect.Block();
|
||||||
|
|
||||||
|
do {
|
||||||
|
// insert the block_run into the array
|
||||||
|
runs[index % runsPerBlock] = run;
|
||||||
|
runs[index % runsPerBlock].length
|
||||||
|
= HOST_ENDIAN_TO_BFS_INT16(doubleIndirectBlockLength);
|
||||||
|
|
||||||
|
// alter the remaining block_run
|
||||||
|
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start()
|
||||||
|
+ doubleIndirectBlockLength);
|
||||||
|
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length()
|
||||||
|
- doubleIndirectBlockLength);
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->max_double_indirect_range = HOST_ENDIAN_TO_BFS_INT64(
|
||||||
|
data->MaxDoubleIndirectRange()
|
||||||
|
+ (runLength << fVolume->BlockShift()));
|
||||||
|
data->size = cutSize ? HOST_ENDIAN_TO_BFS_INT64(targetSize)
|
||||||
|
: data->max_double_indirect_range;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_ERROR(EFBIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Grows the stream to \a size, and fills the direct/indirect/double indirect
|
/*! Grows the stream to \a size, and fills the direct/indirect/double indirect
|
||||||
ranges with the runs.
|
ranges with the runs.
|
||||||
This method will also determine the size of the preallocation, if any.
|
This method will also determine the size of the preallocation, if any.
|
||||||
@@ -1803,6 +2051,12 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
|
|||||||
// the requested blocks do not need to be returned with a
|
// the requested blocks do not need to be returned with a
|
||||||
// single allocation, so we need to iterate until we have
|
// single allocation, so we need to iterate until we have
|
||||||
// enough blocks allocated
|
// enough blocks allocated
|
||||||
|
|
||||||
|
// If data has a double_indirect block, we're adding block_run:s to
|
||||||
|
// the double indirect range.
|
||||||
|
if (!data->double_indirect.IsZero())
|
||||||
|
minimum = data->double_indirect.Length();
|
||||||
|
|
||||||
if (minimum > 1) {
|
if (minimum > 1) {
|
||||||
// make sure that "blocks" is a multiple of minimum
|
// make sure that "blocks" is a multiple of minimum
|
||||||
blocksRequested = round_up(blocksRequested, minimum);
|
blocksRequested = round_up(blocksRequested, minimum);
|
||||||
@@ -1821,239 +2075,34 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
|
|||||||
// don't preallocate if the first allocation was already too small
|
// don't preallocate if the first allocation was already too small
|
||||||
blocksRequested = blocksNeeded;
|
blocksRequested = blocksNeeded;
|
||||||
|
|
||||||
// Direct block range
|
int32 rest;
|
||||||
|
status = _AddBlockRun(transaction, data, run, size, &rest);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
if (data->Size() <= data->MaxDirectRange()) {
|
if (rest != 0) {
|
||||||
// let's try to put them into the direct block range
|
// We've entered the double indirect range, and the number of
|
||||||
int32 free = 0;
|
// allocated blocks isn't a multiple of 'doubleIndirectBlockLength'
|
||||||
for (; free < NUM_DIRECT_BLOCKS; free++) {
|
|
||||||
if (data->direct[free].IsZero())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (free < NUM_DIRECT_BLOCKS) {
|
minimum = _DoubleIndirectBlockLength();
|
||||||
// can we merge the last allocated run with the new one?
|
|
||||||
int32 last = free - 1;
|
|
||||||
if (free > 0 && data->direct[last].MergeableWith(run)) {
|
|
||||||
data->direct[last].length = HOST_ENDIAN_TO_BFS_INT16(
|
|
||||||
data->direct[last].Length() + run.Length());
|
|
||||||
} else
|
|
||||||
data->direct[free] = run;
|
|
||||||
|
|
||||||
data->max_direct_range = HOST_ENDIAN_TO_BFS_INT64(
|
// Free the remaining blocks that don't fit into this multiple.
|
||||||
data->MaxDirectRange()
|
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - rest);
|
||||||
+ run.Length() * fVolume->BlockSize());
|
|
||||||
data->size = HOST_ENDIAN_TO_BFS_INT64(blocksNeeded > 0
|
status = fVolume->Free(transaction,
|
||||||
? data->max_direct_range : size);
|
block_run::Run(run.AllocationGroup(),
|
||||||
|
run.Start() + run.Length(), rest));
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
blocksNeeded += rest;
|
||||||
|
blocksRequested = round_up(blocksNeeded, minimum);
|
||||||
|
|
||||||
|
// Are there any blocks left in the run? If not, allocate
|
||||||
|
// a new one
|
||||||
|
if (run.length == 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indirect block range
|
|
||||||
|
|
||||||
if (data->Size() <= data->MaxIndirectRange()
|
|
||||||
|| !data->MaxIndirectRange()) {
|
|
||||||
CachedBlock cached(fVolume);
|
|
||||||
block_run* runs = NULL;
|
|
||||||
uint32 free = 0;
|
|
||||||
off_t block;
|
|
||||||
|
|
||||||
// if there is no indirect block yet, create one
|
|
||||||
if (data->indirect.IsZero()) {
|
|
||||||
status = _AllocateBlockArray(transaction, data->indirect,
|
|
||||||
NUM_ARRAY_BLOCKS, true);
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64(
|
|
||||||
data->MaxDirectRange());
|
|
||||||
// insert the block_run in the first block
|
|
||||||
status = cached.SetTo(data->indirect);
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
runs = (block_run*)cached.Block();
|
|
||||||
} else {
|
|
||||||
uint32 numberOfRuns = fVolume->BlockSize() / sizeof(block_run);
|
|
||||||
block = fVolume->ToBlock(data->indirect);
|
|
||||||
|
|
||||||
// search first empty entry
|
|
||||||
int32 i = 0;
|
|
||||||
for (; i < data->indirect.Length(); i++) {
|
|
||||||
status = cached.SetTo(block + i);
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
runs = (block_run*)cached.Block();
|
|
||||||
for (free = 0; free < numberOfRuns; free++)
|
|
||||||
if (runs[free].IsZero())
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (free < numberOfRuns)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i == data->indirect.Length())
|
|
||||||
runs = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runs != NULL) {
|
|
||||||
// try to insert the run to the last one - note that this
|
|
||||||
// doesn't take block borders into account, so it could be
|
|
||||||
// further optimized
|
|
||||||
cached.MakeWritable(transaction);
|
|
||||||
|
|
||||||
int32 last = free - 1;
|
|
||||||
if (free > 0 && runs[last].MergeableWith(run)) {
|
|
||||||
runs[last].length = HOST_ENDIAN_TO_BFS_INT16(
|
|
||||||
runs[last].Length() + run.Length());
|
|
||||||
} else
|
|
||||||
runs[free] = run;
|
|
||||||
|
|
||||||
data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64(
|
|
||||||
data->MaxIndirectRange()
|
|
||||||
+ ((uint32)run.Length() << fVolume->BlockShift()));
|
|
||||||
data->size = HOST_ENDIAN_TO_BFS_INT64(blocksNeeded > 0
|
|
||||||
? data->MaxIndirectRange() : size);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Double indirect block range
|
|
||||||
|
|
||||||
if (data->Size() <= data->MaxDoubleIndirectRange()
|
|
||||||
|| !data->max_double_indirect_range) {
|
|
||||||
// We make sure here that we have this minimum allocated, so if
|
|
||||||
// the allocation succeeds, we don't run into an endless loop.
|
|
||||||
if (!data->max_double_indirect_range)
|
|
||||||
minimum = _DoubleIndirectBlockLength();
|
|
||||||
else
|
|
||||||
minimum = data->double_indirect.Length();
|
|
||||||
|
|
||||||
if ((run.Length() % minimum) != 0) {
|
|
||||||
// The number of allocated blocks isn't a multiple of 'minimum',
|
|
||||||
// so we have to change this. This can happen the first time the
|
|
||||||
// stream grows into the double indirect range.
|
|
||||||
// First, free the remaining blocks that don't fit into this
|
|
||||||
// multiple.
|
|
||||||
int32 rest = run.Length() % minimum;
|
|
||||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - rest);
|
|
||||||
|
|
||||||
status = fVolume->Free(transaction,
|
|
||||||
block_run::Run(run.AllocationGroup(),
|
|
||||||
run.Start() + run.Length(), rest));
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
blocksNeeded += rest;
|
|
||||||
blocksRequested = round_up(blocksNeeded, minimum);
|
|
||||||
|
|
||||||
// Are there any blocks left in the run? If not, allocate
|
|
||||||
// a new one
|
|
||||||
if (run.length == 0)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is no double indirect block yet, create one
|
|
||||||
if (data->double_indirect.IsZero()) {
|
|
||||||
status = _AllocateBlockArray(transaction,
|
|
||||||
data->double_indirect, _DoubleIndirectBlockLength());
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
data->max_double_indirect_range = data->max_indirect_range;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate the index where to insert the new blocks
|
|
||||||
|
|
||||||
int32 runsPerBlock;
|
|
||||||
int32 directSize;
|
|
||||||
int32 indirectSize;
|
|
||||||
get_double_indirect_sizes(data->double_indirect.Length(),
|
|
||||||
fVolume->BlockSize(), runsPerBlock, directSize, indirectSize);
|
|
||||||
if (directSize <= 0 || indirectSize <= 0)
|
|
||||||
return B_BAD_DATA;
|
|
||||||
|
|
||||||
off_t start = data->MaxDoubleIndirectRange()
|
|
||||||
- data->MaxIndirectRange();
|
|
||||||
int32 indirectIndex = start / indirectSize;
|
|
||||||
int32 index = (start % indirectSize) / directSize;
|
|
||||||
int32 runsPerArray = runsPerBlock * minimum;
|
|
||||||
|
|
||||||
// distribute the blocks to the array and allocate
|
|
||||||
// new array blocks when needed
|
|
||||||
|
|
||||||
CachedBlock cached(fVolume);
|
|
||||||
CachedBlock cachedDirect(fVolume);
|
|
||||||
block_run* array = NULL;
|
|
||||||
uint32 runLength = run.Length();
|
|
||||||
|
|
||||||
while (run.length != 0) {
|
|
||||||
// get the indirect array block
|
|
||||||
if (array == NULL) {
|
|
||||||
uint32 block = indirectIndex / runsPerBlock;
|
|
||||||
if (block >= minimum)
|
|
||||||
return EFBIG;
|
|
||||||
|
|
||||||
status = cached.SetTo(fVolume->ToBlock(
|
|
||||||
data->double_indirect) + block);
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
array = (block_run*)cached.Block();
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
// do we need a new array block?
|
|
||||||
if (array[indirectIndex % runsPerBlock].IsZero()) {
|
|
||||||
cached.MakeWritable(transaction);
|
|
||||||
|
|
||||||
status = _AllocateBlockArray(transaction,
|
|
||||||
array[indirectIndex % runsPerBlock],
|
|
||||||
data->double_indirect.Length());
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = cachedDirect.SetToWritable(transaction,
|
|
||||||
fVolume->ToBlock(array[indirectIndex
|
|
||||||
% runsPerBlock]) + index / runsPerBlock);
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
block_run* runs = (block_run*)cachedDirect.Block();
|
|
||||||
|
|
||||||
do {
|
|
||||||
// insert the block_run into the array
|
|
||||||
runs[index % runsPerBlock] = run;
|
|
||||||
runs[index % runsPerBlock].length
|
|
||||||
= HOST_ENDIAN_TO_BFS_INT16(minimum);
|
|
||||||
|
|
||||||
// alter the remaining block_run
|
|
||||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start()
|
|
||||||
+ minimum);
|
|
||||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length()
|
|
||||||
- minimum);
|
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data->max_double_indirect_range = HOST_ENDIAN_TO_BFS_INT64(
|
|
||||||
data->MaxDoubleIndirectRange()
|
|
||||||
+ (runLength << fVolume->BlockShift()));
|
|
||||||
data->size = blocksNeeded > 0 ? HOST_ENDIAN_TO_BFS_INT64(
|
|
||||||
data->max_double_indirect_range) : size;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_ERROR(EFBIG);
|
|
||||||
}
|
}
|
||||||
// update the size of the data stream
|
// update the size of the data stream
|
||||||
data->size = HOST_ENDIAN_TO_BFS_INT64(size);
|
data->size = HOST_ENDIAN_TO_BFS_INT64(size);
|
||||||
|
|||||||
@@ -256,6 +256,10 @@ private:
|
|||||||
off_t size);
|
off_t size);
|
||||||
status_t _ShrinkStream(Transaction& transaction,
|
status_t _ShrinkStream(Transaction& transaction,
|
||||||
off_t size);
|
off_t size);
|
||||||
|
status_t _AddBlockRun(Transaction& transaction,
|
||||||
|
data_stream* data, block_run run,
|
||||||
|
off_t targetSize, int32* rest = NULL,
|
||||||
|
off_t beginBlock = 0, off_t endBlock = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rw_lock fLock;
|
rw_lock fLock;
|
||||||
|
|||||||
Reference in New Issue
Block a user