added 4 changesets to branch 'refs/remotes/ahenriksson-github/production' old head: 62e1c717aeab270bf368387c0f768e6e43b1bfc1 new head: debc1307496dc87e1ec14c6bb0630e6d58f852b2 ---------------------------------------------------------------------------- 6498e87: Tweaks to stream moving code 5b66a74: Explain why we can't use Replace in Index::UpdateInode (duplicates) 5b70193: Don't use 'data' as a data_stream name unless it refers to the Inode stream debc130: Logic error in _WriteBufferedRuns() that was hidden by the big buffer [ ahenriksson <sausageboy@xxxxxxxxx> ] ---------------------------------------------------------------------------- 3 files changed, 153 insertions(+), 136 deletions(-) src/add-ons/kernel/file_systems/bfs/Index.cpp | 4 +- src/add-ons/kernel/file_systems/bfs/Inode.cpp | 267 +++++++++++---------- src/add-ons/kernel/file_systems/bfs/Inode.h | 18 +- ############################################################################ Commit: 6498e8701c8e6cdf5abc9c4759c5d44587fa6758 Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Mon Jul 2 14:29:56 2012 UTC Tweaks to stream moving code ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.cpp b/src/add-ons/kernel/file_systems/bfs/Inode.cpp index 882ba9c..356239c 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Inode.cpp @@ -164,13 +164,13 @@ private: */ class BlockRunBuffer { public: - BlockRunBuffer(Volume* volume); + BlockRunBuffer(Volume* volume, + bool useBlockCache); ~BlockRunBuffer(); - status_t GetBlocks(const uint8** buffer, - off_t blocksRequested, + const uint8* GetBlocks(off_t blocksRequested, off_t& blocksWritten); - status_t PutRun(block_run run); + void PutRun(block_run run); off_t NumBlocks() const { return fNumBlocks; } bool IsEmpty() const { return fNumBlocks == 0; } bool IsFull() const; @@ -181,6 +181,7 @@ public: private: Volume* fVolume; + bool fUseBlockCache; // fields to manage the circular buffer of block_run's block_run* fBuffer; @@ -195,9 +196,8 @@ private: // buffer to store block data as we write it to disk uint8* fDataBuffer; - uint32 fDataBufferSize; - static const int32 kTargetDataBufferSize = 16 * 1024 * 1024; - // == 16 MB + static const int32 kDataBufferSize = 32 * 1024; + // == 32 kB }; @@ -336,9 +336,10 @@ InodeAllocator::_TransactionListener(int32 id, int32 event, void* _inode) // #pragma mark - -BlockRunBuffer::BlockRunBuffer(Volume* volume) +BlockRunBuffer::BlockRunBuffer(Volume* volume, bool useBlockCache) : fVolume(volume), + fUseBlockCache(useBlockCache), fBuffer(NULL), fDataBuffer(NULL) { @@ -370,33 +371,25 @@ BlockRunBuffer::IsFull() const } -status_t +void BlockRunBuffer::PutRun(block_run run) { - if (fBuffer == NULL || fDataBuffer == NULL) - return B_NO_INIT; - - if (IsFull()) - return B_NO_MEMORY; + ASSERT(fBuffer != NULL && fDataBuffer != NULL && !IsFull()); fBuffer[fTail] = run; fTail = (fTail + 1) % kSize; fNumBlocks += run.Length(); - - return B_OK; } -status_t -BlockRunBuffer::GetBlocks(const uint8** buffer, off_t blocksRequested, - off_t& blocksWritten) +const uint8* +BlockRunBuffer::GetBlocks(off_t blocksRequested, off_t& blocksWritten) { - if (fBuffer == NULL || fDataBuffer == NULL) - return B_NO_INIT; + ASSERT(fBuffer != NULL && fDataBuffer != NULL); uint32 blockShift = fVolume->BlockShift(); - uint32 blockSize = fVolume->BlockSize(); + int32 blockSize = fVolume->BlockSize(); // the amount of blocks we can return is the minimum of the blocks // requested, the blocks in the buffer and the size of the data buffer @@ -405,15 +398,28 @@ BlockRunBuffer::GetBlocks(const uint8** buffer, off_t blocksRequested, if (blocksWritten > fNumBlocks) blocksWritten = fNumBlocks; - if (blocksWritten > (fDataBufferSize >> blockShift)) - blocksWritten = fDataBufferSize >> blockShift; + if (blocksWritten > (kDataBufferSize >> blockShift)) + blocksWritten = kDataBufferSize >> blockShift; CachedBlock cached(fVolume); + for (off_t i = 0; i < blocksWritten; i++) { - const uint8* data - = cached.SetTo(fVolume->ToBlock(fBuffer[fHead]) + fOffset); + off_t blockNumber = fVolume->ToBlock(fBuffer[fHead]) + fOffset; - memcpy(fDataBuffer + (i << blockShift), data, blockSize); + if (fUseBlockCache) { + const uint8* data = cached.SetTo(blockNumber); + if (data == NULL) + return NULL; + + memcpy(fDataBuffer + (i << blockShift), data, blockSize); + } else { + ssize_t bytesRead = read_pos(fVolume->Device(), + blockNumber << blockShift, fDataBuffer + (i << blockShift), + blockSize); + + if (bytesRead != blockSize) + return NULL; + } if (++fOffset == fBuffer[fHead].Length()) { fHead = (fHead + 1) % kSize; @@ -424,8 +430,7 @@ BlockRunBuffer::GetBlocks(const uint8** buffer, off_t blocksRequested, ASSERT(fNumBlocks >= 0); } - *buffer = fDataBuffer; - return B_OK; + return fDataBuffer; } @@ -434,26 +439,11 @@ BlockRunBuffer::AllocateBuffers() { // allocate block run buffer fBuffer = new(std::nothrow) block_run[kSize]; - if (fBuffer == NULL) - return B_NO_MEMORY; - - // allocate data buffer - fDataBufferSize = kTargetDataBufferSize; - - while (fDataBufferSize > fVolume->BlockSize()) { - fDataBuffer = new(std::nothrow) uint8[fDataBufferSize]; - if (fDataBuffer != NULL) - return B_OK; - - fDataBufferSize /= 4; - } + fDataBuffer = new(std::nothrow) uint8[kDataBufferSize]; - // don't allocate a data buffer which is smaller than the block size - fDataBuffer = new(std::nothrow) uint8[fVolume->BlockSize()]; - if (fDataBuffer == NULL) + if (fBuffer == NULL || fDataBuffer == NULL) return B_NO_MEMORY; - fDataBufferSize = fVolume->BlockSize(); return B_OK; } @@ -2733,18 +2723,18 @@ Inode::_WriteBufferedRuns(Transaction& transaction, BlockRunBuffer& buffer, } // copy the stream data to our run - for (off_t i = 0; i < blocksToWrite; ) { + for (off_t blocksWritten = 0; blocksWritten < blocksToWrite; ) { off_t blocksRead; - const uint8* sourceData; - status = buffer.GetBlocks(&sourceData, blocksToWrite, blocksRead); - if (status != B_OK) - return status; + const uint8* sourceData + = buffer.GetBlocks(blocksToWrite, blocksRead); + if (sourceData == NULL) + return B_IO_ERROR; // Don't use the journal to copy file data. These blocks are // currently not referenced by the file system in any way, so // we'll be in a valid state even if the transaction fails. - off_t targetBlock = fVolume->ToBlock(run) + i; + off_t targetBlock = fVolume->ToBlock(run) + blocksWritten; ssize_t written = write_pos(fVolume->Device(), targetBlock << blockShift, sourceData, @@ -2753,7 +2743,7 @@ Inode::_WriteBufferedRuns(Transaction& transaction, BlockRunBuffer& buffer, if (written != blocksRead << blockShift) return B_IO_ERROR; - i += blocksRead; + blocksWritten += blocksRead; } } return B_OK; @@ -2781,7 +2771,7 @@ Inode::_GetNextBlockRun(off_t& position, block_run& run) const bool -Inode::_BlockRunInRange(block_run run, off_t beginBlock, off_t endBlock) const +Inode::_IsBlockRunInRange(block_run run, off_t beginBlock, off_t endBlock) const { off_t runStart = GetVolume()->ToBlock(run); return runStart >= beginBlock && runStart + run.Length() <= endBlock; @@ -2789,10 +2779,10 @@ Inode::_BlockRunInRange(block_run run, off_t beginBlock, off_t endBlock) const bool -Inode::_BlockRunOutsideRange(block_run run, off_t beginBlock, off_t endBlock) +Inode::_IsBlockRunOutsideRange(block_run run, off_t beginBlock, off_t endBlock) const { - // note that this is not the opposite of _BlockRunInRange, as we only + // note that this is not the opposite of _IsBlockRunInRange, as we only // return true if the block run is completely outside the range. off_t runStart = GetVolume()->ToBlock(run); return runStart + run.Length() <= beginBlock || runStart >= endBlock; @@ -2805,10 +2795,30 @@ Inode::_BlockRunOutsideRange(block_run run, off_t beginBlock, off_t endBlock) status_t Inode::MoveStream(off_t beginBlock, off_t endBlock) { + // We move the stream by rebuilding it from scratch. block_runs which + // can be reused are simply added to the result stream (newStream) as + // they are. Runs which can't, are added to a buffer, and the stream + // data is copied to newly allocated block_runs when necessary. + // + // This is complicated by the fact that the length of block_runs in the + // double indirect range needs to be a multiple of a certain length. + // Two problems result from this: + // + // 1. We can't reuse a block_run from the original stream if it has + // the wrong length, even though it's inside the allowed range. + // + // 2. The number of blocks in the BlockRunBuffer might not be a + // multiple of this base length. When that happens, we can't write + // all the blocks to disk, so we can't reuse the block_run from + // the original stream even if it has a valid size and location. + // + // Note that this only applies when we're adding block_runs to the + // double indirect range of newStream. + status_t status; data_stream data = {}; - BlockRunBuffer buffer(fVolume); + BlockRunBuffer buffer(fVolume, IsDirectory()); status = buffer.AllocateBuffers(); if (status != B_OK) return status; @@ -2831,15 +2841,15 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) if (status != B_OK) return status; - if (_BlockRunInRange(run, beginBlock, endBlock)) { + if (_IsBlockRunInRange(run, beginBlock, endBlock)) { status = _WriteBufferedRuns(transaction, buffer, &data, Size(), false, beginBlock, endBlock); if (status != B_OK) return status; - // if we're writing to the double indirect range, we might not have - // cleared the buffer - + // If we're writing to the double indirect range, we might not have + // cleared the buffer. Before we add this block_run to the stream, + // make sure that this is not the case. if (buffer.IsEmpty()) { int32 rest; status = _AddBlockRun(transaction, &data, run, Size(), &rest, @@ -2847,6 +2857,8 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) if (status != B_OK) return status; + // if there's no rest, we've managed to add this run to the + // output stream, and can move on to the next if (rest == 0) continue; @@ -2864,7 +2876,7 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) } buffer.PutRun(run); - if (_BlockRunOutsideRange(run, beginBlock, endBlock)) { + if (_IsBlockRunOutsideRange(run, beginBlock, endBlock)) { // The block run was outside of the allowed range, which means // that we can free it now without running the risk of // reallocating it and overwriting its content. @@ -2905,7 +2917,7 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) but not including \endBlock. */ status_t -Inode::StreamInRange(bool& inRange, off_t beginBlock, off_t endBlock) const +Inode::StreamInRange(off_t beginBlock, off_t endBlock, bool& inRange) const { inRange = false; // now we can simply return if we find a run which is not in the range @@ -2914,12 +2926,12 @@ Inode::StreamInRange(bool& inRange, off_t beginBlock, off_t endBlock) const const data_stream* data = &fNode.data; if (!data->indirect.IsZero() - && !_BlockRunInRange(data->indirect, beginBlock, endBlock)) { + && !_IsBlockRunInRange(data->indirect, beginBlock, endBlock)) { return B_OK; } if (!data->double_indirect.IsZero()) { - if (!_BlockRunInRange(data->double_indirect, beginBlock, endBlock)) + if (!_IsBlockRunInRange(data->double_indirect, beginBlock, endBlock)) return B_OK; int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run); @@ -2938,7 +2950,7 @@ Inode::StreamInRange(bool& inRange, off_t beginBlock, off_t endBlock) const break; } - if (!_BlockRunInRange(runArray[i], beginBlock, endBlock)) + if (!_IsBlockRunInRange(runArray[i], beginBlock, endBlock)) return B_OK; } @@ -2958,7 +2970,7 @@ Inode::StreamInRange(bool& inRange, off_t beginBlock, off_t endBlock) const if (status != B_OK) return status; - if (!_BlockRunInRange(run, beginBlock, endBlock)) + if (!_IsBlockRunInRange(run, beginBlock, endBlock)) return B_OK; } diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.h b/src/add-ons/kernel/file_systems/bfs/Inode.h index 46148c4..2d6b122 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.h +++ b/src/add-ons/kernel/file_systems/bfs/Inode.h @@ -153,9 +153,8 @@ public: bool NeedsTrimming() const; status_t MoveStream(off_t beginBlock, off_t endBlock); - status_t StreamInRange(bool& inRange, off_t beginBlock, - off_t endBlock) const; - + status_t StreamInRange(off_t beginBlock, off_t endBlock, + bool& inRange) const; status_t Free(Transaction& transaction); status_t Sync(); @@ -270,9 +269,9 @@ private: status_t _GetNextBlockRun(off_t& position, block_run& run) const; - bool _BlockRunInRange(block_run run, + bool _IsBlockRunInRange(block_run run, off_t beginBlock, off_t endBlock) const; - bool _BlockRunOutsideRange(block_run run, + bool _IsBlockRunOutsideRange(block_run run, off_t beginBlock, off_t endBlock) const; private: ############################################################################ Commit: 5b66a74c5e609b7de6fcb9cb2f45a1be425c607d Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Mon Jul 2 17:28:49 2012 UTC Explain why we can't use Replace in Index::UpdateInode (duplicates) ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/bfs/Index.cpp b/src/add-ons/kernel/file_systems/bfs/Index.cpp index 2ee601b..c66a879 100644 --- a/src/add-ons/kernel/file_systems/bfs/Index.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Index.cpp @@ -389,7 +389,9 @@ status_t Index::UpdateInode(Transaction& transaction, const uint8* key, uint16 length, off_t oldInodeID, off_t newInodeID) { - // remove node and insert it with the new id + // remove node and insert it with the new id (we can't use + // BPlusTree::Replace, as it doesn't handle trees where duplicates + // are allowed) BPlusTree* tree = Node()->Tree(); status_t status = tree->Remove(transaction, key, length, oldInodeID); ############################################################################ Commit: 5b70193647d92c567f117f8dc2e3cf313857aedb Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Mon Jul 2 19:33:11 2012 UTC Don't use 'data' as a data_stream name unless it refers to the Inode stream ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.cpp b/src/add-ons/kernel/file_systems/bfs/Inode.cpp index 356239c..07e35a7 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Inode.cpp @@ -1845,7 +1845,7 @@ Inode::_AllocateBlockArray(Transaction& transaction, block_run& run, } -/*! Adds \a run to \a data, allocating indirection blocks if necessary. +/*! Adds \a run to \a dataStream, 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. @@ -1854,74 +1854,75 @@ Inode::_AllocateBlockArray(Transaction& transaction, block_run& run, 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) +Inode::_AddBlockRun(Transaction& transaction, data_stream* dataStream, + 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() + bool cutSize = targetSize < dataStream->Size() + (run.Length() << fVolume->BlockShift()); // if adding this block_run means overshooting the target stream size, - // we need to set data->size to targetSize. + // we need to set dataStream->size to targetSize. // Direct block range - if (data->Size() <= data->MaxDirectRange()) { + if (dataStream->Size() <= dataStream->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()) + if (dataStream->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()); + if (free > 0 && dataStream->direct[last].MergeableWith(run)) { + dataStream->direct[last].length = HOST_ENDIAN_TO_BFS_INT16( + dataStream->direct[last].Length() + run.Length()); } else - data->direct[free] = run; + dataStream->direct[free] = run; - data->max_direct_range = HOST_ENDIAN_TO_BFS_INT64( - data->MaxDirectRange() + dataStream->max_direct_range = HOST_ENDIAN_TO_BFS_INT64( + dataStream->MaxDirectRange() + run.Length() * fVolume->BlockSize()); - data->size = cutSize ? HOST_ENDIAN_TO_BFS_INT64(targetSize) - : data->max_direct_range; + dataStream->size = cutSize ? HOST_ENDIAN_TO_BFS_INT64(targetSize) + : dataStream->max_direct_range; return B_OK; } } // Indirect block range - if (data->Size() <= data->MaxIndirectRange() - || !data->MaxIndirectRange()) { + if (dataStream->Size() <= dataStream->MaxIndirectRange() + || !dataStream->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, + if (dataStream->indirect.IsZero()) { + status = _AllocateBlockArray(transaction, dataStream->indirect, NUM_ARRAY_BLOCKS, true, beginBlock, endBlock); if (status != B_OK) return status; - data->max_indirect_range = data->max_direct_range; + dataStream->max_indirect_range = dataStream->max_direct_range; // insert the block_run in the first block - runs = (block_run*)cached.SetTo(data->indirect); + runs = (block_run*)cached.SetTo(dataStream->indirect); } else { uint32 numberOfRuns = fVolume->BlockSize() / sizeof(block_run); - block = fVolume->ToBlock(data->indirect); + block = fVolume->ToBlock(dataStream->indirect); // search first empty entry int32 i = 0; - for (; i < data->indirect.Length(); i++) { + for (; i < dataStream->indirect.Length(); i++) { if ((runs = (block_run*)cached.SetTo(block + i)) == NULL) return B_IO_ERROR; @@ -1932,7 +1933,7 @@ Inode::_AddBlockRun(Transaction& transaction, data_stream* data, block_run run, if (free < numberOfRuns) break; } - if (i == data->indirect.Length()) + if (i == dataStream->indirect.Length()) runs = NULL; } @@ -1949,26 +1950,26 @@ Inode::_AddBlockRun(Transaction& transaction, data_stream* data, block_run run, } else runs[free] = run; - data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64( - data->MaxIndirectRange() + dataStream->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64( + dataStream->MaxIndirectRange() + (run.Length() << fVolume->BlockShift())); - data->size = cutSize ? HOST_ENDIAN_TO_BFS_INT64(targetSize) - : data->max_indirect_range; + dataStream->size = cutSize ? HOST_ENDIAN_TO_BFS_INT64(targetSize) + : dataStream->max_indirect_range; return B_OK; } } // Double indirect block range - if (data->Size() <= data->MaxDoubleIndirectRange() - || !data->max_double_indirect_range) { + if (dataStream->Size() <= dataStream->MaxDoubleIndirectRange() + || !dataStream->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) + if (!dataStream->max_double_indirect_range) doubleIndirectBlockLength = _DoubleIndirectBlockLength(); else - doubleIndirectBlockLength = data->double_indirect.Length(); + doubleIndirectBlockLength = dataStream->double_indirect.Length(); if ((run.Length() % doubleIndirectBlockLength) != 0) { // The number of allocated blocks isn't a multiple of @@ -1985,14 +1986,15 @@ Inode::_AddBlockRun(Transaction& transaction, data_stream* data, block_run run, } // if there is no double indirect block yet, create one - if (data->double_indirect.IsZero()) { + if (dataStream->double_indirect.IsZero()) { status = _AllocateBlockArray(transaction, - data->double_indirect, _DoubleIndirectBlockLength(), + dataStream->double_indirect, _DoubleIndirectBlockLength(), beginBlock, endBlock); if (status != B_OK) return status; - data->max_double_indirect_range = data->max_indirect_range; + dataStream->max_double_indirect_range = + dataStream->max_indirect_range; } // calculate the index where to insert the new blocks @@ -2000,11 +2002,11 @@ Inode::_AddBlockRun(Transaction& transaction, data_stream* data, block_run run, int32 runsPerBlock; int32 directSize; int32 indirectSize; - get_double_indirect_sizes(data->double_indirect.Length(), + get_double_indirect_sizes(dataStream->double_indirect.Length(), fVolume->BlockSize(), runsPerBlock, directSize, indirectSize); - off_t start = data->MaxDoubleIndirectRange() - - data->MaxIndirectRange(); + off_t start = dataStream->MaxDoubleIndirectRange() + - dataStream->MaxIndirectRange(); int32 indirectIndex = start / indirectSize; int32 index = (start % indirectSize) / directSize; int32 runsPerArray = runsPerBlock * doubleIndirectBlockLength; @@ -2025,7 +2027,7 @@ Inode::_AddBlockRun(Transaction& transaction, data_stream* data, block_run run, return EFBIG; array = (block_run*)cached.SetTo(fVolume->ToBlock( - data->double_indirect) + block); + dataStream->double_indirect) + block); if (array == NULL) return B_IO_ERROR; } @@ -2037,7 +2039,8 @@ Inode::_AddBlockRun(Transaction& transaction, data_stream* data, block_run run, status = _AllocateBlockArray(transaction, array[indirectIndex % runsPerBlock], - data->double_indirect.Length(), beginBlock, endBlock); + dataStream->double_indirect.Length(), beginBlock, + endBlock); if (status != B_OK) return status; } @@ -2070,11 +2073,11 @@ Inode::_AddBlockRun(Transaction& transaction, data_stream* data, block_run run, } } - data->max_double_indirect_range = HOST_ENDIAN_TO_BFS_INT64( - data->MaxDoubleIndirectRange() + dataStream->max_double_indirect_range = HOST_ENDIAN_TO_BFS_INT64( + dataStream->MaxDoubleIndirectRange() + (runLength << fVolume->BlockShift())); - data->size = cutSize ? HOST_ENDIAN_TO_BFS_INT64(targetSize) - : data->max_double_indirect_range; + dataStream->size = cutSize ? HOST_ENDIAN_TO_BFS_INT64(targetSize) + : dataStream->max_double_indirect_range; return B_OK; } @@ -2648,13 +2651,13 @@ Inode::Sync() } -/*! Write the block runs in \a buffer to \a data. +/*! Write the block runs in \a buffer to \a dataStream. If \a flush is set, we always empty the buffer even if it means allocating a block run which is larger than the availible blocks. */ status_t Inode::_WriteBufferedRuns(Transaction& transaction, BlockRunBuffer& buffer, - data_stream* data, off_t targetSize, bool flush, off_t beginBlock, + data_stream* dataStream, off_t targetSize, bool flush, off_t beginBlock, off_t endBlock) { status_t status; @@ -2662,8 +2665,8 @@ Inode::_WriteBufferedRuns(Transaction& transaction, BlockRunBuffer& buffer, uint32 blockShift = fVolume->BlockShift(); - bool inDoubleIndirect = data->MaxIndirectRange() != 0 - && data->Size() > data->MaxIndirectRange(); + bool inDoubleIndirect = dataStream->MaxIndirectRange() != 0 + && dataStream->Size() > dataStream->MaxIndirectRange(); // we might be about to add a block_run to the double indirect range // even if this is false, we'll discover that case when we try @@ -2704,7 +2707,7 @@ Inode::_WriteBufferedRuns(Transaction& transaction, BlockRunBuffer& buffer, // add the run to the data stream int32 rest; - status = _AddBlockRun(transaction, data, run, targetSize, + status = _AddBlockRun(transaction, dataStream, run, targetSize, &rest, beginBlock, endBlock); if (status != B_OK) return status; @@ -2816,7 +2819,7 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) // double indirect range of newStream. status_t status; - data_stream data = {}; + data_stream newStream = {}; BlockRunBuffer buffer(fVolume, IsDirectory()); status = buffer.AllocateBuffers(); @@ -2842,8 +2845,8 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) return status; if (_IsBlockRunInRange(run, beginBlock, endBlock)) { - status = _WriteBufferedRuns(transaction, buffer, &data, Size(), - false, beginBlock, endBlock); + status = _WriteBufferedRuns(transaction, buffer, &newStream, + Size(), false, beginBlock, endBlock); if (status != B_OK) return status; @@ -2852,8 +2855,8 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) // make sure that this is not the case. if (buffer.IsEmpty()) { int32 rest; - status = _AddBlockRun(transaction, &data, run, Size(), &rest, - beginBlock, endBlock); + status = _AddBlockRun(transaction, &newStream, run, Size(), + &rest, beginBlock, endBlock); if (status != B_OK) return status; @@ -2869,8 +2872,8 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) // We can't reuse this block_run, add it to the block_run buffer. if (buffer.IsFull()) { - status = _WriteBufferedRuns(transaction, buffer, &data, Size(), - false, beginBlock, endBlock); + status = _WriteBufferedRuns(transaction, buffer, &newStream, + Size(), false, beginBlock, endBlock); if (status != B_OK) return status; } @@ -2892,12 +2895,12 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) } // write all blocks remaining in the buffer to disk - status = _WriteBufferedRuns(transaction, buffer, &data, Size(), true, + status = _WriteBufferedRuns(transaction, buffer, &newStream, Size(), true, beginBlock, endBlock); if (status != B_OK) return status; - ASSERT(data.Size() == Size()); + ASSERT(newStream.Size() == Size()); // free the blocks we didn't end up reusing block_run toFree; @@ -2907,7 +2910,7 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock) return status; } - fNode.data = data; + fNode.data = newStream; return transaction.Done(); } diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.h b/src/add-ons/kernel/file_systems/bfs/Inode.h index 2d6b122..d20db02 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.h +++ b/src/add-ons/kernel/file_systems/bfs/Inode.h @@ -257,15 +257,16 @@ private: status_t _ShrinkStream(Transaction& transaction, off_t size); status_t _AddBlockRun(Transaction& transaction, - data_stream* data, block_run run, + data_stream* dataStream, block_run run, off_t targetSize, int32* rest = NULL, off_t beginBlock = 0, off_t endBlock = 0); // moving the data stream status_t _WriteBufferedRuns(Transaction& transaction, - BlockRunBuffer& buffer, data_stream* data, - off_t targetSize, bool flush = false, - off_t beginBlock = 0, off_t endBlock = 0); + BlockRunBuffer& buffer, + data_stream* dataStream, off_t targetSize, + bool flush = false, off_t beginBlock = 0, + off_t endBlock = 0); status_t _GetNextBlockRun(off_t& position, block_run& run) const; ############################################################################ Commit: debc1307496dc87e1ec14c6bb0630e6d58f852b2 Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Tue Jul 3 12:12:05 2012 UTC Logic error in _WriteBufferedRuns() that was hidden by the big buffer ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.cpp b/src/add-ons/kernel/file_systems/bfs/Inode.cpp index 07e35a7..77db9bf 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Inode.cpp @@ -2730,7 +2730,7 @@ Inode::_WriteBufferedRuns(Transaction& transaction, BlockRunBuffer& buffer, off_t blocksRead; const uint8* sourceData - = buffer.GetBlocks(blocksToWrite, blocksRead); + = buffer.GetBlocks(blocksToWrite - blocksWritten, blocksRead); if (sourceData == NULL) return B_IO_ERROR;