|
Packit Service |
d40955 |
/*
|
|
Packit Service |
d40955 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
d40955 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
d40955 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
d40955 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
d40955 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
d40955 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
d40955 |
* GNU General Public License for more details.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
d40955 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
d40955 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
d40955 |
* 02110-1301, USA.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/superBlock.c#5 $
|
|
Packit Service |
d40955 |
*/
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "superBlock.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "buffer.h"
|
|
Packit Service |
d40955 |
#include "logger.h"
|
|
Packit Service |
d40955 |
#include "memoryAlloc.h"
|
|
Packit Service |
d40955 |
#include "permassert.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "completion.h"
|
|
Packit Service |
d40955 |
#include "constants.h"
|
|
Packit Service |
d40955 |
#include "header.h"
|
|
Packit Service |
d40955 |
#include "releaseVersions.h"
|
|
Packit Service |
d40955 |
#include "statusCodes.h"
|
|
Packit Service |
d40955 |
#include "types.h"
|
|
Packit Service |
d40955 |
#include "vio.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
struct superBlock {
|
|
Packit Service |
d40955 |
/** The parent for asynchronous load and save operations */
|
|
Packit Service |
d40955 |
VDOCompletion *parent;
|
|
Packit Service |
d40955 |
/** The VIO for reading and writing the super block to disk */
|
|
Packit Service |
d40955 |
VIO *vio;
|
|
Packit Service |
d40955 |
/** The buffer for encoding and decoding component data */
|
|
Packit Service |
d40955 |
Buffer *componentBuffer;
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* A sector-sized buffer wrapping the first sector of encodedSuperBlock, for
|
|
Packit Service |
d40955 |
* encoding and decoding the entire super block.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
Buffer *blockBuffer;
|
|
Packit Service |
d40955 |
/** A 1-block buffer holding the encoded on-disk super block */
|
|
Packit Service |
d40955 |
byte *encodedSuperBlock;
|
|
Packit Service |
d40955 |
/** The release version number loaded from the volume */
|
|
Packit Service |
d40955 |
ReleaseVersionNumber loadedReleaseVersion;
|
|
Packit Service |
d40955 |
/** Whether this super block may not be written */
|
|
Packit Service |
d40955 |
bool unwriteable;
|
|
Packit Service |
d40955 |
};
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
enum {
|
|
Packit Service |
d40955 |
SUPER_BLOCK_FIXED_SIZE
|
|
Packit Service |
d40955 |
= ENCODED_HEADER_SIZE + sizeof(ReleaseVersionNumber) + CHECKSUM_SIZE,
|
|
Packit Service |
d40955 |
MAX_COMPONENT_DATA_SIZE = VDO_SECTOR_SIZE - SUPER_BLOCK_FIXED_SIZE,
|
|
Packit Service |
d40955 |
};
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
static const Header SUPER_BLOCK_HEADER_12_0 = {
|
|
Packit Service |
d40955 |
.id = SUPER_BLOCK,
|
|
Packit Service |
d40955 |
.version = {
|
|
Packit Service |
d40955 |
.majorVersion = 12,
|
|
Packit Service |
d40955 |
.minorVersion = 0,
|
|
Packit Service |
d40955 |
},
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// This is the minimum size, if the super block contains no components.
|
|
Packit Service |
d40955 |
.size = SUPER_BLOCK_FIXED_SIZE - ENCODED_HEADER_SIZE,
|
|
Packit Service |
d40955 |
};
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Allocate a super block. Callers must free the allocated super block even
|
|
Packit Service |
d40955 |
* on error.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param layer The physical layer which holds the super block on disk
|
|
Packit Service |
d40955 |
* @param superBlockPtr A pointer to hold the new super block
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return VDO_SUCCESS or an error
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result))
|
|
Packit Service |
d40955 |
static int allocateSuperBlock(PhysicalLayer *layer, SuperBlock **superBlockPtr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
int result = ALLOCATE(1, SuperBlock, __func__, superBlockPtr);
|
|
Packit Service |
d40955 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
SuperBlock *superBlock = *superBlockPtr;
|
|
Packit Service |
d40955 |
result = makeBuffer(MAX_COMPONENT_DATA_SIZE, &superBlock->componentBuffer);
|
|
Packit Service |
d40955 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
result = layer->allocateIOBuffer(layer, VDO_BLOCK_SIZE,
|
|
Packit Service |
d40955 |
"encoded super block",
|
|
Packit Service |
d40955 |
(char **) &superBlock->encodedSuperBlock);
|
|
Packit Service |
d40955 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Even though the buffer is a full block, to avoid the potential corruption
|
|
Packit Service |
d40955 |
// from a torn write, the entire encoding must fit in the first sector.
|
|
Packit Service |
d40955 |
result = wrapBuffer(superBlock->encodedSuperBlock, VDO_SECTOR_SIZE, 0,
|
|
Packit Service |
d40955 |
&superBlock->blockBuffer);
|
|
Packit Service |
d40955 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
if (layer->createMetadataVIO == NULL) {
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return createVIO(layer, VIO_TYPE_SUPER_BLOCK, VIO_PRIORITY_METADATA,
|
|
Packit Service |
d40955 |
superBlock, (char *) superBlock->encodedSuperBlock,
|
|
Packit Service |
d40955 |
&superBlock->vio);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int makeSuperBlock(PhysicalLayer *layer, SuperBlock **superBlockPtr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SuperBlock *superBlock;
|
|
Packit Service |
d40955 |
int result = allocateSuperBlock(layer, &superBlock);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
freeSuperBlock(&superBlock);
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// For a new super block, use the current release.
|
|
Packit Service |
d40955 |
superBlock->loadedReleaseVersion = CURRENT_RELEASE_VERSION_NUMBER;
|
|
Packit Service |
d40955 |
*superBlockPtr = superBlock;
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void freeSuperBlock(SuperBlock **superBlockPtr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
if (*superBlockPtr == NULL) {
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
SuperBlock *superBlock = *superBlockPtr;
|
|
Packit Service |
d40955 |
freeBuffer(&superBlock->blockBuffer);
|
|
Packit Service |
d40955 |
freeBuffer(&superBlock->componentBuffer);
|
|
Packit Service |
d40955 |
freeVIO(&superBlock->vio);
|
|
Packit Service |
d40955 |
FREE(superBlock->encodedSuperBlock);
|
|
Packit Service |
d40955 |
FREE(superBlock);
|
|
Packit Service |
d40955 |
*superBlockPtr = NULL;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Encode a super block into its on-disk representation.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param layer The physical layer which implements the checksum
|
|
Packit Service |
d40955 |
* @param superBlock The super block to encode
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return VDO_SUCCESS or an error
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result))
|
|
Packit Service |
d40955 |
static int encodeSuperBlock(PhysicalLayer *layer, SuperBlock *superBlock)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
Buffer *buffer = superBlock->blockBuffer;
|
|
Packit Service |
d40955 |
int result = resetBufferEnd(buffer, 0);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
size_t componentDataSize = contentLength(superBlock->componentBuffer);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Encode the header.
|
|
Packit Service |
d40955 |
Header header = SUPER_BLOCK_HEADER_12_0;
|
|
Packit Service |
d40955 |
header.size += componentDataSize;
|
|
Packit Service |
d40955 |
result = encodeHeader(&header, buffer);
|
|
Packit Service |
d40955 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Encode the loaded release version.
|
|
Packit Service |
d40955 |
result = putUInt32LEIntoBuffer(buffer, superBlock->loadedReleaseVersion);
|
|
Packit Service |
d40955 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Copy the already-encoded component data.
|
|
Packit Service |
d40955 |
result = putBytes(buffer, componentDataSize,
|
|
Packit Service |
d40955 |
getBufferContents(superBlock->componentBuffer));
|
|
Packit Service |
d40955 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Compute and encode the checksum.
|
|
Packit Service |
d40955 |
CRC32Checksum checksum = layer->updateCRC32(INITIAL_CHECKSUM,
|
|
Packit Service |
d40955 |
superBlock->encodedSuperBlock,
|
|
Packit Service |
d40955 |
contentLength(buffer));
|
|
Packit Service |
d40955 |
result = putUInt32LEIntoBuffer(buffer, checksum);
|
|
Packit Service |
d40955 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return UDS_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int saveSuperBlock(PhysicalLayer *layer,
|
|
Packit Service |
d40955 |
SuperBlock *superBlock,
|
|
Packit Service |
d40955 |
PhysicalBlockNumber superBlockOffset)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
int result = encodeSuperBlock(layer, superBlock);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return layer->writer(layer, superBlockOffset, 1,
|
|
Packit Service |
d40955 |
(char *) superBlock->encodedSuperBlock, NULL);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Finish the parent of a super block load or save operation. This
|
|
Packit Service |
d40955 |
* callback is registered in saveSuperBlockAsync() and loadSuperBlockAsync.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The super block VIO
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void finishSuperBlockParent(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SuperBlock *superBlock = completion->parent;
|
|
Packit Service |
d40955 |
VDOCompletion *parent = superBlock->parent;
|
|
Packit Service |
d40955 |
superBlock->parent = NULL;
|
|
Packit Service |
d40955 |
finishCompletion(parent, completion->result);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Log a super block save error. This error handler is registered in
|
|
Packit Service |
d40955 |
* saveSuperBlockAsync().
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The super block VIO
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void handleSaveError(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
logErrorWithStringError(completion->result, "super block save failed");
|
|
Packit Service |
d40955 |
/*
|
|
Packit Service |
d40955 |
* Mark the super block as unwritable so that we won't attempt to write it
|
|
Packit Service |
d40955 |
* again. This avoids the case where a growth attempt fails writing the
|
|
Packit Service |
d40955 |
* super block with the new size, but the subsequent attempt to write out
|
|
Packit Service |
d40955 |
* the read-only state succeeds. In this case, writes which happened just
|
|
Packit Service |
d40955 |
* before the suspend would not be visible if the VDO is restarted without
|
|
Packit Service |
d40955 |
* rebuilding, but, after a read-only rebuild, the effects of those writes
|
|
Packit Service |
d40955 |
* would reappear.
|
|
Packit Service |
d40955 |
*/
|
|
Packit Service |
d40955 |
((SuperBlock *) completion->parent)->unwriteable = true;
|
|
Packit Service |
d40955 |
completion->callback(completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void saveSuperBlockAsync(SuperBlock *superBlock,
|
|
Packit Service |
d40955 |
PhysicalBlockNumber superBlockOffset,
|
|
Packit Service |
d40955 |
VDOCompletion *parent)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
if (superBlock->unwriteable) {
|
|
Packit Service |
d40955 |
finishCompletion(parent, VDO_READ_ONLY);
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
if (superBlock->parent != NULL) {
|
|
Packit Service |
d40955 |
finishCompletion(parent, VDO_COMPONENT_BUSY);
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
PhysicalLayer *layer = parent->layer;
|
|
Packit Service |
d40955 |
int result = encodeSuperBlock(layer, superBlock);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
finishCompletion(parent, result);
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
superBlock->parent = parent;
|
|
Packit Service |
d40955 |
superBlock->vio->completion.callbackThreadID = parent->callbackThreadID;
|
|
Packit Service |
d40955 |
launchWriteMetadataVIOWithFlush(superBlock->vio, superBlockOffset,
|
|
Packit Service |
d40955 |
finishSuperBlockParent, handleSaveError,
|
|
Packit Service |
d40955 |
true, true);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Decode a super block from its on-disk representation.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param layer The physical layer which implements the checksum
|
|
Packit Service |
d40955 |
* @param superBlock The super block to decode
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return VDO_SUCCESS or an error
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result))
|
|
Packit Service |
d40955 |
static int decodeSuperBlock(PhysicalLayer *layer, SuperBlock *superBlock)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
// Reset the block buffer to start decoding the entire first sector.
|
|
Packit Service |
d40955 |
Buffer *buffer = superBlock->blockBuffer;
|
|
Packit Service |
d40955 |
clearBuffer(buffer);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Decode and validate the header.
|
|
Packit Service |
d40955 |
Header header;
|
|
Packit Service |
d40955 |
int result = decodeHeader(buffer, &header);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
result = validateHeader(&SUPER_BLOCK_HEADER_12_0, &header, false, __func__);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
if (header.size > contentLength(buffer)) {
|
|
Packit Service |
d40955 |
// We can't check release version or checksum until we know the content
|
|
Packit Service |
d40955 |
// size, so we have to assume a version mismatch on unexpected values.
|
|
Packit Service |
d40955 |
return logErrorWithStringError(VDO_UNSUPPORTED_VERSION,
|
|
Packit Service |
d40955 |
"super block contents too large: %zu",
|
|
Packit Service |
d40955 |
header.size);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Restrict the buffer to the actual payload bytes that remain.
|
|
Packit Service |
d40955 |
result = resetBufferEnd(buffer, uncompactedAmount(buffer) + header.size);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Decode and store the release version number. It will be checked when the
|
|
Packit Service |
d40955 |
// VDO master version is decoded and validated.
|
|
Packit Service |
d40955 |
result = getUInt32LEFromBuffer(buffer, &superBlock->loadedReleaseVersion);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// The component data is all the rest, except for the checksum.
|
|
Packit Service |
d40955 |
size_t componentDataSize = contentLength(buffer) - sizeof(CRC32Checksum);
|
|
Packit Service |
d40955 |
result = putBuffer(superBlock->componentBuffer, buffer, componentDataSize);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Checksum everything up to but not including the saved checksum itself.
|
|
Packit Service |
d40955 |
CRC32Checksum checksum = layer->updateCRC32(INITIAL_CHECKSUM,
|
|
Packit Service |
d40955 |
superBlock->encodedSuperBlock,
|
|
Packit Service |
d40955 |
uncompactedAmount(buffer));
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Decode and verify the saved checksum.
|
|
Packit Service |
d40955 |
CRC32Checksum savedChecksum;
|
|
Packit Service |
d40955 |
result = getUInt32LEFromBuffer(buffer, &savedChecksum);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
result = ASSERT(contentLength(buffer) == 0,
|
|
Packit Service |
d40955 |
"must have decoded entire superblock payload");
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return ((checksum != savedChecksum) ? VDO_CHECKSUM_MISMATCH : VDO_SUCCESS);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int loadSuperBlock(PhysicalLayer *layer,
|
|
Packit Service |
d40955 |
PhysicalBlockNumber superBlockOffset,
|
|
Packit Service |
d40955 |
SuperBlock **superBlockPtr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SuperBlock *superBlock = NULL;
|
|
Packit Service |
d40955 |
int result = allocateSuperBlock(layer, &superBlock);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
freeSuperBlock(&superBlock);
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
result = layer->reader(layer, superBlockOffset, 1,
|
|
Packit Service |
d40955 |
(char *) superBlock->encodedSuperBlock, NULL);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
freeSuperBlock(&superBlock);
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
result = decodeSuperBlock(layer, superBlock);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
freeSuperBlock(&superBlock);
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
*superBlockPtr = superBlock;
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Continue after loading the super block. This callback is registered
|
|
Packit Service |
d40955 |
* in loadSuperBlockAsync().
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The super block VIO
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void finishReadingSuperBlock(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SuperBlock *superBlock = completion->parent;
|
|
Packit Service |
d40955 |
VDOCompletion *parent = superBlock->parent;
|
|
Packit Service |
d40955 |
superBlock->parent = NULL;
|
|
Packit Service |
d40955 |
finishCompletion(parent, decodeSuperBlock(completion->layer, superBlock));
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void loadSuperBlockAsync(VDOCompletion *parent,
|
|
Packit Service |
d40955 |
PhysicalBlockNumber superBlockOffset,
|
|
Packit Service |
d40955 |
SuperBlock **superBlockPtr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
PhysicalLayer *layer = parent->layer;
|
|
Packit Service |
d40955 |
SuperBlock *superBlock = NULL;
|
|
Packit Service |
d40955 |
int result = allocateSuperBlock(layer, &superBlock);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
freeSuperBlock(&superBlock);
|
|
Packit Service |
d40955 |
finishCompletion(parent, result);
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
*superBlockPtr = superBlock;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
superBlock->parent = parent;
|
|
Packit Service |
d40955 |
superBlock->vio->completion.callbackThreadID = parent->callbackThreadID;
|
|
Packit Service |
d40955 |
launchReadMetadataVIO(superBlock->vio, superBlockOffset,
|
|
Packit Service |
d40955 |
finishReadingSuperBlock, finishSuperBlockParent);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
Buffer *getComponentBuffer(SuperBlock *superBlock)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
return superBlock->componentBuffer;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
ReleaseVersionNumber getLoadedReleaseVersion(const SuperBlock *superBlock)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
return superBlock->loadedReleaseVersion;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
size_t getFixedSuperBlockSize(void)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
return SUPER_BLOCK_FIXED_SIZE;
|
|
Packit Service |
d40955 |
}
|