|
Packit Service |
b3514a |
/*
|
|
Packit Service |
b3514a |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
b3514a |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
b3514a |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
b3514a |
* of the License, or (at your option) any later version.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
b3514a |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
b3514a |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
b3514a |
* GNU General Public License for more details.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
b3514a |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
b3514a |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
b3514a |
* 02110-1301, USA.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/vdoResize.c#15 $
|
|
Packit Service |
b3514a |
*/
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#include "vdoResize.h"
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#include "logger.h"
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
#include "adminCompletion.h"
|
|
Packit Service |
b3514a |
#include "completion.h"
|
|
Packit Service |
b3514a |
#include "recoveryJournal.h"
|
|
Packit Service |
b3514a |
#include "slabDepot.h"
|
|
Packit Service |
b3514a |
#include "slabSummary.h"
|
|
Packit Service |
b3514a |
#include "vdoInternal.h"
|
|
Packit Service |
b3514a |
#include "vdoLayout.h"
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
typedef enum {
|
|
Packit Service |
b3514a |
GROW_PHYSICAL_PHASE_START = 0,
|
|
Packit Service |
b3514a |
GROW_PHYSICAL_PHASE_COPY_SUMMARY,
|
|
Packit Service |
b3514a |
GROW_PHYSICAL_PHASE_UPDATE_COMPONENTS,
|
|
Packit Service |
b3514a |
GROW_PHYSICAL_PHASE_USE_NEW_SLABS,
|
|
Packit Service |
b3514a |
GROW_PHYSICAL_PHASE_END,
|
|
Packit Service |
b3514a |
GROW_PHYSICAL_PHASE_ERROR,
|
|
Packit Service |
b3514a |
} GrowPhysicalPhase;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
static const char *GROW_PHYSICAL_PHASE_NAMES[] = {
|
|
Packit Service |
b3514a |
"GROW_PHYSICAL_PHASE_START",
|
|
Packit Service |
b3514a |
"GROW_PHYSICAL_PHASE_COPY_SUMMARY",
|
|
Packit Service |
b3514a |
"GROW_PHYSICAL_PHASE_UPDATE_COMPONENTS",
|
|
Packit Service |
b3514a |
"GROW_PHYSICAL_PHASE_USE_NEW_SLABS",
|
|
Packit Service |
b3514a |
"GROW_PHYSICAL_PHASE_END",
|
|
Packit Service |
b3514a |
"GROW_PHYSICAL_PHASE_ERROR",
|
|
Packit Service |
b3514a |
};
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Implements ThreadIDGetterForPhase.
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
__attribute__((warn_unused_result))
|
|
Packit Service |
b3514a |
static ThreadID getThreadIDForPhase(AdminCompletion *adminCompletion)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
return getAdminThread(getThreadConfig(adminCompletion->completion.parent));
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Callback to initiate a grow physical, registered in performGrowPhysical().
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param completion The sub-task completion
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static void growPhysicalCallback(VDOCompletion *completion)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
AdminCompletion *adminCompletion = adminCompletionFromSubTask(completion);
|
|
Packit Service |
b3514a |
assertAdminOperationType(adminCompletion, ADMIN_OPERATION_GROW_PHYSICAL);
|
|
Packit Service |
b3514a |
assertAdminPhaseThread(adminCompletion, __func__, GROW_PHYSICAL_PHASE_NAMES);
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
VDO *vdo = adminCompletion->completion.parent;
|
|
Packit Service |
b3514a |
switch (adminCompletion->phase++) {
|
|
Packit Service |
b3514a |
case GROW_PHYSICAL_PHASE_START:
|
|
Packit Service |
b3514a |
if (isReadOnly(vdo->readOnlyNotifier)) {
|
|
Packit Service |
b3514a |
logErrorWithStringError(VDO_READ_ONLY,
|
|
Packit Service |
b3514a |
"Can't grow physical size of a read-only VDO");
|
|
Packit Service |
b3514a |
setCompletionResult(resetAdminSubTask(completion), VDO_READ_ONLY);
|
|
Packit Service |
b3514a |
break;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
if (startOperationWithWaiter(&vdo->adminState,
|
|
Packit Service |
b3514a |
ADMIN_STATE_SUSPENDED_OPERATION,
|
|
Packit Service |
b3514a |
&adminCompletion->completion, NULL)) {
|
|
Packit Service |
b3514a |
// Copy the journal into the new layout.
|
|
Packit Service |
b3514a |
copyPartition(vdo->layout, RECOVERY_JOURNAL_PARTITION,
|
|
Packit Service |
b3514a |
resetAdminSubTask(completion));
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
case GROW_PHYSICAL_PHASE_COPY_SUMMARY:
|
|
Packit Service |
b3514a |
copyPartition(vdo->layout, SLAB_SUMMARY_PARTITION,
|
|
Packit Service |
b3514a |
resetAdminSubTask(completion));
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
case GROW_PHYSICAL_PHASE_UPDATE_COMPONENTS:
|
|
Packit Service |
b3514a |
vdo->config.physicalBlocks = growVDOLayout(vdo->layout);
|
|
Packit Service |
b3514a |
updateSlabDepotSize(vdo->depot);
|
|
Packit Service |
b3514a |
saveVDOComponentsAsync(vdo, resetAdminSubTask(completion));
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
case GROW_PHYSICAL_PHASE_USE_NEW_SLABS:
|
|
Packit Service |
b3514a |
useNewSlabs(vdo->depot, resetAdminSubTask(completion));
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
case GROW_PHYSICAL_PHASE_END:
|
|
Packit Service |
b3514a |
setSlabSummaryOrigin(getSlabSummary(vdo->depot),
|
|
Packit Service |
b3514a |
getVDOPartition(vdo->layout, SLAB_SUMMARY_PARTITION));
|
|
Packit Service |
b3514a |
setRecoveryJournalPartition(vdo->recoveryJournal,
|
|
Packit Service |
b3514a |
getVDOPartition(vdo->layout,
|
|
Packit Service |
b3514a |
RECOVERY_JOURNAL_PARTITION));
|
|
Packit Service |
b3514a |
break;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
case GROW_PHYSICAL_PHASE_ERROR:
|
|
Packit Service |
b3514a |
enterReadOnlyMode(vdo->readOnlyNotifier, completion->result);
|
|
Packit Service |
b3514a |
break;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
default:
|
|
Packit Service |
b3514a |
setCompletionResult(resetAdminSubTask(completion), UDS_BAD_STATE);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
finishVDOLayoutGrowth(vdo->layout);
|
|
Packit Service |
b3514a |
finishOperationWithResult(&vdo->adminState, completion->result);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Handle an error during the grow physical process.
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param completion The sub-task completion
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static void handleGrowthError(VDOCompletion *completion)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
adminCompletionFromSubTask(completion)->phase = GROW_PHYSICAL_PHASE_ERROR;
|
|
Packit Service |
b3514a |
growPhysicalCallback(completion);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**********************************************************************/
|
|
Packit Service |
b3514a |
int performGrowPhysical(VDO *vdo, BlockCount newPhysicalBlocks)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
BlockCount oldPhysicalBlocks = vdo->config.physicalBlocks;
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
// Skip any noop grows.
|
|
Packit Service |
b3514a |
if (oldPhysicalBlocks == newPhysicalBlocks) {
|
|
Packit Service |
b3514a |
return VDO_SUCCESS;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
if (newPhysicalBlocks != getNextVDOLayoutSize(vdo->layout)) {
|
|
Packit Service |
b3514a |
/*
|
|
Packit Service |
b3514a |
* Either the VDO isn't prepared to grow, or it was prepared to grow
|
|
Packit Service |
b3514a |
* to a different size. Doing this check here relies on the fact that
|
|
Packit Service |
b3514a |
* the call to this method is done under the dmsetup message lock.
|
|
Packit Service |
b3514a |
*/
|
|
Packit Service |
b3514a |
finishVDOLayoutGrowth(vdo->layout);
|
|
Packit Service |
b3514a |
abandonNewSlabs(vdo->depot);
|
|
Packit Service |
b3514a |
return VDO_PARAMETER_MISMATCH;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
// Validate that we are prepared to grow appropriately.
|
|
Packit Service |
b3514a |
BlockCount newDepotSize = getNextBlockAllocatorPartitionSize(vdo->layout);
|
|
Packit Service |
b3514a |
BlockCount preparedDepotSize = getNewDepotSize(vdo->depot);
|
|
Packit Service |
b3514a |
if (preparedDepotSize != newDepotSize) {
|
|
Packit Service |
b3514a |
return VDO_PARAMETER_MISMATCH;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
int result = performAdminOperation(vdo, ADMIN_OPERATION_GROW_PHYSICAL,
|
|
Packit Service |
b3514a |
getThreadIDForPhase, growPhysicalCallback,
|
|
Packit Service |
b3514a |
handleGrowthError);
|
|
Packit Service |
b3514a |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
b3514a |
return result;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
logInfo("Physical block count was %llu, now %llu",
|
|
Packit Service |
b3514a |
oldPhysicalBlocks, newPhysicalBlocks);
|
|
Packit Service |
b3514a |
return VDO_SUCCESS;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**
|
|
Packit Service |
b3514a |
* Callback to check that we're not in recovery mode, used in
|
|
Packit Service |
b3514a |
* prepareToGrowPhysical().
|
|
Packit Service |
b3514a |
*
|
|
Packit Service |
b3514a |
* @param completion The sub-task completion
|
|
Packit Service |
b3514a |
**/
|
|
Packit Service |
b3514a |
static void checkMayGrowPhysical(VDOCompletion *completion)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
AdminCompletion *adminCompletion = adminCompletionFromSubTask(completion);
|
|
Packit Service |
b3514a |
assertAdminOperationType(adminCompletion,
|
|
Packit Service |
b3514a |
ADMIN_OPERATION_PREPARE_GROW_PHYSICAL);
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
VDO *vdo = adminCompletion->completion.parent;
|
|
Packit Service |
b3514a |
assertOnAdminThread(vdo, __func__);
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
resetAdminSubTask(completion);
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
// This check can only be done from a base code thread.
|
|
Packit Service |
b3514a |
if (isReadOnly(vdo->readOnlyNotifier)) {
|
|
Packit Service |
b3514a |
finishCompletion(completion->parent, VDO_READ_ONLY);
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
// This check should only be done from a base code thread.
|
|
Packit Service |
b3514a |
if (inRecoveryMode(vdo)) {
|
|
Packit Service |
b3514a |
finishCompletion(completion->parent, VDO_RETRY_AFTER_REBUILD);
|
|
Packit Service |
b3514a |
return;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
completeCompletion(completion->parent);
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
/**********************************************************************/
|
|
Packit Service |
b3514a |
int prepareToGrowPhysical(VDO *vdo, BlockCount newPhysicalBlocks)
|
|
Packit Service |
b3514a |
{
|
|
Packit Service |
b3514a |
BlockCount currentPhysicalBlocks = vdo->config.physicalBlocks;
|
|
Packit Service |
b3514a |
if (newPhysicalBlocks < currentPhysicalBlocks) {
|
|
Packit Service |
b3514a |
return logErrorWithStringError(VDO_NOT_IMPLEMENTED,
|
|
Packit Service |
b3514a |
"Removing physical storage from a VDO is "
|
|
Packit Service |
b3514a |
"not supported");
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
if (newPhysicalBlocks == currentPhysicalBlocks) {
|
|
Packit Service |
b3514a |
logWarning("Requested physical block count %" PRIu64
|
|
Packit Service |
b3514a |
" not greater than %llu",
|
|
Packit Service |
b3514a |
newPhysicalBlocks, currentPhysicalBlocks);
|
|
Packit Service |
b3514a |
finishVDOLayoutGrowth(vdo->layout);
|
|
Packit Service |
b3514a |
abandonNewSlabs(vdo->depot);
|
|
Packit Service |
b3514a |
return VDO_PARAMETER_MISMATCH;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
int result = performAdminOperation(vdo,
|
|
Packit Service |
b3514a |
ADMIN_OPERATION_PREPARE_GROW_PHYSICAL,
|
|
Packit Service |
b3514a |
getThreadIDForPhase, checkMayGrowPhysical,
|
|
Packit Service |
b3514a |
finishParentCallback);
|
|
Packit Service |
b3514a |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
b3514a |
return result;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
result = prepareToGrowVDOLayout(vdo->layout, currentPhysicalBlocks,
|
|
Packit Service |
b3514a |
newPhysicalBlocks, vdo->layer);
|
|
Packit Service |
b3514a |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
b3514a |
return result;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
BlockCount newDepotSize = getNextBlockAllocatorPartitionSize(vdo->layout);
|
|
Packit Service |
b3514a |
result = prepareToGrowSlabDepot(vdo->depot, newDepotSize);
|
|
Packit Service |
b3514a |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
b3514a |
finishVDOLayoutGrowth(vdo->layout);
|
|
Packit Service |
b3514a |
return result;
|
|
Packit Service |
b3514a |
}
|
|
Packit Service |
b3514a |
|
|
Packit Service |
b3514a |
return VDO_SUCCESS;
|
|
Packit Service |
b3514a |
}
|