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.
This commit is contained in:
@@ -77,60 +77,71 @@ ExtentStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count)
|
|||||||
panic("ExtentStream::FindBlock() invalid header\n");
|
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) {
|
if (stream->extent_header.NumEntries() > 7) {
|
||||||
// binary search when enough entries
|
// binary search when enough entries
|
||||||
int32 low = 0;
|
int32 low = 0;
|
||||||
int32 high = stream->extent_header.NumEntries() - 1;
|
int32 high = stream->extent_header.NumEntries() - 1;
|
||||||
int32 middle = 0;
|
while (low < high) {
|
||||||
while (low <= high) {
|
int32 middle = (high + low + 1) / 2;
|
||||||
middle = (high + low) >> 1;
|
if (stream->extent_entries[middle].LogicalBlock() > index)
|
||||||
if (stream->extent_entries[middle].LogicalBlock() == index)
|
|
||||||
break;
|
|
||||||
if (stream->extent_entries[middle].LogicalBlock() < index)
|
|
||||||
low = middle + 1;
|
|
||||||
else
|
|
||||||
high = middle - 1;
|
high = middle - 1;
|
||||||
}
|
else
|
||||||
if (stream->extent_entries[middle].LogicalBlock() > index)
|
low = middle;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
block = stream->extent_entries[middle].PhysicalBlock() + diff;
|
extentIndex = low + 1;
|
||||||
if (_count)
|
} else {
|
||||||
*_count = stream->extent_entries[middle].Length() - diff;
|
extentIndex = stream->extent_header.NumEntries();
|
||||||
TRACE("FindBlock(offset %" B_PRIdOFF "): %" B_PRIu64 " %" B_PRIu32
|
for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) {
|
||||||
"\n", offset, block, _count != NULL ? *_count : 1);
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32 i = 0; i < stream->extent_header.NumEntries(); i++) {
|
const ext2_extent_entry& extent = stream->extent_entries[extentIndex - 1];
|
||||||
if (stream->extent_entries[i].LogicalBlock() > index) {
|
// the extent supposedly containing the offset
|
||||||
// sparse block
|
fileblock_t diff = index - extent.LogicalBlock();
|
||||||
TRACE("FindBlock() sparse block index %" B_PRIu64 " at %" B_PRIu32
|
if (diff >= extent.Length()) {
|
||||||
"\n", index, stream->extent_entries[i].LogicalBlock());
|
// sparse block between extends or at the end of the stream
|
||||||
block = 0xffffffff;
|
TRACE("FindBlock() sparse block index %" B_PRIu64 " at %" B_PRIu32
|
||||||
return B_OK;
|
"\n", index, extent.LogicalBlock());
|
||||||
}
|
block = 0;
|
||||||
fileblock_t diff = index - stream->extent_entries[i].LogicalBlock();
|
if (_count != NULL) {
|
||||||
if (diff < stream->extent_entries[i].Length()) {
|
*_count = stream->extent_header.NumEntries() == extentIndex
|
||||||
block = stream->extent_entries[i].PhysicalBlock() + diff;
|
? logicalEndIndex - index
|
||||||
if (_count)
|
: stream->extent_entries[extentIndex].LogicalBlock() - index;
|
||||||
*_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;
|
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user