|
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/upgrade.c#6 $
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "upgrade.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "logger.h"
|
|
Packit Service |
75d76b |
#include "memoryAlloc.h"
|
|
Packit Service |
75d76b |
#include "permassert.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "blockMap.h"
|
|
Packit Service |
75d76b |
#include "readOnlyNotifier.h"
|
|
Packit Service |
75d76b |
#include "recoveryJournal.h"
|
|
Packit Service |
75d76b |
#include "releaseVersions.h"
|
|
Packit Service |
75d76b |
#include "slabDepot.h"
|
|
Packit Service |
75d76b |
#include "statusCodes.h"
|
|
Packit Service |
75d76b |
#include "superBlock.h"
|
|
Packit Service |
75d76b |
#include "vdoInternal.h"
|
|
Packit Service |
75d76b |
#include "volumeGeometry.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/* The latest supported Sodium version */
|
|
Packit Service |
75d76b |
/* Commented out because not currently used.
|
|
Packit Service |
75d76b |
* static const VersionNumber SODIUM_MASTER_VERSION_67_0 = {
|
|
Packit Service |
75d76b |
* .majorVersion = 67,
|
|
Packit Service |
75d76b |
* .minorVersion = 0,
|
|
Packit Service |
75d76b |
* };
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/* The component data version for current Sodium */
|
|
Packit Service |
75d76b |
static const VersionNumber SODIUM_COMPONENT_DATA_41_0 = {
|
|
Packit Service |
75d76b |
.majorVersion = 41,
|
|
Packit Service |
75d76b |
.minorVersion = 0,
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Current Sodium's configuration of the VDO component.
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
typedef struct {
|
|
Packit Service |
75d76b |
VDOState state;
|
|
Packit Service |
75d76b |
uint64_t completeRecoveries;
|
|
Packit Service |
75d76b |
uint64_t readOnlyRecoveries;
|
|
Packit Service |
75d76b |
VDOConfig config;
|
|
Packit Service |
75d76b |
Nonce nonce;
|
|
Packit Service |
75d76b |
} __attribute__((packed)) SodiumComponent41_0;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Checks whether the release version loaded in the superblock is the
|
|
Packit Service |
75d76b |
* current VDO version.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param vdo The VDO to validate
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return true if the release version number is the current version
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static bool isCurrentReleaseVersion(VDO *vdo)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
ReleaseVersionNumber loadedVersion
|
|
Packit Service |
75d76b |
= getLoadedReleaseVersion(vdo->superBlock);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return (loadedVersion == CURRENT_RELEASE_VERSION_NUMBER);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Loads the VDO master version into the VDO and checks that the version
|
|
Packit Service |
75d76b |
* can be understood by VDO.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param vdo The VDO to validate
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return VDO_SUCCESS or an error if the loaded version is not supported
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int validateSodiumVersion(VDO *vdo)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = decodeVDOVersion(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (isCurrentReleaseVersion(vdo)) {
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
ReleaseVersionNumber loadedVersion
|
|
Packit Service |
75d76b |
= getLoadedReleaseVersion(vdo->superBlock);
|
|
Packit Service |
75d76b |
return logErrorWithStringError(VDO_UNSUPPORTED_VERSION,
|
|
Packit Service |
75d76b |
"Release version %d, load version %d.%d"
|
|
Packit Service |
75d76b |
" cannot be upgraded", loadedVersion,
|
|
Packit Service |
75d76b |
vdo->loadVersion.majorVersion,
|
|
Packit Service |
75d76b |
vdo->loadVersion.minorVersion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Decode a SodiumComponent41_0.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param buffer The component data buffer
|
|
Packit Service |
75d76b |
* @param component The component structure to decode into
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return VDO_SUCCESS or an error code
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static int decodeSodium41_0Component(Buffer *buffer,
|
|
Packit Service |
75d76b |
SodiumComponent41_0 *component)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return getBytesFromBuffer(buffer, sizeof(*component), component);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Decode the component data for the VDO itself from the component data
|
|
Packit Service |
75d76b |
* buffer in the super block.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param vdo The VDO to decode
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return VDO_SUCCESS or an error
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
__attribute__((warn_unused_result))
|
|
Packit Service |
75d76b |
static int decodeSodiumComponent(VDO *vdo)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
Buffer *buffer = getComponentBuffer(vdo->superBlock);
|
|
Packit Service |
75d76b |
VersionNumber version;
|
|
Packit Service |
75d76b |
int result = decodeVersionNumber(buffer, &version);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
SodiumComponent41_0 component;
|
|
Packit Service |
75d76b |
if (areSameVersion(SODIUM_COMPONENT_DATA_41_0, version)) {
|
|
Packit Service |
75d76b |
result = decodeSodium41_0Component(buffer, &component);
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
return logErrorWithStringError(VDO_UNSUPPORTED_VERSION,
|
|
Packit Service |
75d76b |
"VDO component data version mismatch,"
|
|
Packit Service |
75d76b |
" expected 41.0, got %d.%d",
|
|
Packit Service |
75d76b |
version.majorVersion,
|
|
Packit Service |
75d76b |
version.minorVersion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Copy the decoded component into the VDO structure.
|
|
Packit Service |
75d76b |
vdo->state = component.state;
|
|
Packit Service |
75d76b |
vdo->loadState = component.state;
|
|
Packit Service |
75d76b |
vdo->completeRecoveries = component.completeRecoveries;
|
|
Packit Service |
75d76b |
vdo->readOnlyRecoveries = component.readOnlyRecoveries;
|
|
Packit Service |
75d76b |
vdo->config = component.config;
|
|
Packit Service |
75d76b |
vdo->nonce = component.nonce;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
logInfo("Converted VDO component data version %d.%d",
|
|
Packit Service |
75d76b |
version.majorVersion, version.minorVersion);
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
__attribute__((warn_unused_result))
|
|
Packit Service |
75d76b |
static int finishSodiumDecode(VDO *vdo)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
Buffer *buffer = getComponentBuffer(vdo->superBlock);
|
|
Packit Service |
75d76b |
const ThreadConfig *threadConfig = getThreadConfig(vdo);
|
|
Packit Service |
75d76b |
int result = makeRecoveryJournal(vdo->nonce, vdo->layer,
|
|
Packit Service |
75d76b |
getVDOPartition(vdo->layout,
|
|
Packit Service |
75d76b |
RECOVERY_JOURNAL_PARTITION),
|
|
Packit Service |
75d76b |
vdo->completeRecoveries,
|
|
Packit Service |
75d76b |
vdo->config.recoveryJournalSize,
|
|
Packit Service |
75d76b |
RECOVERY_JOURNAL_TAIL_BUFFER_SIZE,
|
|
Packit Service |
75d76b |
vdo->readOnlyNotifier, threadConfig,
|
|
Packit Service |
75d76b |
&vdo->recoveryJournal);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = decodeSodiumRecoveryJournal(vdo->recoveryJournal, buffer);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = decodeSodiumSlabDepot(buffer, threadConfig, vdo->nonce, vdo->layer,
|
|
Packit Service |
75d76b |
getVDOPartition(vdo->layout,
|
|
Packit Service |
75d76b |
SLAB_SUMMARY_PARTITION),
|
|
Packit Service |
75d76b |
vdo->readOnlyNotifier, vdo->recoveryJournal,
|
|
Packit Service |
75d76b |
&vdo->depot);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = decodeSodiumBlockMap(buffer, vdo->config.logicalBlocks,
|
|
Packit Service |
75d76b |
threadConfig, &vdo->blockMap);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
ASSERT_LOG_ONLY((contentLength(buffer) == 0),
|
|
Packit Service |
75d76b |
"All decoded component data was used");
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int upgradePriorVDO(PhysicalLayer *layer)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VolumeGeometry geometry;
|
|
Packit Service |
75d76b |
int result = loadVolumeGeometry(layer, &geometry);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
VDO *vdo;
|
|
Packit Service |
75d76b |
result = makeVDO(layer, &vdo;;
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = loadSuperBlock(vdo->layer, getDataRegionOffset(geometry),
|
|
Packit Service |
75d76b |
&vdo->superBlock);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
return logErrorWithStringError(result, "Could not load VDO super block");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Load the necessary pieces to save again.
|
|
Packit Service |
75d76b |
result = validateSodiumVersion(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (isCurrentReleaseVersion(vdo)) {
|
|
Packit Service |
75d76b |
logInfo("VDO already up-to-date");
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = decodeSodiumComponent(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (requiresRebuild(vdo)) {
|
|
Packit Service |
75d76b |
// Do not attempt to upgrade a dirty prior version.
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
return logErrorWithStringError(VDO_UNSUPPORTED_VERSION,
|
|
Packit Service |
75d76b |
"Cannot upgrade a dirty VDO.");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = decodeVDOLayout(getComponentBuffer(vdo->superBlock), &vdo->layout);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
const ThreadConfig *threadConfig = getThreadConfig(vdo);
|
|
Packit Service |
75d76b |
result = makeReadOnlyNotifier(inReadOnlyMode(vdo), threadConfig, vdo->layer,
|
|
Packit Service |
75d76b |
&vdo->readOnlyNotifier);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = finishSodiumDecode(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Saving will automatically change the release version to current.
|
|
Packit Service |
75d76b |
result = saveVDOComponents(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
logInfo("Successfully saved upgraded VDO");
|
|
Packit Service |
75d76b |
freeVDO(&vdo;;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|