Blame vdo/base/partitionCopy.c

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