From fd91d2cbe1f045c71e94fa7db6fbce2b6b0d4883 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 11 Nov 2013 21:45:03 +0100 Subject: [PATCH] ext2: ExtentStream::FindBlock(): Restructure/fix * The binary search was somewhat broken. * Restructure a bit so that only the binary/linear search itself is handled separately. The handling afterwards is common again. * Fix sparse block handling: - There can be sparse blocks before the first extend. - Set the return parameter _count in this case as well. - Set the return parameter block to 0 instead of 0xffffffff. That's what ext2_get_file_map() expects. Fixes an infinite loop in ext2_get_file_map() when sparse blocks are involved, due to previously returning a wrong block and a 0 count. Ticket #9274 may be related. --- .../kernel/file_systems/ext2/ExtentStream.cpp | 93 +++++++++++-------- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp b/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp index 6bf7ff62f9..3374d1b5aa 100644 --- a/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp +++ b/src/add-ons/kernel/file_systems/ext2/ExtentStream.cpp @@ -77,60 +77,71 @@ ExtentStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count) panic("ExtentStream::FindBlock() invalid header\n"); } + // find the extend following the one that should contain the logical block + int32 extentIndex; if (stream->extent_header.NumEntries() > 7) { // binary search when enough entries int32 low = 0; int32 high = stream->extent_header.NumEntries() - 1; - int32 middle = 0; - while (low <= high) { - middle = (high + low) >> 1; - if (stream->extent_entries[middle].LogicalBlock() == index) - break; - if (stream->extent_entries[middle].LogicalBlock() < index) - low = middle + 1; - else + while (low < high) { + int32 middle = (high + low + 1) / 2; + if (stream->extent_entries[middle].LogicalBlock() > index) high = middle - 1; - } - if (stream->extent_entries[middle].LogicalBlock() > index) - middle--; - fileblock_t diff = index - - stream->extent_entries[middle].LogicalBlock(); - if (diff > stream->extent_entries[middle].Length()) { - // sparse block - TRACE("FindBlock() sparse block index %" B_PRIu64 " at %" B_PRIu32 - "\n", index, stream->extent_entries[middle].LogicalBlock()); - block = 0xffffffff; - return B_OK; + else + low = middle; } - block = stream->extent_entries[middle].PhysicalBlock() + diff; - if (_count) - *_count = stream->extent_entries[middle].Length() - diff; - TRACE("FindBlock(offset %" B_PRIdOFF "): %" B_PRIu64 " %" B_PRIu32 - "\n", offset, block, _count != NULL ? *_count : 1); + extentIndex = low + 1; + } else { + extentIndex = stream->extent_header.NumEntries(); + for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) { + if (stream->extent_entries[i].LogicalBlock() > index) { + extentIndex = i; + break; + } + } + } + + fileblock_t logicalEndIndex + = (fSize + fVolume->BlockSize() - 1) >> fVolume->BlockShift(); + + if (extentIndex == 0) { + // sparse block at the beginning of the stream + block = 0; + if (_count != NULL) { + *_count = stream->extent_header.NumEntries() == 0 + ? logicalEndIndex - index + : stream->extent_entries[0].LogicalBlock() - index; + } + TRACE("FindBlock() sparse block index %" B_PRIu64 " at beginning of " + "stream\n", index); return B_OK; } - for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) { - if (stream->extent_entries[i].LogicalBlock() > index) { - // sparse block - TRACE("FindBlock() sparse block index %" B_PRIu64 " at %" B_PRIu32 - "\n", index, stream->extent_entries[i].LogicalBlock()); - block = 0xffffffff; - return B_OK; - } - fileblock_t diff = index - stream->extent_entries[i].LogicalBlock(); - if (diff < stream->extent_entries[i].Length()) { - block = stream->extent_entries[i].PhysicalBlock() + diff; - if (_count) - *_count = stream->extent_entries[i].Length() - diff; - TRACE("FindBlock(offset %" B_PRIdOFF "): %" B_PRIu64 " %" B_PRIu32 - "\n", offset, block, _count != NULL ? *_count : 1); - return B_OK; + const ext2_extent_entry& extent = stream->extent_entries[extentIndex - 1]; + // the extent supposedly containing the offset + fileblock_t diff = index - extent.LogicalBlock(); + if (diff >= extent.Length()) { + // sparse block between extends or at the end of the stream + TRACE("FindBlock() sparse block index %" B_PRIu64 " at %" B_PRIu32 + "\n", index, extent.LogicalBlock()); + block = 0; + if (_count != NULL) { + *_count = stream->extent_header.NumEntries() == extentIndex + ? logicalEndIndex - index + : stream->extent_entries[extentIndex].LogicalBlock() - index; } + return B_OK; } - return B_ERROR; + block = extent.PhysicalBlock() + diff; + if (_count != NULL) + *_count = extent.Length() - diff; + + TRACE("FindBlock(offset %" B_PRIdOFF "): %" B_PRIu64 " %" B_PRIu32 + "\n", offset, block, _count != NULL ? *_count : 1); + + return B_OK; }