|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
75d76b |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
75d76b |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
75d76b |
* of the License, or (at your option) any later version.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
75d76b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
75d76b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
75d76b |
* GNU General Public License for more details.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
75d76b |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
75d76b |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
75d76b |
* 02110-1301, USA.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/volumeGeometry.c#10 $
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "volumeGeometry.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "buffer.h"
|
|
Packit Service |
75d76b |
#include "logger.h"
|
|
Packit Service |
75d76b |
#include "memoryAlloc.h"
|
|
Packit Service |
75d76b |
#include "numeric.h"
|
|
Packit Service |
75d76b |
#include "permassert.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "constants.h"
|
|
Packit Service |
75d76b |
#include "header.h"
|
|
Packit Service |
75d76b |
#include "physicalLayer.h"
|
|
Packit Service |
75d76b |
#include "releaseVersions.h"
|
|
Packit Service |
75d76b |
#include "statusCodes.h"
|
|
Packit Service |
75d76b |
#include "types.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
enum {
|
|
Packit Service |
75d76b |
GEOMETRY_BLOCK_LOCATION = 0,
|
|
Packit Service |
75d76b |
MAGIC_NUMBER_SIZE = 8,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
typedef struct {
|
|
Packit Service |
75d76b |
char magicNumber[MAGIC_NUMBER_SIZE];
|
|
Packit Service |
75d76b |
Header header;
|
|
Packit Service |
75d76b |
VolumeGeometry geometry;
|
|
Packit Service |
75d76b |
CRC32Checksum checksum;
|
|
Packit Service |
75d76b |
} __attribute__((packed)) GeometryBlock;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
static const Header GEOMETRY_BLOCK_HEADER_4_0 = {
|
|
Packit Service |
75d76b |
.id = GEOMETRY_BLOCK,
|
|
Packit Service |
75d76b |
.version = {
|
|
Packit Service |
75d76b |
.majorVersion = 4,
|
|
Packit Service |
75d76b |
.minorVersion = 0,
|
|
Packit Service |
75d76b |
},
|
|
Packit Service |
75d76b |
// Note: this size isn't just the payload size following the header, like it
|
|
Packit Service |
75d76b |
// is everywhere else in VDO.
|
|
Packit Service |
75d76b |
.size = sizeof(GeometryBlock),
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
static const byte MAGIC_NUMBER[MAGIC_NUMBER_SIZE + 1] = "dmvdo001";
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
static const ReleaseVersionNumber COMPATIBLE_RELEASE_VERSIONS[] = {
|
|
Packit Service |
75d76b |
MAGNESIUM_RELEASE_VERSION_NUMBER,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Determine whether the supplied release version can be understood by
|
|
Packit Service |
75d76b |
* the VDO code.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param version The release version number to check
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return True if the given version can be loaded.
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static inline bool isLoadableReleaseVersion(ReleaseVersionNumber version)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (version == CURRENT_RELEASE_VERSION_NUMBER) {
|
|
Packit Service |
75d76b |
return true;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
for (unsigned int i = 0; i < COUNT_OF(COMPATIBLE_RELEASE_VERSIONS); i++) {
|
|
Packit Service |
75d76b |
if (version == COMPATIBLE_RELEASE_VERSIONS[i]) {
|
|
Packit Service |
75d76b |
return true;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return false;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Decode the on-disk representation of an index configuration from a buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
75d76b |
* @param config The structure to receive the decoded fields
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return UDS_SUCCESS or an error
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int decodeIndexConfig(Buffer *buffer, IndexConfig *config)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
uint32_t mem;
|
|
Packit Service |
75d76b |
int result = getUInt32LEFromBuffer(buffer, &mem;;
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
uint32_t checkpointFrequency;
|
|
Packit Service |
75d76b |
result = getUInt32LEFromBuffer(buffer, &checkpointFrequency);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
bool sparse;
|
|
Packit Service |
75d76b |
result = getBoolean(buffer, &sparse);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*config = (IndexConfig) {
|
|
Packit Service |
75d76b |
.mem = mem,
|
|
Packit Service |
75d76b |
.checkpointFrequency = checkpointFrequency,
|
|
Packit Service |
75d76b |
.sparse = sparse,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Encode the on-disk representation of an index configuration into a buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param config The index configuration to encode
|
|
Packit Service |
75d76b |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return UDS_SUCCESS or an error
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int encodeIndexConfig(const IndexConfig *config, Buffer *buffer)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = putUInt32LEIntoBuffer(buffer, config->mem);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = putUInt32LEIntoBuffer(buffer, config->checkpointFrequency);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return putBoolean(buffer, config->sparse);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Decode the on-disk representation of a volume region from a buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
75d76b |
* @param region The structure to receive the decoded fields
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return UDS_SUCCESS or an error
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int decodeVolumeRegion(Buffer *buffer, VolumeRegion *region)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VolumeRegionID id;
|
|
Packit Service |
75d76b |
int result = getUInt32LEFromBuffer(buffer, &id;;
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
PhysicalBlockNumber startBlock;
|
|
Packit Service |
75d76b |
result = getUInt64LEFromBuffer(buffer, &startBlock);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*region = (VolumeRegion) {
|
|
Packit Service |
75d76b |
.id = id,
|
|
Packit Service |
75d76b |
.startBlock = startBlock,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Encode the on-disk representation of a volume region into a buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param region The region to encode
|
|
Packit Service |
75d76b |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return UDS_SUCCESS or an error
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int encodeVolumeRegion(const VolumeRegion *region, Buffer *buffer)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = putUInt32LEIntoBuffer(buffer, region->id);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return putUInt64LEIntoBuffer(buffer, region->startBlock);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Decode the on-disk representation of a volume geometry from a buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
75d76b |
* @param geometry The structure to receive the decoded fields
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return UDS_SUCCESS or an error
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int decodeVolumeGeometry(Buffer *buffer, VolumeGeometry *geometry)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
ReleaseVersionNumber releaseVersion;
|
|
Packit Service |
75d76b |
int result = getUInt32LEFromBuffer(buffer, &releaseVersion);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
Nonce nonce;
|
|
Packit Service |
75d76b |
result = getUInt64LEFromBuffer(buffer, &nonce);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
geometry->releaseVersion = releaseVersion;
|
|
Packit Service |
75d76b |
geometry->nonce = nonce;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = getBytesFromBuffer(buffer, sizeof(UUID), geometry->uuid);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
for (VolumeRegionID id = 0; id < VOLUME_REGION_COUNT; id++) {
|
|
Packit Service |
75d76b |
result = decodeVolumeRegion(buffer, &geometry->regions[id]);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return decodeIndexConfig(buffer, &geometry->indexConfig);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Encode the on-disk representation of a volume geometry into a buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param geometry The geometry to encode
|
|
Packit Service |
75d76b |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return UDS_SUCCESS or an error
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int encodeVolumeGeometry(const VolumeGeometry *geometry, Buffer *buffer)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = putUInt32LEIntoBuffer(buffer, geometry->releaseVersion);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = putUInt64LEIntoBuffer(buffer, geometry->nonce);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = putBytes(buffer, sizeof(UUID), geometry->uuid);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
for (VolumeRegionID id = 0; id < VOLUME_REGION_COUNT; id++) {
|
|
Packit Service |
75d76b |
result = encodeVolumeRegion(&geometry->regions[id], buffer);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return encodeIndexConfig(&geometry->indexConfig, buffer);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Decode the on-disk representation of a geometry block, up to but not
|
|
Packit Service |
75d76b |
* including the checksum, from a buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param buffer A buffer positioned at the start of the block
|
|
Packit Service |
75d76b |
* @param geometry The structure to receive the decoded volume geometry fields
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return UDS_SUCCESS or an error
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int decodeGeometryBlock(Buffer *buffer, VolumeGeometry *geometry)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (!hasSameBytes(buffer, MAGIC_NUMBER, MAGIC_NUMBER_SIZE)) {
|
|
Packit Service |
75d76b |
return VDO_BAD_MAGIC;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
int result = skipForward(buffer, MAGIC_NUMBER_SIZE);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
Header header;
|
|
Packit Service |
75d76b |
result = decodeHeader(buffer, &header);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = validateHeader(&GEOMETRY_BLOCK_HEADER_4_0, &header, true, __func__);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = decodeVolumeGeometry(buffer, geometry);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Leave the CRC for the caller to decode and verify.
|
|
Packit Service |
75d76b |
return ASSERT(header.size
|
|
Packit Service |
75d76b |
== (uncompactedAmount(buffer) + sizeof(CRC32Checksum)),
|
|
Packit Service |
75d76b |
"should have decoded up to the geometry checksum");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Encode the on-disk representation of a geometry block, up to but not
|
|
Packit Service |
75d76b |
* including the checksum, into a buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param geometry The volume geometry to encode into the block
|
|
Packit Service |
75d76b |
* @param buffer A buffer positioned at the start of the block
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return UDS_SUCCESS or an error
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int encodeGeometryBlock(const VolumeGeometry *geometry, Buffer *buffer)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = putBytes(buffer, MAGIC_NUMBER_SIZE, MAGIC_NUMBER);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = encodeHeader(&GEOMETRY_BLOCK_HEADER_4_0, buffer);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = encodeVolumeGeometry(geometry, buffer);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Leave the CRC for the caller to compute and encode.
|
|
Packit Service |
75d76b |
return ASSERT(GEOMETRY_BLOCK_HEADER_4_0.size
|
|
Packit Service |
75d76b |
== (contentLength(buffer) + sizeof(CRC32Checksum)),
|
|
Packit Service |
75d76b |
"should have decoded up to the geometry checksum");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Allocate a block-size buffer to read the geometry from the physical layer,
|
|
Packit Service |
75d76b |
* read the block, and return the buffer.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param [in] layer The physical layer containing the block to read
|
|
Packit Service |
75d76b |
* @param [out] blockPtr A pointer to receive the allocated buffer
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return VDO_SUCCESS or an error code
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int readGeometryBlock(PhysicalLayer *layer, byte **blockPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = ASSERT(layer->reader != NULL, "Layer must have a sync reader");
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
char *block;
|
|
Packit Service |
75d76b |
result = layer->allocateIOBuffer(layer, VDO_BLOCK_SIZE, "geometry block",
|
|
Packit Service |
75d76b |
&block);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = layer->reader(layer, GEOMETRY_BLOCK_LOCATION, 1, block, NULL);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*blockPtr = (byte *) block;
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int loadVolumeGeometry(PhysicalLayer *layer, VolumeGeometry *geometry)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
byte *block;
|
|
Packit Service |
75d76b |
int result = readGeometryBlock(layer, &block);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
Buffer *buffer;
|
|
Packit Service |
75d76b |
result = wrapBuffer(block, VDO_BLOCK_SIZE, VDO_BLOCK_SIZE, &buffer);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = decodeGeometryBlock(buffer, geometry);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeBuffer(&buffer);
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Checksum everything decoded so far.
|
|
Packit Service |
75d76b |
CRC32Checksum checksum = layer->updateCRC32(INITIAL_CHECKSUM, block,
|
|
Packit Service |
75d76b |
uncompactedAmount(buffer));
|
|
Packit Service |
75d76b |
CRC32Checksum savedChecksum;
|
|
Packit Service |
75d76b |
result = getUInt32LEFromBuffer(buffer, &savedChecksum);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeBuffer(&buffer);
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Finished all decoding. Everything that follows is validation code.
|
|
Packit Service |
75d76b |
freeBuffer(&buffer);
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (!isLoadableReleaseVersion(geometry->releaseVersion)) {
|
|
Packit Service |
75d76b |
return logErrorWithStringError(VDO_UNSUPPORTED_VERSION,
|
|
Packit Service |
75d76b |
"release version %d cannot be loaded",
|
|
Packit Service |
75d76b |
geometry->releaseVersion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return ((checksum == savedChecksum) ? VDO_SUCCESS : VDO_CHECKSUM_MISMATCH);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/************************************************************************/
|
|
Packit Service |
75d76b |
int computeIndexBlocks(IndexConfig *indexConfig, BlockCount *indexBlocksPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UdsConfiguration udsConfiguration = NULL;
|
|
Packit Service |
75d76b |
int result = indexConfigToUdsConfiguration(indexConfig, &udsConfiguration);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
return logErrorWithStringError(result, "error creating index config");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
uint64_t indexBytes;
|
|
Packit Service |
75d76b |
result = udsComputeIndexSize(udsConfiguration, 0, &indexBytes);
|
|
Packit Service |
75d76b |
udsFreeConfiguration(udsConfiguration);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
return logErrorWithStringError(result, "error computing index size");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
BlockCount indexBlocks = indexBytes / VDO_BLOCK_SIZE;
|
|
Packit Service |
75d76b |
if ((((uint64_t) indexBlocks) * VDO_BLOCK_SIZE) != indexBytes) {
|
|
Packit Service |
75d76b |
return logErrorWithStringError(VDO_PARAMETER_MISMATCH, "index size must be"
|
|
Packit Service |
75d76b |
" a multiple of block size %d",
|
|
Packit Service |
75d76b |
VDO_BLOCK_SIZE);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*indexBlocksPtr = indexBlocks;
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int initializeVolumeGeometry(Nonce nonce,
|
|
Packit Service |
75d76b |
UUID uuid,
|
|
Packit Service |
75d76b |
IndexConfig *indexConfig,
|
|
Packit Service |
75d76b |
VolumeGeometry *geometry)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
BlockCount indexSize = 0;
|
|
Packit Service |
75d76b |
if (indexConfig != NULL) {
|
|
Packit Service |
75d76b |
int result = computeIndexBlocks(indexConfig, &indexSize);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*geometry = (VolumeGeometry) {
|
|
Packit Service |
75d76b |
.releaseVersion = CURRENT_RELEASE_VERSION_NUMBER,
|
|
Packit Service |
75d76b |
.nonce = nonce,
|
|
Packit Service |
75d76b |
.regions = {
|
|
Packit Service |
75d76b |
[INDEX_REGION] = {
|
|
Packit Service |
75d76b |
.id = INDEX_REGION,
|
|
Packit Service |
75d76b |
.startBlock = 1,
|
|
Packit Service |
75d76b |
},
|
|
Packit Service |
75d76b |
[DATA_REGION] = {
|
|
Packit Service |
75d76b |
.id = DATA_REGION,
|
|
Packit Service |
75d76b |
.startBlock = 1 + indexSize,
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
memcpy(geometry->uuid, uuid, sizeof(UUID));
|
|
Packit Service |
75d76b |
if (indexSize > 0) {
|
|
Packit Service |
75d76b |
memcpy(&geometry->indexConfig, indexConfig, sizeof(IndexConfig));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int clearVolumeGeometry(PhysicalLayer *layer)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
char *block;
|
|
Packit Service |
75d76b |
int result = layer->allocateIOBuffer(layer, VDO_BLOCK_SIZE, "geometry block",
|
|
Packit Service |
75d76b |
&block);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = layer->writer(layer, GEOMETRY_BLOCK_LOCATION, 1, block, NULL);
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int writeVolumeGeometry(PhysicalLayer *layer, VolumeGeometry *geometry)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
char *block;
|
|
Packit Service |
75d76b |
int result = layer->allocateIOBuffer(layer, VDO_BLOCK_SIZE, "geometry block",
|
|
Packit Service |
75d76b |
&block);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
Buffer *buffer;
|
|
Packit Service |
75d76b |
result = wrapBuffer((byte *) block, VDO_BLOCK_SIZE, 0, &buffer);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = encodeGeometryBlock(geometry, buffer);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeBuffer(&buffer);
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Checksum everything encoded so far and then encode the checksum.
|
|
Packit Service |
75d76b |
CRC32Checksum checksum = layer->updateCRC32(INITIAL_CHECKSUM, (byte *) block,
|
|
Packit Service |
75d76b |
contentLength(buffer));
|
|
Packit Service |
75d76b |
result = putUInt32LEIntoBuffer(buffer, checksum);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeBuffer(&buffer);
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Write it.
|
|
Packit Service |
75d76b |
result = layer->writer(layer, GEOMETRY_BLOCK_LOCATION, 1, block, NULL);
|
|
Packit Service |
75d76b |
freeBuffer(&buffer);
|
|
Packit Service |
75d76b |
FREE(block);
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/************************************************************************/
|
|
Packit Service |
75d76b |
int indexConfigToUdsConfiguration(IndexConfig *indexConfig,
|
|
Packit Service |
75d76b |
UdsConfiguration *udsConfigPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
UdsConfiguration udsConfiguration;
|
|
Packit Service |
75d76b |
int result = udsInitializeConfiguration(&udsConfiguration, indexConfig->mem);
|
|
Packit Service |
75d76b |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
75d76b |
return logErrorWithStringError(result, "error initializing configuration");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
udsConfigurationSetSparse(udsConfiguration, indexConfig->sparse);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*udsConfigPtr = udsConfiguration;
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/************************************************************************/
|
|
Packit Service |
75d76b |
void indexConfigToUdsParameters(IndexConfig *indexConfig,
|
|
Packit Service |
75d76b |
struct uds_parameters *userParams)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
userParams->checkpoint_frequency = indexConfig->checkpointFrequency;
|
|
Packit Service |
75d76b |
}
|