The log replay code now checks if a super block is valid before the current
one gets overwritten; if the log contains invalid data, it will no longer render the whole disk unreadable. This should have helped to prevent bug #1911 (but of course the problem that there is invalid data in the log in the first place remains). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24381 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -419,12 +419,22 @@ Journal::_ReplayRunArray(int32 *_start)
|
|||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
RETURN_ERROR(B_IO_ERROR);
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
|
|
||||||
ssize_t written = write_pos(fVolume->Device(),
|
// TODO: eventually check other well known offsets, like the
|
||||||
offset + (i * blockSize), data, blockSize);
|
// root and index dirs
|
||||||
|
if (offset == 0) {
|
||||||
|
// This log entry writes over the super block - check if
|
||||||
|
// it's valid!
|
||||||
|
if (Volume::CheckSuperBlock(data) != B_OK)
|
||||||
|
RETURN_ERROR(B_BAD_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t written = write_pos(fVolume->Device(), offset, data,
|
||||||
|
blockSize);
|
||||||
if (written != blockSize)
|
if (written != blockSize)
|
||||||
RETURN_ERROR(B_IO_ERROR);
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
|
|
||||||
blockNumber = (blockNumber + 1) % fLogSize;
|
blockNumber = (blockNumber + 1) % fLogSize;
|
||||||
|
offset += blockSize;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,25 +558,42 @@ Volume::RemoveQuery(Query *query)
|
|||||||
// #pragma mark - Disk scanning and initialization
|
// #pragma mark - Disk scanning and initialization
|
||||||
|
|
||||||
|
|
||||||
status_t
|
/*static*/ status_t
|
||||||
|
Volume::CheckSuperBlock(const uint8* data, uint32* _offset)
|
||||||
|
{
|
||||||
|
disk_super_block* superBlock = (disk_super_block*)(data + 512);
|
||||||
|
if (superBlock->IsValid()) {
|
||||||
|
if (_offset != NULL)
|
||||||
|
*_offset = 512;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef BFS_LITTLE_ENDIAN_ONLY
|
||||||
|
// For PPC, the super block might be located at offset 0
|
||||||
|
superBlock = (disk_super_block*)data;
|
||||||
|
if (superBlock->IsValid()) {
|
||||||
|
if (_offset != NULL)
|
||||||
|
*_offset = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ status_t
|
||||||
Volume::Identify(int fd, disk_super_block *superBlock)
|
Volume::Identify(int fd, disk_super_block *superBlock)
|
||||||
{
|
{
|
||||||
char buffer[1024];
|
uint8 buffer[1024];
|
||||||
if (read_pos(fd, 0, buffer, sizeof(buffer)) != sizeof(buffer))
|
if (read_pos(fd, 0, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
|
|
||||||
memcpy(superBlock, buffer + 512, sizeof(disk_super_block));
|
uint32 offset;
|
||||||
if (!superBlock->IsValid()) {
|
if (CheckSuperBlock(buffer, &offset) != B_OK)
|
||||||
#ifndef BFS_LITTLE_ENDIAN_ONLY
|
|
||||||
// For PPC, the super block might be located at offset 0
|
|
||||||
memcpy(superBlock, buffer, sizeof(disk_super_block));
|
|
||||||
if (!superBlock->IsValid())
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
#else
|
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
memcpy(superBlock, buffer + offset, sizeof(disk_super_block));
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ class Volume {
|
|||||||
|
|
||||||
uint32 GetUniqueID();
|
uint32 GetUniqueID();
|
||||||
|
|
||||||
|
static status_t CheckSuperBlock(const uint8* data,
|
||||||
|
uint32* _offset = NULL);
|
||||||
static status_t Identify(int fd, disk_super_block *superBlock);
|
static status_t Identify(int fd, disk_super_block *superBlock);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
Reference in New Issue
Block a user