Blame source/vdo/base/upgrade.c

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
}