|
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/vdoLoad.c#17 $
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "vdoLoad.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "logger.h"
|
|
Packit Service |
75d76b |
#include "memoryAlloc.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "adminCompletion.h"
|
|
Packit Service |
75d76b |
#include "blockMap.h"
|
|
Packit Service |
75d76b |
#include "completion.h"
|
|
Packit Service |
75d76b |
#include "constants.h"
|
|
Packit Service |
75d76b |
#include "hashZone.h"
|
|
Packit Service |
75d76b |
#include "header.h"
|
|
Packit Service |
75d76b |
#include "logicalZone.h"
|
|
Packit Service |
75d76b |
#include "physicalZone.h"
|
|
Packit Service |
75d76b |
#include "readOnlyRebuild.h"
|
|
Packit Service |
75d76b |
#include "recoveryJournal.h"
|
|
Packit Service |
75d76b |
#include "releaseVersions.h"
|
|
Packit Service |
75d76b |
#include "slabDepot.h"
|
|
Packit Service |
75d76b |
#include "slabSummary.h"
|
|
Packit Service |
75d76b |
#include "threadConfig.h"
|
|
Packit Service |
75d76b |
#include "types.h"
|
|
Packit Service |
75d76b |
#include "vdoInternal.h"
|
|
Packit Service |
75d76b |
#include "vdoRecovery.h"
|
|
Packit Service |
75d76b |
#include "volumeGeometry.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Extract the VDO from an AdminCompletion, checking that the current operation
|
|
Packit Service |
75d76b |
* is a load.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The AdminCompletion's sub-task completion
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @return The VDO
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static inline VDO *vdoFromLoadSubTask(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return vdoFromAdminSubTask(completion, ADMIN_OPERATION_LOAD);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Finish aborting a load now that any entry to read-only mode is complete.
|
|
Packit Service |
75d76b |
* This callback is registered in abortLoad().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void finishAborting(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
vdo->closeRequired = false;
|
|
Packit Service |
75d76b |
finishParentCallback(completion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Make sure the recovery journal is closed when aborting a load.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void closeRecoveryJournalForAbort(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
prepareAdminSubTask(vdo, finishAborting, finishAborting);
|
|
Packit Service |
75d76b |
drainRecoveryJournal(vdo->recoveryJournal, ADMIN_STATE_SAVING, completion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Clean up after an error loading a VDO. This error handler is set in
|
|
Packit Service |
75d76b |
* loadCallback() and loadVDOComponents().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void abortLoad(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
logErrorWithStringError(completion->result, "aborting load");
|
|
Packit Service |
75d76b |
if (vdo->readOnlyNotifier == NULL) {
|
|
Packit Service |
75d76b |
// There are no threads, so we're done
|
|
Packit Service |
75d76b |
finishParentCallback(completion);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Preserve the error.
|
|
Packit Service |
75d76b |
setCompletionResult(completion->parent, completion->result);
|
|
Packit Service |
75d76b |
if (vdo->recoveryJournal == NULL) {
|
|
Packit Service |
75d76b |
prepareAdminSubTask(vdo, finishAborting, finishAborting);
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
prepareAdminSubTaskOnThread(vdo, closeRecoveryJournalForAbort,
|
|
Packit Service |
75d76b |
closeRecoveryJournalForAbort,
|
|
Packit Service |
75d76b |
getJournalZoneThread(getThreadConfig(vdo)));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
waitUntilNotEnteringReadOnlyMode(vdo->readOnlyNotifier, completion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Wait for the VDO to be in read-only mode.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void waitForReadOnlyMode(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
prepareToFinishParent(completion, completion->parent);
|
|
Packit Service |
75d76b |
setCompletionResult(completion, VDO_READ_ONLY);
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
waitUntilNotEnteringReadOnlyMode(vdo->readOnlyNotifier, completion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Finish loading the VDO after an error, but leave it in read-only
|
|
Packit Service |
75d76b |
* mode. This error handler is set in makeDirty(), scrubSlabs(), and
|
|
Packit Service |
75d76b |
* loadVDOComponents().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void continueLoadReadOnly(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
logErrorWithStringError(completion->result,
|
|
Packit Service |
75d76b |
"Entering read-only mode due to load error");
|
|
Packit Service |
75d76b |
enterReadOnlyMode(vdo->readOnlyNotifier, completion->result);
|
|
Packit Service |
75d76b |
waitForReadOnlyMode(completion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Exit recovery mode if necessary now that online slab scrubbing or loading
|
|
Packit Service |
75d76b |
* is complete. This callback is registrered in scrubSlabs().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The slab scrubber completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void finishScrubbingSlabs(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = completion->parent;
|
|
Packit Service |
75d76b |
assertOnAdminThread(vdo, __func__);
|
|
Packit Service |
75d76b |
if (inRecoveryMode(vdo)) {
|
|
Packit Service |
75d76b |
leaveRecoveryMode(vdo);
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
logInfo("VDO commencing normal operation");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Handle an error scrubbing or loading all slabs after the VDO has come
|
|
Packit Service |
75d76b |
* online. This error handler is registered in scrubSlabs().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The slab scrubber completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void handleScrubAllError(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = completion->parent;
|
|
Packit Service |
75d76b |
enterReadOnlyMode(vdo->readOnlyNotifier, completion->result);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Initiate slab scrubbing if necessary. This callback is registered in
|
|
Packit Service |
75d76b |
* prepareToComeOnline().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void scrubSlabs(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
if (!hasUnrecoveredSlabs(vdo->depot)) {
|
|
Packit Service |
75d76b |
finishParentCallback(completion);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (requiresRecovery(vdo)) {
|
|
Packit Service |
75d76b |
enterRecoveryMode(vdo);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
prepareAdminSubTask(vdo, finishParentCallback, continueLoadReadOnly);
|
|
Packit Service |
75d76b |
scrubAllUnrecoveredSlabs(vdo->depot, vdo, finishScrubbingSlabs,
|
|
Packit Service |
75d76b |
handleScrubAllError, 0, completion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* This is the error handler for slab scrubbing. It is registered in
|
|
Packit Service |
75d76b |
* prepareToComeOnline().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void handleScrubbingError(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
enterReadOnlyMode(vdo->readOnlyNotifier, completion->result);
|
|
Packit Service |
75d76b |
waitForReadOnlyMode(completion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* This is the callback after the super block is written. It prepares the block
|
|
Packit Service |
75d76b |
* allocator to come online and start allocating. It is registered in
|
|
Packit Service |
75d76b |
* makeDirty().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void prepareToComeOnline(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
SlabDepotLoadType loadType = NORMAL_LOAD;
|
|
Packit Service |
75d76b |
if (requiresReadOnlyRebuild(vdo)) {
|
|
Packit Service |
75d76b |
loadType = REBUILD_LOAD;
|
|
Packit Service |
75d76b |
} else if (requiresRecovery(vdo)) {
|
|
Packit Service |
75d76b |
loadType = RECOVERY_LOAD;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
initializeBlockMapFromJournal(vdo->blockMap, vdo->recoveryJournal);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
prepareAdminSubTask(vdo, scrubSlabs, handleScrubbingError);
|
|
Packit Service |
75d76b |
prepareToAllocate(vdo->depot, loadType, completion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Mark the super block as dirty now that everything has been loaded or
|
|
Packit Service |
75d76b |
* rebuilt.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void makeDirty(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
if (isReadOnly(vdo->readOnlyNotifier)) {
|
|
Packit Service |
75d76b |
finishCompletion(completion->parent, VDO_READ_ONLY);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
vdo->state = VDO_DIRTY;
|
|
Packit Service |
75d76b |
prepareAdminSubTask(vdo, prepareToComeOnline, continueLoadReadOnly);
|
|
Packit Service |
75d76b |
saveVDOComponentsAsync(vdo, completion);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Callback to do the destructive parts of a load now that the new VDO device
|
|
Packit Service |
75d76b |
* is being resumed.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void loadCallback(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
assertOnAdminThread(vdo, __func__);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Prepare the recovery journal for new entries.
|
|
Packit Service |
75d76b |
openRecoveryJournal(vdo->recoveryJournal, vdo->depot, vdo->blockMap);
|
|
Packit Service |
75d76b |
vdo->closeRequired = true;
|
|
Packit Service |
75d76b |
if (isReadOnly(vdo->readOnlyNotifier)) {
|
|
Packit Service |
75d76b |
// In read-only mode we don't use the allocator and it may not
|
|
Packit Service |
75d76b |
// even be readable, so use the default structure.
|
|
Packit Service |
75d76b |
finishCompletion(completion->parent, VDO_READ_ONLY);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (requiresReadOnlyRebuild(vdo)) {
|
|
Packit Service |
75d76b |
prepareAdminSubTask(vdo, makeDirty, abortLoad);
|
|
Packit Service |
75d76b |
launchRebuild(vdo, completion);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (requiresRebuild(vdo)) {
|
|
Packit Service |
75d76b |
prepareAdminSubTask(vdo, makeDirty, continueLoadReadOnly);
|
|
Packit Service |
75d76b |
launchRecovery(vdo, completion);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
prepareAdminSubTask(vdo, makeDirty, continueLoadReadOnly);
|
|
Packit Service |
75d76b |
loadSlabDepot(vdo->depot,
|
|
Packit Service |
75d76b |
(wasNew(vdo) ? ADMIN_STATE_FORMATTING : ADMIN_STATE_LOADING),
|
|
Packit Service |
75d76b |
completion, NULL);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int performVDOLoad(VDO *vdo)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return performAdminOperation(vdo, ADMIN_OPERATION_LOAD, NULL, loadCallback,
|
|
Packit Service |
75d76b |
loadCallback);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
__attribute__((warn_unused_result))
|
|
Packit Service |
75d76b |
static int startVDODecode(VDO *vdo, bool validateConfig)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = validateVDOVersion(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = decodeVDOComponent(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (!validateConfig) {
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (vdo->loadConfig.nonce != vdo->nonce) {
|
|
Packit Service |
75d76b |
return logErrorWithStringError(VDO_BAD_NONCE, "Geometry nonce %" PRIu64
|
|
Packit Service |
75d76b |
" does not match superblock nonce %llu",
|
|
Packit Service |
75d76b |
vdo->loadConfig.nonce, vdo->nonce);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
BlockCount blockCount = vdo->layer->getBlockCount(vdo->layer);
|
|
Packit Service |
75d76b |
return validateVDOConfig(&vdo->config, blockCount, true);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
__attribute__((warn_unused_result))
|
|
Packit Service |
75d76b |
static int finishVDODecode(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 = decodeRecoveryJournal(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 = decodeSlabDepot(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 = decodeBlockMap(buffer, vdo->config.logicalBlocks, threadConfig,
|
|
Packit Service |
75d76b |
&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 |
* Decode the component data portion of a super block and fill in the
|
|
Packit Service |
75d76b |
* corresponding portions of the VDO being loaded. This will also allocate the
|
|
Packit Service |
75d76b |
* recovery journal and slab depot. If this method is called with an
|
|
Packit Service |
75d76b |
* asynchronous layer (i.e. a thread config which specifies at least one base
|
|
Packit Service |
75d76b |
* thread), the block map and packer will be constructed as well.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param vdo The VDO being loaded
|
|
Packit Service |
75d76b |
* @param validateConfig Whether to validate the config
|
|
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 decodeVDO(VDO *vdo, bool validateConfig)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = startVDODecode(vdo, validateConfig);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
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 |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = enableReadOnlyEntry(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
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 |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = finishVDODecode(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = makeFlusher(vdo);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
BlockCount maximumAge = getConfiguredBlockMapMaximumAge(vdo);
|
|
Packit Service |
75d76b |
BlockCount journalLength
|
|
Packit Service |
75d76b |
= getRecoveryJournalLength(vdo->config.recoveryJournalSize);
|
|
Packit Service |
75d76b |
if ((maximumAge > (journalLength / 2)) || (maximumAge < 1)) {
|
|
Packit Service |
75d76b |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
result = makeBlockMapCaches(vdo->blockMap, vdo->layer,
|
|
Packit Service |
75d76b |
vdo->readOnlyNotifier, vdo->recoveryJournal,
|
|
Packit Service |
75d76b |
vdo->nonce, getConfiguredCacheSize(vdo),
|
|
Packit Service |
75d76b |
maximumAge);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = ALLOCATE(threadConfig->hashZoneCount, HashZone *, __func__,
|
|
Packit Service |
75d76b |
&vdo->hashZones);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
for (ZoneCount zone = 0; zone < threadConfig->hashZoneCount; zone++) {
|
|
Packit Service |
75d76b |
result = makeHashZone(vdo, zone, &vdo->hashZones[zone]);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = makeLogicalZones(vdo, &vdo->logicalZones);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = ALLOCATE(threadConfig->physicalZoneCount, PhysicalZone *, __func__,
|
|
Packit Service |
75d76b |
&vdo->physicalZones);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
for (ZoneCount zone = 0; zone < threadConfig->physicalZoneCount; zone++) {
|
|
Packit Service |
75d76b |
result = makePhysicalZone(vdo, zone, &vdo->physicalZones[zone]);
|
|
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 makePacker(vdo->layer, DEFAULT_PACKER_INPUT_BINS,
|
|
Packit Service |
75d76b |
DEFAULT_PACKER_OUTPUT_BINS, threadConfig, &vdo->packer);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Load the components of a VDO. This is the super block load callback
|
|
Packit Service |
75d76b |
* set by loadCallback().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void loadVDOComponents(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
prepareCompletion(completion, finishParentCallback, abortLoad,
|
|
Packit Service |
75d76b |
completion->callbackThreadID, completion->parent);
|
|
Packit Service |
75d76b |
finishCompletion(completion, decodeVDO(vdo, true));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Callback to initiate a pre-load, registered in prepareToLoadVDO().
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* @param completion The sub-task completion
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void preLoadCallback(VDOCompletion *completion)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo = vdoFromLoadSubTask(completion);
|
|
Packit Service |
75d76b |
assertOnAdminThread(vdo, __func__);
|
|
Packit Service |
75d76b |
prepareAdminSubTask(vdo, loadVDOComponents, abortLoad);
|
|
Packit Service |
75d76b |
loadSuperBlockAsync(completion, getFirstBlockOffset(vdo), &vdo->superBlock);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int prepareToLoadVDO(VDO *vdo, const VDOLoadConfig *loadConfig)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
vdo->loadConfig = *loadConfig;
|
|
Packit Service |
75d76b |
return performAdminOperation(vdo, ADMIN_OPERATION_LOAD, NULL,
|
|
Packit Service |
75d76b |
preLoadCallback, preLoadCallback);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
__attribute__((warn_unused_result))
|
|
Packit Service |
75d76b |
static int decodeSynchronousVDO(VDO *vdo, bool validateConfig)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
int result = startVDODecode(vdo, validateConfig);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
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 |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return finishVDODecode(vdo);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int loadVDOSuperblock(PhysicalLayer *layer,
|
|
Packit Service |
75d76b |
VolumeGeometry *geometry,
|
|
Packit Service |
75d76b |
bool validateConfig,
|
|
Packit Service |
75d76b |
VDODecoder *decoder,
|
|
Packit Service |
75d76b |
VDO **vdoPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
VDO *vdo;
|
|
Packit Service |
75d76b |
int 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 |
setLoadConfigFromGeometry(geometry, &vdo->loadConfig);
|
|
Packit Service |
75d76b |
result = loadSuperBlock(layer, getFirstBlockOffset(vdo), &vdo->superBlock);
|
|
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 = ((decoder == NULL)
|
|
Packit Service |
75d76b |
? decodeSynchronousVDO(vdo, validateConfig)
|
|
Packit Service |
75d76b |
: decoder(vdo, validateConfig));
|
|
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 |
*vdoPtr = vdo;
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int loadVDO(PhysicalLayer *layer,
|
|
Packit Service |
75d76b |
bool validateConfig,
|
|
Packit Service |
75d76b |
VDODecoder *decoder,
|
|
Packit Service |
75d76b |
VDO **vdoPtr)
|
|
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 |
return loadVDOSuperblock(layer, &geometry, validateConfig, decoder, vdoPtr);
|
|
Packit Service |
75d76b |
}
|