|
Packit Service |
d40955 |
/*
|
|
Packit Service |
d40955 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
d40955 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
d40955 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
d40955 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
d40955 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
d40955 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
d40955 |
* GNU General Public License for more details.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
d40955 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
d40955 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
d40955 |
* 02110-1301, USA.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/partitionCopy.c#2 $
|
|
Packit Service |
d40955 |
*/
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "partitionCopy.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "memoryAlloc.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "completion.h"
|
|
Packit Service |
d40955 |
#include "constants.h"
|
|
Packit Service |
d40955 |
#include "extent.h"
|
|
Packit Service |
d40955 |
#include "numUtils.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
enum {
|
|
Packit Service |
d40955 |
STRIDE_LENGTH = 2048
|
|
Packit Service |
d40955 |
};
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* A partition copy completion.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
typedef struct {
|
|
Packit Service |
d40955 |
/** completion header */
|
|
Packit Service |
d40955 |
VDOCompletion completion;
|
|
Packit Service |
d40955 |
/** the source partition to copy from */
|
|
Packit Service |
d40955 |
Partition *source;
|
|
Packit Service |
d40955 |
/** the target partition to copy to */
|
|
Packit Service |
d40955 |
Partition *target;
|
|
Packit Service |
d40955 |
/** the current in-partition PBN the copy is beginning at */
|
|
Packit Service |
d40955 |
PhysicalBlockNumber currentIndex;
|
|
Packit Service |
d40955 |
/** the last block to copy */
|
|
Packit Service |
d40955 |
PhysicalBlockNumber endingIndex;
|
|
Packit Service |
d40955 |
/** the backing data used by the extent */
|
|
Packit Service |
d40955 |
char *data;
|
|
Packit Service |
d40955 |
/** the extent being used to copy */
|
|
Packit Service |
d40955 |
VDOExtent *extent;
|
|
Packit Service |
d40955 |
} CopyCompletion;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Convert a VDOCompletion to a CopyCompletion.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The completion to convert
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return the completion as a CopyCompletion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result))
|
|
Packit Service |
d40955 |
static inline
|
|
Packit Service |
d40955 |
CopyCompletion *asCopyCompletion(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
STATIC_ASSERT(offsetof(CopyCompletion, completion) == 0);
|
|
Packit Service |
d40955 |
assertCompletionType(completion->type, PARTITION_COPY_COMPLETION);
|
|
Packit Service |
d40955 |
return (CopyCompletion *) completion;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int makeCopyCompletion(PhysicalLayer *layer, VDOCompletion **completionPtr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
CopyCompletion *copy;
|
|
Packit Service |
d40955 |
int result = ALLOCATE(1, CopyCompletion, __func__, ©);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
initializeCompletion(©->completion, PARTITION_COPY_COMPLETION, layer);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
result = ALLOCATE((VDO_BLOCK_SIZE * STRIDE_LENGTH), char,
|
|
Packit Service |
d40955 |
"partition copy extent", ©->data);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
VDOCompletion *completion = ©->completion;
|
|
Packit Service |
d40955 |
freeCopyCompletion(&completion);
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
result = createExtent(layer, VIO_TYPE_PARTITION_COPY, VIO_PRIORITY_HIGH,
|
|
Packit Service |
d40955 |
STRIDE_LENGTH, copy->data, ©->extent);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
VDOCompletion *completion = ©->completion;
|
|
Packit Service |
d40955 |
freeCopyCompletion(&completion);
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
*completionPtr = ©->completion;
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void freeCopyCompletion(VDOCompletion **completionPtr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
if (*completionPtr == NULL) {
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
CopyCompletion *copy = asCopyCompletion(*completionPtr);
|
|
Packit Service |
d40955 |
freeExtent(©->extent);
|
|
Packit Service |
d40955 |
FREE(copy->data);
|
|
Packit Service |
d40955 |
FREE(copy);
|
|
Packit Service |
d40955 |
*completionPtr = NULL;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
static void copyPartitionStride(CopyCompletion *copy);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Determine the number of blocks to copy in the current stride.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param copy The copy completion
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return The number of blocks to copy in the current stride
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static inline BlockCount getStrideSize(CopyCompletion *copy)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
return minBlockCount(STRIDE_LENGTH, copy->endingIndex - copy->currentIndex);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Process a completed write during a partition copy.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The extent which has just completed writing
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void completeWriteForCopy(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
CopyCompletion *copy = asCopyCompletion(completion->parent);
|
|
Packit Service |
d40955 |
copy->currentIndex += getStrideSize(copy);
|
|
Packit Service |
d40955 |
if (copy->currentIndex >= copy->endingIndex) {
|
|
Packit Service |
d40955 |
// We're done.
|
|
Packit Service |
d40955 |
finishCompletion(completion->parent, VDO_SUCCESS);
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
copyPartitionStride(copy);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Process a completed read during a partition copy, and launch the
|
|
Packit Service |
d40955 |
* corresponding write to the new partition.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The extent which has just completed reading
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void completeReadForCopy(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
CopyCompletion *copy = asCopyCompletion(completion->parent);
|
|
Packit Service |
d40955 |
PhysicalBlockNumber layerStartBlock;
|
|
Packit Service |
d40955 |
int result = translateToPBN(copy->target, copy->currentIndex,
|
|
Packit Service |
d40955 |
&layerStartBlock);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
finishCompletion(completion->parent, result);
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
completion->callback = completeWriteForCopy;
|
|
Packit Service |
d40955 |
writePartialMetadataExtent(asVDOExtent(completion), layerStartBlock,
|
|
Packit Service |
d40955 |
getStrideSize(copy));
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Copy a stride from one partition to the new partition.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param copy The CopyCompletion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void copyPartitionStride(CopyCompletion *copy)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
PhysicalBlockNumber layerStartBlock;
|
|
Packit Service |
d40955 |
int result = translateToPBN(copy->source, copy->currentIndex,
|
|
Packit Service |
d40955 |
&layerStartBlock);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
finishCompletion(©->completion, result);
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
prepareCompletion(©->extent->completion, completeReadForCopy,
|
|
Packit Service |
d40955 |
finishParentCallback, copy->completion.callbackThreadID,
|
|
Packit Service |
d40955 |
©->completion);
|
|
Packit Service |
d40955 |
readPartialMetadataExtent(copy->extent, layerStartBlock,
|
|
Packit Service |
d40955 |
getStrideSize(copy));
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Verify that the source can be copied to the target safely.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param source The source partition
|
|
Packit Service |
d40955 |
* @param target The target partition
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return VDO_SUCCESS or an error code
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static int validatePartitionCopy(Partition *source, Partition *target)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
BlockCount sourceSize = getFixedLayoutPartitionSize(source);
|
|
Packit Service |
d40955 |
BlockCount targetSize = getFixedLayoutPartitionSize(target);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
PhysicalBlockNumber sourceStart = getFixedLayoutPartitionOffset(source);
|
|
Packit Service |
d40955 |
PhysicalBlockNumber sourceEnd = sourceStart + sourceSize;
|
|
Packit Service |
d40955 |
PhysicalBlockNumber targetStart = getFixedLayoutPartitionOffset(target);
|
|
Packit Service |
d40955 |
PhysicalBlockNumber targetEnd = targetStart + targetSize;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
int result = ASSERT(sourceSize <= targetSize,
|
|
Packit Service |
d40955 |
"target partition must be not smaller than source"
|
|
Packit Service |
d40955 |
" partition");
|
|
Packit Service |
d40955 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return ASSERT(((sourceEnd <= targetStart) || (targetEnd <= sourceStart)),
|
|
Packit Service |
d40955 |
"target partition must not overlap source partition");
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void copyPartitionAsync(VDOCompletion *completion,
|
|
Packit Service |
d40955 |
Partition *source,
|
|
Packit Service |
d40955 |
Partition *target,
|
|
Packit Service |
d40955 |
VDOCompletion *parent)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
int result = validatePartitionCopy(source, target);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
finishCompletion(parent, result);
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
CopyCompletion *copy = asCopyCompletion(completion);
|
|
Packit Service |
d40955 |
prepareToFinishParent(©->completion, parent);
|
|
Packit Service |
d40955 |
copy->source = source;
|
|
Packit Service |
d40955 |
copy->target = target;
|
|
Packit Service |
d40955 |
copy->currentIndex = 0;
|
|
Packit Service |
d40955 |
copy->endingIndex = getFixedLayoutPartitionSize(source);
|
|
Packit Service |
d40955 |
copyPartitionStride(copy);
|
|
Packit Service |
d40955 |
}
|