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:
Axel Dörfler
2008-03-12 22:49:41 +00:00
parent 876b8c17c8
commit 0dc57dbece
3 changed files with 43 additions and 14 deletions
@@ -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++;
} }
} }
+29 -12
View File
@@ -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: