The whole reading was seriously confused. It tried to use the block cache for

multiple blocks at a time which it doesn't do as it always only returns one
block (and actually completely ignores the provided offset and length).
It only didn't crash after that because it would in the end always only memcpy
length >> block shift bytes which ends up being pretty small in most cases.
Since it does block wise mapping it can't do multiple blocks anyway, and really
using the block cache for this is all wrong because this should really use a
file map to resolve the block mapping and then use the file cache instead.
Still this at least gets it working. Beware though that protected DVD content
will make the block cache panic, as reading these blocks without prior setting
the drive up correctly will fail (the drive will stall the reads).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35651 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2010-02-28 05:35:31 +00:00
parent cd4e946773
commit 4f3f1911cd

View File

@ -203,12 +203,20 @@ Icb::_Read(DescriptorList &list, off_t pos, void *_buffer, size_t *length, uint3
off_t blockOffset
= pos - off_t((pos >> volume->BlockShift()) << volume->BlockShift());
size_t fullBlocksLeft = bytesLeft >> volume->BlockShift();
size_t readLength = volume->BlockSize() - blockOffset;
if (bytesLeft < readLength)
readLength = bytesLeft;
if (extent.length() < readLength)
readLength = extent.length();
if (fullBlocksLeft > 0 && blockOffset == 0) {
TRACE(("Icb::_Read(): reading full block (or more)\n"));
// Block aligned and at least one full block left. Read
// in using block_cache_get_etc() calls.
TRACE(("Icb::_Read: reading block. offset = %Ld, length: %ld\n",
blockOffset, readLength));
if (isEmpty) {
TRACE(("Icb::_Read: reading %ld empty bytes as zeros\n",
readLength));
memset(buffer, 0, readLength);
} else {
off_t diskBlock;
status = volume->MapBlock(extent, &diskBlock);
if (status != B_OK) {
@ -216,83 +224,20 @@ Icb::_Read(DescriptorList &list, off_t pos, void *_buffer, size_t *length, uint3
break;
}
size_t fullBlockBytesLeft = fullBlocksLeft << volume->BlockShift();
size_t readLength = fullBlockBytesLeft < extent.length()
? fullBlockBytesLeft : extent.length();
TRACE(("Icb::_Read: %ld bytes from disk block %Ld using "
"block_cache_get_etc()\n", readLength, diskBlock));
uint8 *data = (uint8*)block_cache_get_etc(volume->BlockCache(),
diskBlock, 0, readLength);
if (data == NULL)
break;
memcpy(buffer, data + blockOffset, readLength);
block_cache_put(volume->BlockCache(), diskBlock);
}
if (isEmpty) {
TRACE(("Icb::_Read(): reading %ld empty bytes as zeros\n",
readLength));
memset(buffer, 0, readLength);
} else {
off_t diskBlock;
status = volume->MapBlock(extent, &diskBlock);
if (status != B_OK) {
TRACE_ERROR(("Icb::_Read: could not map extent\n"));
break;
}
TRACE(("Icb::_Read(): reading %ld bytes from disk block %Ld "
"using block_cache_get_etc()\n", readLength, diskBlock));
size_t length = readLength >> volume->BlockShift();
uint8 *data = (uint8*)block_cache_get_etc(volume->BlockCache(),
diskBlock, pos, length);
if (data == NULL) {
status = B_BAD_DATA;
break;
}
memcpy(buffer, data, length);
block_cache_put(volume->BlockCache(), diskBlock);
}
bytesLeft -= readLength;
bytesRead += readLength;
pos += readLength;
buffer += readLength;
} else {
off_t partialOffset;
size_t partialLength;
if (blockOffset == 0) {
// Block aligned, but only a partial block's worth remaining.
// Read in remaining bytes of file
partialOffset = 0;
partialLength = bytesLeft;
} else {
// Not block aligned, so just read up to the next block boundary.
partialOffset = blockOffset;
partialLength = volume->BlockSize() - blockOffset;
if (bytesLeft < partialLength)
partialLength = bytesLeft;
}
TRACE(("Icb::_Read: reading partial block. partialOffset = %Ld, "
"partialLength: %ld\n",partialOffset, partialLength));
if (isEmpty) {
TRACE(("Icb::_Read: reading %ld empty bytes as zeros\n",
partialLength));
memset(buffer, 0, partialLength);
} else {
off_t diskBlock;
status = volume->MapBlock(extent, &diskBlock);
if (status != B_OK) {
TRACE_ERROR(("Icb::_Read: could not map extent\n"));
break;
}
TRACE(("Icb::_Read: %ld bytes from disk block %Ld using "
"block_cache_get_etc()\n", partialLength, diskBlock));
uint8 *data = (uint8*)block_cache_get_etc(volume->BlockCache(),
diskBlock, 0, partialLength);
if (data == NULL)
break;
memcpy(buffer, data + partialOffset, partialLength);
block_cache_put(volume->BlockCache(), diskBlock);
}
bytesLeft -= partialLength;
bytesRead += partialLength;
pos += partialLength;
buffer += partialLength;
}
bytesLeft -= readLength;
bytesRead += readLength;
pos += readLength;
buffer += readLength;
}
*length = bytesRead;