Blame source/vdo/kernel/dataKVIO.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/kernel/dataKVIO.c#18 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "dataKVIO.h"
Packit Service 310c69
Packit Service 310c69
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "murmur/MurmurHash3.h"
Packit Service 310c69
Packit Service 310c69
#include "dataVIO.h"
Packit Service 310c69
#include "compressedBlock.h"
Packit Service 310c69
#include "hashLock.h"
Packit Service 310c69
#include "lz4.h"
Packit Service 310c69
Packit Service 310c69
#include "bio.h"
Packit Service 310c69
#include "dedupeIndex.h"
Packit Service 310c69
#include "kvdoFlush.h"
Packit Service 310c69
#include "kvio.h"
Packit Service 310c69
#include "ioSubmitter.h"
Packit Service 310c69
#include "vdoCommon.h"
Packit Service 310c69
#include "verify.h"
Packit Service 310c69
Packit Service 310c69
static void dumpPooledDataKVIO(void *poolData, void *data);
Packit Service 310c69
Packit Service 310c69
enum {
Packit Service 310c69
  WRITE_PROTECT_FREE_POOL = 0,
Packit Service 310c69
  WP_DATA_KVIO_SIZE       = (sizeof(DataKVIO) + PAGE_SIZE - 1
Packit Service 310c69
                             - ((sizeof(DataKVIO) + PAGE_SIZE - 1)
Packit Service 310c69
                                % PAGE_SIZE))
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Alter the write-access permission to a page of memory, so that
Packit Service 310c69
 * objects in the free pool may no longer be modified.
Packit Service 310c69
 *
Packit Service 310c69
 * To do: Deny read access as well.
Packit Service 310c69
 *
Packit Service 310c69
 * @param address    The starting address to protect, which must be on a
Packit Service 310c69
 *                   page boundary
Packit Service 310c69
 * @param byteCount  The number of bytes to protect, which must be a multiple
Packit Service 310c69
 *                   of the page size
Packit Service 310c69
 * @param mode       The write protection mode (true means read-only)
Packit Service 310c69
 **/
Packit Service 310c69
static __always_inline void
Packit Service 310c69
setWriteProtect(void   *address,
Packit Service 310c69
                size_t  byteCount,
Packit Service 310c69
                bool    mode __attribute__((unused)))
Packit Service 310c69
{
Packit Service 310c69
  BUG_ON((((long) address) % PAGE_SIZE) != 0);
Packit Service 310c69
  BUG_ON((byteCount % PAGE_SIZE) != 0);
Packit Service 310c69
  BUG(); // only works in internal code, sorry
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void maybeLogDataKVIOTrace(DataKVIO *dataKVIO)
Packit Service 310c69
{
Packit Service 310c69
  if (dataKVIO->kvio.layer->traceLogging) {
Packit Service 310c69
    logKvioTrace(&dataKVIO->kvio);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * First tracing hook for VIO completion.
Packit Service 310c69
 *
Packit Service 310c69
 * If the SystemTap script vdotrace.stp is in use, it does stage 1 of
Packit Service 310c69
 * its processing here. We must not call addTraceRecord between the
Packit Service 310c69
 * two tap functions.
Packit Service 310c69
 *
Packit Service 310c69
 * @param dataKVIO  The VIO we're finishing up
Packit Service 310c69
 **/
Packit Service 310c69
static void kvioCompletionTap1(DataKVIO *dataKVIO)
Packit Service 310c69
{
Packit Service 310c69
  /*
Packit Service 310c69
   * Ensure that dataKVIO doesn't get optimized out, even under inline
Packit Service 310c69
   * expansion. Also, make sure the compiler has to emit debug info
Packit Service 310c69
   * for baseTraceLocation, which some of our SystemTap scripts will
Packit Service 310c69
   * use here.
Packit Service 310c69
   *
Packit Service 310c69
   * First, make it look as though all memory could be clobbered; then
Packit Service 310c69
   * require that a value be read into a register. That'll force at
Packit Service 310c69
   * least one instruction to exist (so SystemTap can hook in) where
Packit Service 310c69
   * dataKVIO is live. We use a field that the caller would've
Packit Service 310c69
   * accessed recently anyway, so it may be cached.
Packit Service 310c69
   */
Packit Service 310c69
  barrier();
Packit Service 310c69
  __asm__ __volatile__(""
Packit Service 310c69
                       :
Packit Service 310c69
                       : "g" (dataKVIO), "g" (baseTraceLocation),
Packit Service 310c69
                         "r" (dataKVIO->kvio.layer));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Second tracing hook for VIO completion.
Packit Service 310c69
 *
Packit Service 310c69
 * The SystemTap script vdotrace.stp splits its VIO-completion work
Packit Service 310c69
 * into two stages, to reduce lock contention for script variables.
Packit Service 310c69
 * Hence, it needs two hooks in the code.
Packit Service 310c69
 *
Packit Service 310c69
 * @param dataKVIO  The VIO we're finishing up
Packit Service 310c69
 **/
Packit Service 310c69
static void kvioCompletionTap2(DataKVIO *dataKVIO)
Packit Service 310c69
{
Packit Service 310c69
  // Hack to ensure variable doesn't get optimized out.
Packit Service 310c69
  barrier();
Packit Service 310c69
  __asm__ __volatile__("" : : "g" (dataKVIO), "r" (dataKVIO->kvio.layer));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void kvdoAcknowledgeDataKVIO(DataKVIO *dataKVIO)
Packit Service 310c69
{
Packit Service 310c69
  KernelLayer       *layer             = dataKVIO->kvio.layer;
Packit Service 310c69
  ExternalIORequest *externalIORequest = &dataKVIO->externalIORequest;
Packit Service 310c69
  BIO               *bio               = externalIORequest->bio;
Packit Service 310c69
  if (bio == NULL) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  externalIORequest->bio = NULL;
Packit Service 310c69
Packit Service 310c69
  int error
Packit Service 310c69
    = mapToSystemError(dataVIOAsCompletion(&dataKVIO->dataVIO)->result);
Packit Service 310c69
  bio->bi_end_io  = externalIORequest->endIO;
Packit Service 310c69
  bio->bi_private = externalIORequest->private;
Packit Service 310c69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
Packit Service 310c69
  bio->bi_opf     = externalIORequest->rw;
Packit Service 310c69
#else
Packit Service 310c69
  bio->bi_rw      = externalIORequest->rw;
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
  countBios(&layer->biosAcknowledged, bio);
Packit Service 310c69
  if (dataKVIO->isPartial) {
Packit Service 310c69
    countBios(&layer->biosAcknowledgedPartial, bio);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
Packit Service 310c69
  dataKVIOAddTraceRecord(dataKVIO, THIS_LOCATION(NULL));
Packit Service 310c69
  completeBio(bio, error);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static noinline void cleanDataKVIO(DataKVIO *dataKVIO, FreeBufferPointers *fbp)
Packit Service 310c69
{
Packit Service 310c69
  dataKVIOAddTraceRecord(dataKVIO, THIS_LOCATION(NULL));
Packit Service 310c69
  kvdoAcknowledgeDataKVIO(dataKVIO);
Packit Service 310c69
Packit Service 310c69
  KVIO *kvio = dataKVIOAsKVIO(dataKVIO);
Packit Service 310c69
  kvio->bio  = NULL;
Packit Service 310c69
Packit Service 310c69
  if (unlikely(kvio->vio->trace != NULL)) {
Packit Service 310c69
    maybeLogDataKVIOTrace(dataKVIO);
Packit Service 310c69
    kvioCompletionTap1(dataKVIO);
Packit Service 310c69
    kvioCompletionTap2(dataKVIO);
Packit Service 310c69
    freeTraceToPool(kvio->layer, kvio->vio->trace);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  addFreeBufferPointer(fbp, dataKVIO);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void returnDataKVIOBatchToPool(BatchProcessor *batch, void *closure)
Packit Service 310c69
{
Packit Service 310c69
  KernelLayer *layer = closure;
Packit Service 310c69
  uint32_t     count = 0;
Packit Service 310c69
  ASSERT_LOG_ONLY(batch != NULL, "batch not null");
Packit Service 310c69
  ASSERT_LOG_ONLY(layer != NULL, "layer not null");
Packit Service 310c69
Packit Service 310c69
  FreeBufferPointers fbp;
Packit Service 310c69
  initFreeBufferPointers(&fbp, layer->dataKVIOPool);
Packit Service 310c69
Packit Service 310c69
  KvdoWorkItem *item;
Packit Service 310c69
  while ((item = nextBatchItem(batch)) != NULL) {
Packit Service 310c69
    cleanDataKVIO(workItemAsDataKVIO(item), &fbp);
Packit Service 310c69
    condReschedBatchProcessor(batch);
Packit Service 310c69
    count++;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (fbp.index > 0) {
Packit Service 310c69
    freeBufferPointers(&fbp);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  completeManyRequests(layer, count);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void kvdoAcknowledgeThenCompleteDataKVIO(KvdoWorkItem *item)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = workItemAsDataKVIO(item);
Packit Service 310c69
  kvdoAcknowledgeDataKVIO(dataKVIO);
Packit Service 310c69
  addToBatchProcessor(dataKVIO->kvio.layer->dataKVIOReleaser, item);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoCompleteDataKVIO(VDOCompletion *completion)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = dataVIOAsDataKVIO(asDataVIO(completion));
Packit Service 310c69
  dataKVIOAddTraceRecord(dataKVIO, THIS_LOCATION(NULL));
Packit Service 310c69
Packit Service 310c69
  KernelLayer *layer = getLayerFromDataKVIO(dataKVIO);
Packit Service 310c69
  if (useBioAckQueue(layer) && USE_BIO_ACK_QUEUE_FOR_READ
Packit Service 310c69
      && (dataKVIO->externalIORequest.bio != NULL)) {
Packit Service 310c69
    launchDataKVIOOnBIOAckQueue(dataKVIO, kvdoAcknowledgeThenCompleteDataKVIO,
Packit Service 310c69
                                NULL, BIO_ACK_Q_ACTION_ACK);
Packit Service 310c69
  } else {
Packit Service 310c69
    addToBatchProcessor(layer->dataKVIOReleaser,
Packit Service 310c69
                        workItemFromDataKVIO(dataKVIO));
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Copy the uncompressed data from a compressed block read into the user
Packit Service 310c69
 * bio which requested the read.
Packit Service 310c69
 *
Packit Service 310c69
 * @param workItem  The DataKVIO which requested the read
Packit Service 310c69
 **/
Packit Service 310c69
static void copyReadBlockData(KvdoWorkItem *workItem)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = workItemAsDataKVIO(workItem);
Packit Service 310c69
Packit Service 310c69
  // For a read-modify-write, copy the data into the dataBlock buffer so it
Packit Service 310c69
  // will be set up for the write phase.
Packit Service 310c69
  if (isReadModifyWriteVIO(dataKVIO->kvio.vio)) {
Packit Service 310c69
    bioCopyDataOut(getBIOFromDataKVIO(dataKVIO), dataKVIO->readBlock.data);
Packit Service 310c69
    kvdoEnqueueDataVIOCallback(dataKVIO);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // For a partial read, the callback will copy the requested data from the
Packit Service 310c69
  // read block.
Packit Service 310c69
  if (dataKVIO->isPartial) {
Packit Service 310c69
    kvdoEnqueueDataVIOCallback(dataKVIO);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // For a full block read, copy the data to the bio and acknowledge.
Packit Service 310c69
  bioCopyDataOut(getBIOFromDataKVIO(dataKVIO), dataKVIO->readBlock.data);
Packit Service 310c69
  kvdoAcknowledgeDataVIO(&dataKVIO->dataVIO);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Finish reading data for a compressed block.
Packit Service 310c69
 *
Packit Service 310c69
 * @param dataKVIO  The DataKVIO which requested the read
Packit Service 310c69
 **/
Packit Service 310c69
static void readDataKVIOReadBlockCallback(DataKVIO *dataKVIO)
Packit Service 310c69
{
Packit Service 310c69
  if (dataKVIO->readBlock.status != VDO_SUCCESS) {
Packit Service 310c69
    setCompletionResult(dataVIOAsCompletion(&dataKVIO->dataVIO),
Packit Service 310c69
                        dataKVIO->readBlock.status);
Packit Service 310c69
    kvdoEnqueueDataVIOCallback(dataKVIO);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  launchDataKVIOOnCPUQueue(dataKVIO, copyReadBlockData, NULL,
Packit Service 310c69
                           CPU_Q_ACTION_COMPRESS_BLOCK);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
Packit Service 310c69
/**
Packit Service 310c69
 * Complete and reset a bio that was supplied by the user and then used for a
Packit Service 310c69
 * read (so that we can complete it with the user's callback).
Packit Service 310c69
 *
Packit Service 310c69
 * @param bio   The bio to complete
Packit Service 310c69
 **/
Packit Service 310c69
static void resetUserBio(BIO *bio)
Packit Service 310c69
#else
Packit Service 310c69
/**
Packit Service 310c69
 * Complete and reset a bio that was supplied by the user and then used for a
Packit Service 310c69
 * read (so that we can complete it with the user's callback).
Packit Service 310c69
 *
Packit Service 310c69
 * @param bio   The bio to complete
Packit Service 310c69
 * @param error Possible error from underlying block device
Packit Service 310c69
 **/
Packit Service 310c69
static void resetUserBio(BIO *bio, int error)
Packit Service 310c69
#endif
Packit Service 310c69
{
Packit Service 310c69
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) \
Packit Service 310c69
     && (LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)))
Packit Service 310c69
  // This is a user bio, and the device just called bio_endio() on it, so
Packit Service 310c69
  // we need to re-increment bi_remaining so we too can call bio_endio().
Packit Service 310c69
  atomic_inc(&bio->bi_remaining);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
Packit Service 310c69
  completeAsyncBio(bio);
Packit Service 310c69
#else
Packit Service 310c69
  completeAsyncBio(bio, error);
Packit Service 310c69
#endif
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Uncompress the data that's just been read and then call back the requesting
Packit Service 310c69
 * DataKVIO.
Packit Service 310c69
 *
Packit Service 310c69
 * @param workItem  The DataKVIO requesting the data
Packit Service 310c69
 **/
Packit Service 310c69
static void uncompressReadBlock(KvdoWorkItem *workItem)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO  *dataKVIO  = workItemAsDataKVIO(workItem);
Packit Service 310c69
  ReadBlock *readBlock = &dataKVIO->readBlock;
Packit Service 310c69
  BlockSize  blockSize = VDO_BLOCK_SIZE;
Packit Service 310c69
Packit Service 310c69
  // The DataKVIO's scratch block will be used to contain the
Packit Service 310c69
  // uncompressed data.
Packit Service 310c69
  uint16_t fragmentOffset, fragmentSize;
Packit Service 310c69
  char *compressedData = readBlock->data;
Packit Service 310c69
  int result = getCompressedBlockFragment(readBlock->mappingState,
Packit Service 310c69
                                          compressedData, blockSize,
Packit Service 310c69
                                          &fragmentOffset,
Packit Service 310c69
                                          &fragmentSize);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    logDebug("%s: frag err %d", __func__, result);
Packit Service 310c69
    readBlock->status = result;
Packit Service 310c69
    readBlock->callback(dataKVIO);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  char *fragment = compressedData + fragmentOffset;
Packit Service 310c69
  int size = LZ4_uncompress_unknownOutputSize(fragment, dataKVIO->scratchBlock,
Packit Service 310c69
                                              fragmentSize, blockSize);
Packit Service 310c69
  if (size == blockSize) {
Packit Service 310c69
    readBlock->data = dataKVIO->scratchBlock;
Packit Service 310c69
  } else {
Packit Service 310c69
    logDebug("%s: lz4 error", __func__);
Packit Service 310c69
    readBlock->status = VDO_INVALID_FRAGMENT;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  readBlock->callback(dataKVIO);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Now that we have gotten the data from storage, uncompress the data if
Packit Service 310c69
 * necessary and then call back the requesting DataKVIO.
Packit Service 310c69
 *
Packit Service 310c69
 * @param dataKVIO  The DataKVIO requesting the data
Packit Service 310c69
 * @param result    The result of the read operation
Packit Service 310c69
 **/
Packit Service 310c69
static void completeRead(DataKVIO *dataKVIO, int result)
Packit Service 310c69
{
Packit Service 310c69
  ReadBlock *readBlock = &dataKVIO->readBlock;
Packit Service 310c69
  readBlock->status = result;
Packit Service 310c69
Packit Service 310c69
  if ((result == VDO_SUCCESS) && isCompressed(readBlock->mappingState)) {
Packit Service 310c69
    launchDataKVIOOnCPUQueue(dataKVIO, uncompressReadBlock, NULL,
Packit Service 310c69
                             CPU_Q_ACTION_COMPRESS_BLOCK);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  readBlock->callback(dataKVIO);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
Packit Service 310c69
/**
Packit Service 310c69
 * Callback for a bio doing a read.
Packit Service 310c69
 *
Packit Service 310c69
 * @param bio     The bio
Packit Service 310c69
 */
Packit Service 310c69
static void readBioCallback(BIO *bio)
Packit Service 310c69
#else
Packit Service 310c69
/**
Packit Service 310c69
 * Callback for a bio doing a read.
Packit Service 310c69
 *
Packit Service 310c69
 * @param bio     The bio
Packit Service 310c69
 * @param result  The result of the read operation
Packit Service 310c69
 */
Packit Service 310c69
static void readBioCallback(BIO *bio, int result)
Packit Service 310c69
#endif
Packit Service 310c69
{
Packit Service 310c69
  KVIO *kvio = (KVIO *) bio->bi_private;
Packit Service 310c69
  DataKVIO *dataKVIO = kvioAsDataKVIO(kvio);
Packit Service 310c69
  dataKVIO->readBlock.data = dataKVIO->readBlock.buffer;
Packit Service 310c69
  dataKVIOAddTraceRecord(dataKVIO, THIS_LOCATION(NULL));
Packit Service 310c69
  countCompletedBios(bio);
Packit Service 310c69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
Packit Service 310c69
  completeRead(dataKVIO, getBioResult(bio));
Packit Service 310c69
#else
Packit Service 310c69
  completeRead(dataKVIO, result);
Packit Service 310c69
#endif
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoReadBlock(DataVIO             *dataVIO,
Packit Service 310c69
                   PhysicalBlockNumber  location,
Packit Service 310c69
                   BlockMappingState    mappingState,
Packit Service 310c69
                   BioQAction           action,
Packit Service 310c69
                   DataKVIOCallback     callback)
Packit Service 310c69
{
Packit Service 310c69
  dataVIOAddTraceRecord(dataVIO, THIS_LOCATION(NULL));
Packit Service 310c69
Packit Service 310c69
  DataKVIO    *dataKVIO  = dataVIOAsDataKVIO(dataVIO);
Packit Service 310c69
  ReadBlock   *readBlock = &dataKVIO->readBlock;
Packit Service 310c69
  KernelLayer *layer     = getLayerFromDataKVIO(dataKVIO);
Packit Service 310c69
Packit Service 310c69
  readBlock->callback     = callback;
Packit Service 310c69
  readBlock->status       = VDO_SUCCESS;
Packit Service 310c69
  readBlock->mappingState = mappingState;
Packit Service 310c69
Packit Service 310c69
  BUG_ON(getBIOFromDataKVIO(dataKVIO)->bi_private != &dataKVIO->kvio);
Packit Service 310c69
  // Read the data directly from the device using the read bio.
Packit Service 310c69
  BIO *bio = readBlock->bio;
Packit Service 310c69
  resetBio(bio, layer);
Packit Service 310c69
  setBioSector(bio, blockToSector(layer, location));
Packit Service 310c69
  setBioOperationRead(bio);
Packit Service 310c69
  bio->bi_end_io = readBioCallback;
Packit Service 310c69
  submitBio(bio, action);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoReadDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  ASSERT_LOG_ONLY(!isWriteVIO(dataVIOAsVIO(dataVIO)),
Packit Service 310c69
                  "operation set correctly for data read");
Packit Service 310c69
  dataVIOAddTraceRecord(dataVIO, THIS_LOCATION("$F;io=readData"));
Packit Service 310c69
Packit Service 310c69
  if (isCompressed(dataVIO->mapped.state)) {
Packit Service 310c69
    kvdoReadBlock(dataVIO, dataVIO->mapped.pbn, dataVIO->mapped.state,
Packit Service 310c69
                  BIO_Q_ACTION_COMPRESSED_DATA, readDataKVIOReadBlockCallback);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  KVIO *kvio = dataVIOAsKVIO(dataVIO);
Packit Service 310c69
  BIO  *bio  = kvio->bio;
Packit Service 310c69
  bio->bi_end_io = resetUserBio;
Packit Service 310c69
  setBioSector(bio, blockToSector(kvio->layer, dataVIO->mapped.pbn));
Packit Service 310c69
  submitBio(bio, BIO_Q_ACTION_DATA);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void kvdoAcknowledgeDataKVIOThenContinue(KvdoWorkItem *item)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = workItemAsDataKVIO(item);
Packit Service 310c69
  dataKVIOAddTraceRecord(dataKVIO, THIS_LOCATION(NULL));
Packit Service 310c69
  kvdoAcknowledgeDataKVIO(dataKVIO);
Packit Service 310c69
  // Even if we're not using bio-ack threads, we may be in the wrong
Packit Service 310c69
  // base-code thread.
Packit Service 310c69
  kvdoEnqueueDataVIOCallback(dataKVIO);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoAcknowledgeDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO    *dataKVIO = dataVIOAsDataKVIO(dataVIO);
Packit Service 310c69
  KernelLayer *layer    = getLayerFromDataKVIO(dataKVIO);
Packit Service 310c69
Packit Service 310c69
  // If the remaining discard work is not completely processed by this VIO,
Packit Service 310c69
  // don't acknowledge it yet.
Packit Service 310c69
  if (isDiscardBio(dataKVIO->externalIORequest.bio)
Packit Service 310c69
      && (dataKVIO->remainingDiscard
Packit Service 310c69
          > (VDO_BLOCK_SIZE - dataKVIO->offset))) {
Packit Service 310c69
    invokeCallback(dataVIOAsCompletion(dataVIO));
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // We've finished with the KVIO; acknowledge completion of the bio to the
Packit Service 310c69
  // kernel.
Packit Service 310c69
  if (useBioAckQueue(layer)) {
Packit Service 310c69
    dataVIOAddTraceRecord(dataVIO, THIS_LOCATION(NULL));
Packit Service 310c69
    launchDataKVIOOnBIOAckQueue(dataKVIO, kvdoAcknowledgeDataKVIOThenContinue,
Packit Service 310c69
                                NULL, BIO_ACK_Q_ACTION_ACK);
Packit Service 310c69
  } else {
Packit Service 310c69
    kvdoAcknowledgeDataKVIOThenContinue(workItemFromDataKVIO(dataKVIO));
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoWriteDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  ASSERT_LOG_ONLY(isWriteVIO(dataVIOAsVIO(dataVIO)),
Packit Service 310c69
                  "kvdoWriteDataVIO() called on write DataVIO");
Packit Service 310c69
  dataVIOAddTraceRecord(dataVIO, THIS_LOCATION("$F;io=writeData;j=normal"));
Packit Service 310c69
Packit Service 310c69
  KVIO *kvio  = dataVIOAsKVIO(dataVIO);
Packit Service 310c69
  BIO  *bio   = kvio->bio;
Packit Service 310c69
  setBioOperationWrite(bio);
Packit Service 310c69
  setBioSector(bio, blockToSector(kvio->layer, dataVIO->newMapped.pbn));
Packit Service 310c69
  submitBio(bio, BIO_Q_ACTION_DATA);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoModifyWriteDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  dataVIOAddTraceRecord(dataVIO, THIS_LOCATION(NULL));
Packit Service 310c69
  DataKVIO    *dataKVIO = dataVIOAsDataKVIO(dataVIO);
Packit Service 310c69
  BIO         *bio      = dataKVIO->externalIORequest.bio;
Packit Service 310c69
  KernelLayer *layer    = getLayerFromDataKVIO(dataKVIO);
Packit Service 310c69
  resetBio(dataKVIO->dataBlockBio, layer);
Packit Service 310c69
Packit Service 310c69
  if (!isDiscardBio(bio)) {
Packit Service 310c69
    bioCopyDataIn(bio, dataKVIO->dataBlock + dataKVIO->offset);
Packit Service 310c69
  } else {
Packit Service 310c69
    memset(dataKVIO->dataBlock + dataKVIO->offset, '\0',
Packit Service 310c69
           min(dataKVIO->remainingDiscard,
Packit Service 310c69
               (DiscardSize) (VDO_BLOCK_SIZE - dataKVIO->offset)));
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  dataVIO->isZeroBlock               = bioIsZeroData(dataKVIO->dataBlockBio);
Packit Service 310c69
  dataKVIO->dataBlockBio->bi_private = &dataKVIO->kvio;
Packit Service 310c69
  copyBioOperationAndFlags(dataKVIO->dataBlockBio, bio);
Packit Service 310c69
  // Make the bio a write, not (potentially) a discard.
Packit Service 310c69
  setBioOperationWrite(dataKVIO->dataBlockBio);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoZeroDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  dataVIOAddTraceRecord(dataVIO, THIS_LOCATION("zeroDataVIO;io=readData"));
Packit Service 310c69
  bioZeroData(dataVIOAsKVIO(dataVIO)->bio);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoCopyDataVIO(DataVIO *source, DataVIO *destination)
Packit Service 310c69
{
Packit Service 310c69
  dataVIOAddTraceRecord(destination, THIS_LOCATION(NULL));
Packit Service 310c69
  bioCopyDataOut(dataVIOAsKVIO(destination)->bio,
Packit Service 310c69
                 dataVIOAsDataKVIO(source)->dataBlock);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void kvdoCompressWork(KvdoWorkItem *item)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO    *dataKVIO = workItemAsDataKVIO(item);
Packit Service 310c69
  KernelLayer *layer    = getLayerFromDataKVIO(dataKVIO);
Packit Service 310c69
  dataKVIOAddTraceRecord(dataKVIO, THIS_LOCATION(NULL));
Packit Service 310c69
Packit Service 310c69
  char *context = getWorkQueuePrivateData();
Packit Service 310c69
  if (unlikely(context == NULL)) {
Packit Service 310c69
    uint32_t index = atomicAdd32(&layer->compressionContextIndex, 1) - 1;
Packit Service 310c69
    BUG_ON(index >= layer->deviceConfig->threadCounts.cpuThreads);
Packit Service 310c69
    context = layer->compressionContext[index];
Packit Service 310c69
    setWorkQueuePrivateData(context);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  int size = LZ4_compress_ctx_limitedOutput(context, dataKVIO->dataBlock,
Packit Service 310c69
                                            dataKVIO->scratchBlock,
Packit Service 310c69
                                            VDO_BLOCK_SIZE,
Packit Service 310c69
                                            VDO_BLOCK_SIZE);
Packit Service 310c69
  DataVIO *dataVIO = &dataKVIO->dataVIO;
Packit Service 310c69
  if (size > 0) {
Packit Service 310c69
    // The scratch block will be used to contain the compressed data.
Packit Service 310c69
    dataVIO->compression.data = dataKVIO->scratchBlock;
Packit Service 310c69
    dataVIO->compression.size = size;
Packit Service 310c69
  } else {
Packit Service 310c69
    // Use block size plus one as an indicator for uncompressible data.
Packit Service 310c69
    dataVIO->compression.size = VDO_BLOCK_SIZE + 1;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  kvdoEnqueueDataVIOCallback(dataKVIO);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoCompressDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  dataVIOAddTraceRecord(dataVIO,
Packit Service 310c69
                        THIS_LOCATION("compressDataVIO;"
Packit Service 310c69
                                      "io=compress;cb=compress"));
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * If the orignal bio was a discard, but we got this far because the discard
Packit Service 310c69
   * was a partial one (r/m/w), and it is part of a larger discard, we cannot
Packit Service 310c69
   * compress this VIO. We need to make sure the VIO completes ASAP.
Packit Service 310c69
   */
Packit Service 310c69
  DataKVIO *dataKVIO = dataVIOAsDataKVIO(dataVIO);
Packit Service 310c69
  if (isDiscardBio(dataKVIO->externalIORequest.bio)
Packit Service 310c69
      && (dataKVIO->remainingDiscard > 0)) {
Packit Service 310c69
    dataVIO->compression.size = VDO_BLOCK_SIZE + 1;
Packit Service 310c69
    kvdoEnqueueDataVIOCallback(dataKVIO);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  launchDataKVIOOnCPUQueue(dataKVIO, kvdoCompressWork, NULL,
Packit Service 310c69
                           CPU_Q_ACTION_COMPRESS_BLOCK);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Construct a DataKVIO.
Packit Service 310c69
 *
Packit Service 310c69
 * @param [in]  layer        The physical layer
Packit Service 310c69
 * @param [in]  bio          The bio to associate with this DataKVIO
Packit Service 310c69
 * @param [out] dataKVIOPtr  A pointer to hold the new DataKVIO
Packit Service 310c69
 *
Packit Service 310c69
 * @return VDO_SUCCESS or an error
Packit Service 310c69
 **/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int makeDataKVIO(KernelLayer *layer, BIO *bio, DataKVIO **dataKVIOPtr)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO;
Packit Service 310c69
  int result = allocBufferFromPool(layer->dataKVIOPool, (void **) &dataKVIO);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "data kvio allocation failure");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (WRITE_PROTECT_FREE_POOL) {
Packit Service 310c69
    setWriteProtect(dataKVIO, WP_DATA_KVIO_SIZE, false);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  KVIO *kvio = &dataKVIO->kvio;
Packit Service 310c69
  kvio->vio = dataVIOAsVIO(&dataKVIO->dataVIO);
Packit Service 310c69
  memset(&kvio->enqueueable, 0, sizeof(KvdoEnqueueable));
Packit Service 310c69
  memset(&dataKVIO->dedupeContext.pendingList, 0, sizeof(struct list_head));
Packit Service 310c69
  memset(&dataKVIO->dataVIO, 0, sizeof(DataVIO));
Packit Service 310c69
  kvio->bioToSubmit = NULL;
Packit Service 310c69
  bio_list_init(&kvio->biosMerged);
Packit Service 310c69
Packit Service 310c69
  // The dataBlock is only needed for writes and some partial reads.
Packit Service 310c69
  if (isWriteBio(bio) || (getBioSize(bio) < VDO_BLOCK_SIZE)) {
Packit Service 310c69
    resetBio(dataKVIO->dataBlockBio, layer);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  initializeKVIO(kvio, layer, VIO_TYPE_DATA, VIO_PRIORITY_DATA, NULL, bio);
Packit Service 310c69
  *dataKVIOPtr = dataKVIO;
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Creates a new DataVIO structure. A DataVIO represents a single logical
Packit Service 310c69
 * block of data. It is what most VDO operations work with. This function also
Packit Service 310c69
 * creates a wrapping DataKVIO structure that is used when we want to
Packit Service 310c69
 * physically read or write the data associated with the DataVIO.
Packit Service 310c69
 *
Packit Service 310c69
 * @param [in]  layer        The physical layer
Packit Service 310c69
 * @param [in]  bio          The BIO from the request the new DataKVIO will
Packit Service 310c69
 *                           service
Packit Service 310c69
 * @param [in]  arrivalTime  The arrival time of the BIO
Packit Service 310c69
 * @param [out] dataKVIOPtr  A pointer to hold the new DataKVIO
Packit Service 310c69
 *
Packit Service 310c69
 * @return VDO_SUCCESS or an error
Packit Service 310c69
 **/
Packit Service 310c69
static int kvdoCreateKVIOFromBio(KernelLayer  *layer,
Packit Service 310c69
                                 BIO          *bio,
Packit Service 310c69
                                 Jiffies       arrivalTime,
Packit Service 310c69
                                 DataKVIO    **dataKVIOPtr)
Packit Service 310c69
{
Packit Service 310c69
  ExternalIORequest externalIORequest = {
Packit Service 310c69
    .bio         = bio,
Packit Service 310c69
    .private     = bio->bi_private,
Packit Service 310c69
    .endIO       = bio->bi_end_io,
Packit Service 310c69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
Packit Service 310c69
    .rw          = bio->bi_opf,
Packit Service 310c69
#else
Packit Service 310c69
    .rw          = bio->bi_rw,
Packit Service 310c69
#endif
Packit Service 310c69
  };
Packit Service 310c69
Packit Service 310c69
  // We will handle FUA at the end of the request (after we restore the
Packit Service 310c69
  // bi_rw field from externalIORequest.rw).
Packit Service 310c69
  clearBioOperationFlagFua(bio);
Packit Service 310c69
Packit Service 310c69
  DataKVIO *dataKVIO = NULL;
Packit Service 310c69
  int       result   = makeDataKVIO(layer, bio, &dataKVIO);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  dataKVIO->externalIORequest = externalIORequest;
Packit Service 310c69
  dataKVIO->offset = sectorToBlockOffset(layer, getBioSector(bio));
Packit Service 310c69
  dataKVIO->isPartial = ((getBioSize(bio) < VDO_BLOCK_SIZE)
Packit Service 310c69
                         || (dataKVIO->offset != 0));
Packit Service 310c69
Packit Service 310c69
  if (dataKVIO->isPartial) {
Packit Service 310c69
    countBios(&layer->biosInPartial, bio);
Packit Service 310c69
  } else {
Packit Service 310c69
    /*
Packit Service 310c69
     * Note that we unconditionally fill in the dataBlock array for
Packit Service 310c69
     * non-read operations. There are places like kvdoCopyVIO that may
Packit Service 310c69
     * look at kvio->dataBlock for a zero block (and maybe for
Packit Service 310c69
     * discards?). We could skip filling in dataBlock for such cases,
Packit Service 310c69
     * but only once we're sure all such places are fixed to check the
Packit Service 310c69
     * isZeroBlock flag first.
Packit Service 310c69
     */
Packit Service 310c69
    if (isDiscardBio(bio)) {
Packit Service 310c69
      /*
Packit Service 310c69
       * This is a discard/trim operation. This is treated much like the zero
Packit Service 310c69
       * block, but we keep different stats and distinguish it in the block
Packit Service 310c69
       * map.
Packit Service 310c69
       */
Packit Service 310c69
      memset(dataKVIO->dataBlock, 0, VDO_BLOCK_SIZE);
Packit Service 310c69
    } else if (bio_data_dir(bio) == WRITE) {
Packit Service 310c69
      dataKVIO->dataVIO.isZeroBlock = bioIsZeroData(bio);
Packit Service 310c69
      // Copy the bio data to a char array so that we can continue to use
Packit Service 310c69
      // the data after we acknowledge the bio.
Packit Service 310c69
      bioCopyDataIn(bio, dataKVIO->dataBlock);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (dataKVIO->isPartial || isWriteBio(bio)) {
Packit Service 310c69
    /*
Packit Service 310c69
     * dataKVIO->bio will point at kvio->dataBlockBio for all writes and
Packit Service 310c69
     * partial block I/O so the rest of the kernel code doesn't need to
Packit Service 310c69
     * make a decision as to what to use.
Packit Service 310c69
     */
Packit Service 310c69
    dataKVIO->dataBlockBio->bi_private = &dataKVIO->kvio;
Packit Service 310c69
    if (dataKVIO->isPartial && isWriteBio(bio)) {
Packit Service 310c69
      clearBioOperationAndFlags(dataKVIO->dataBlockBio);
Packit Service 310c69
      setBioOperationRead(dataKVIO->dataBlockBio);
Packit Service 310c69
    } else {
Packit Service 310c69
      copyBioOperationAndFlags(dataKVIO->dataBlockBio, bio);
Packit Service 310c69
    }
Packit Service 310c69
    dataKVIOAsKVIO(dataKVIO)->bio = dataKVIO->dataBlockBio;
Packit Service 310c69
    dataKVIO->readBlock.data      = dataKVIO->dataBlock;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setBioBlockDevice(bio, getKernelLayerBdev(layer));
Packit Service 310c69
  bio->bi_end_io = completeAsyncBio;
Packit Service 310c69
  *dataKVIOPtr   = dataKVIO;
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void launchDataKVIOWork(KvdoWorkItem *item)
Packit Service 310c69
{
Packit Service 310c69
  runCallback(vioAsCompletion(workItemAsKVIO(item)->vio));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Continue discard processing for requests that span multiple physical blocks.
Packit Service 310c69
 * If all have been processed the KVIO is completed.  If we have already seen
Packit Service 310c69
 * an error, we skip the rest of the discard and fail immediately.
Packit Service 310c69
 *
Packit Service 310c69
 * 

Invoked in a request-queue thread after the discard of a block has

Packit Service 310c69
 * completed.
Packit Service 310c69
 *
Packit Service 310c69
 * @param completion  A completion representing the discard KVIO
Packit Service 310c69
 **/
Packit Service 310c69
static void kvdoContinueDiscardKVIO(VDOCompletion *completion)
Packit Service 310c69
{
Packit Service 310c69
  DataVIO     *dataVIO  = asDataVIO(completion);
Packit Service 310c69
  DataKVIO    *dataKVIO = dataVIOAsDataKVIO(dataVIO);
Packit Service 310c69
  KernelLayer *layer    = getLayerFromDataKVIO(dataKVIO);
Packit Service 310c69
  dataKVIO->remainingDiscard
Packit Service 310c69
    -= min(dataKVIO->remainingDiscard,
Packit Service 310c69
           (DiscardSize) (VDO_BLOCK_SIZE - dataKVIO->offset));
Packit Service 310c69
  if ((completion->result != VDO_SUCCESS)
Packit Service 310c69
      || (dataKVIO->remainingDiscard == 0)) {
Packit Service 310c69
    if (dataKVIO->hasDiscardPermit) {
Packit Service 310c69
      limiterRelease(&layer->discardLimiter);
Packit Service 310c69
      dataKVIO->hasDiscardPermit = false;
Packit Service 310c69
    }
Packit Service 310c69
    kvdoCompleteDataKVIO(completion);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  BIO *bio = getBIOFromDataKVIO(dataKVIO);
Packit Service 310c69
  resetBio(bio, layer);
Packit Service 310c69
  dataKVIO->isPartial = (dataKVIO->remainingDiscard < VDO_BLOCK_SIZE);
Packit Service 310c69
  dataKVIO->offset    = 0;
Packit Service 310c69
Packit Service 310c69
  VIOOperation operation;
Packit Service 310c69
  if (dataKVIO->isPartial) {
Packit Service 310c69
    operation  = VIO_READ_MODIFY_WRITE;
Packit Service 310c69
    setBioOperationRead(bio);
Packit Service 310c69
  } else {
Packit Service 310c69
    operation  = VIO_WRITE;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (requestorSetFUA(dataKVIO)) {
Packit Service 310c69
    operation |= VIO_FLUSH_AFTER;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  prepareDataVIO(dataVIO, dataVIO->logical.lbn + 1, operation,
Packit Service 310c69
                 !dataKVIO->isPartial, kvdoContinueDiscardKVIO);
Packit Service 310c69
  enqueueDataKVIO(dataKVIO, launchDataKVIOWork, completion->callback,
Packit Service 310c69
                  REQ_Q_ACTION_MAP_BIO);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Finish a partial read.
Packit Service 310c69
 *
Packit Service 310c69
 * @param completion  The partial read KVIO
Packit Service 310c69
 **/
Packit Service 310c69
static void kvdoCompletePartialRead(VDOCompletion *completion)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = dataVIOAsDataKVIO(asDataVIO(completion));
Packit Service 310c69
  dataKVIOAddTraceRecord(dataKVIO, THIS_LOCATION(NULL));
Packit Service 310c69
Packit Service 310c69
  bioCopyDataOut(dataKVIO->externalIORequest.bio,
Packit Service 310c69
                 dataKVIO->readBlock.data + dataKVIO->offset);
Packit Service 310c69
  kvdoCompleteDataKVIO(completion);
Packit Service 310c69
  return;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int kvdoLaunchDataKVIOFromBio(KernelLayer *layer,
Packit Service 310c69
                              BIO         *bio,
Packit Service 310c69
                              uint64_t     arrivalTime,
Packit Service 310c69
                              bool         hasDiscardPermit)
Packit Service 310c69
{
Packit Service 310c69
Packit Service 310c69
  DataKVIO *dataKVIO = NULL;
Packit Service 310c69
  int result = kvdoCreateKVIOFromBio(layer, bio, arrivalTime, &dataKVIO);
Packit Service 310c69
  if (unlikely(result != VDO_SUCCESS)) {
Packit Service 310c69
    logInfo("%s: KVIO allocation failure", __func__);
Packit Service 310c69
    if (hasDiscardPermit) {
Packit Service 310c69
      limiterRelease(&layer->discardLimiter);
Packit Service 310c69
    }
Packit Service 310c69
    limiterRelease(&layer->requestLimiter);
Packit Service 310c69
    return mapToSystemError(result);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Discards behave very differently than other requests when coming
Packit Service 310c69
   * in from device-mapper. We have to be able to handle any size discards
Packit Service 310c69
   * and with various sector offsets within a block.
Packit Service 310c69
   */
Packit Service 310c69
  KVIO         *kvio      = &dataKVIO->kvio;
Packit Service 310c69
  VDOAction    *callback  = kvdoCompleteDataKVIO;
Packit Service 310c69
  VIOOperation  operation = VIO_WRITE;
Packit Service 310c69
  bool          isTrim    = false;
Packit Service 310c69
  if (isDiscardBio(bio)) {
Packit Service 310c69
    dataKVIO->hasDiscardPermit = hasDiscardPermit;
Packit Service 310c69
    dataKVIO->remainingDiscard = getBioSize(bio);
Packit Service 310c69
    callback                   = kvdoContinueDiscardKVIO;
Packit Service 310c69
    if (dataKVIO->isPartial) {
Packit Service 310c69
      operation = VIO_READ_MODIFY_WRITE;
Packit Service 310c69
    } else {
Packit Service 310c69
      isTrim = true;
Packit Service 310c69
    }
Packit Service 310c69
  } else if (dataKVIO->isPartial) {
Packit Service 310c69
    if (bio_data_dir(bio) == READ) {
Packit Service 310c69
      callback  = kvdoCompletePartialRead;
Packit Service 310c69
      operation = VIO_READ;
Packit Service 310c69
    } else {
Packit Service 310c69
      operation = VIO_READ_MODIFY_WRITE;
Packit Service 310c69
    }
Packit Service 310c69
  } else if (bio_data_dir(bio) == READ) {
Packit Service 310c69
    operation = VIO_READ;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (requestorSetFUA(dataKVIO)) {
Packit Service 310c69
    operation |= VIO_FLUSH_AFTER;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  LogicalBlockNumber lbn
Packit Service 310c69
    = sectorToBlock(layer, getBioSector(bio) - layer->startingSectorOffset);
Packit Service 310c69
  prepareDataVIO(&dataKVIO->dataVIO, lbn, operation, isTrim, callback);
Packit Service 310c69
  enqueueKVIO(kvio, launchDataKVIOWork, vioAsCompletion(kvio->vio)->callback,
Packit Service 310c69
              REQ_Q_ACTION_MAP_BIO);
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Hash a DataKVIO and set its chunk name.
Packit Service 310c69
 *
Packit Service 310c69
 * @param item  The DataKVIO to be hashed
Packit Service 310c69
 **/
Packit Service 310c69
static void kvdoHashDataWork(KvdoWorkItem *item)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = workItemAsDataKVIO(item);
Packit Service 310c69
  DataVIO  *dataVIO  = &dataKVIO->dataVIO;
Packit Service 310c69
  dataVIOAddTraceRecord(dataVIO, THIS_LOCATION(NULL));
Packit Service 310c69
Packit Service 310c69
  MurmurHash3_x64_128(dataKVIO->dataBlock, VDO_BLOCK_SIZE, 0x62ea60be,
Packit Service 310c69
                      &dataVIO->chunkName);
Packit Service 310c69
  dataKVIO->dedupeContext.chunkName = &dataVIO->chunkName;
Packit Service 310c69
Packit Service 310c69
  kvdoEnqueueDataVIOCallback(dataKVIO);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoHashDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  dataVIOAddTraceRecord(dataVIO, THIS_LOCATION(NULL));
Packit Service 310c69
  launchDataKVIOOnCPUQueue(dataVIOAsDataKVIO(dataVIO), kvdoHashDataWork, NULL,
Packit Service 310c69
                           CPU_Q_ACTION_HASH_BLOCK);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoCheckForDuplication(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  dataVIOAddTraceRecord(dataVIO,
Packit Service 310c69
                        THIS_LOCATION("checkForDuplication;dup=post"));
Packit Service 310c69
  ASSERT_LOG_ONLY(!dataVIO->isZeroBlock,
Packit Service 310c69
                  "zero block not checked for duplication");
Packit Service 310c69
  ASSERT_LOG_ONLY(dataVIO->newMapped.state != MAPPING_STATE_UNMAPPED,
Packit Service 310c69
                  "discard not checked for duplication");
Packit Service 310c69
Packit Service 310c69
  DataKVIO *dataKVIO = dataVIOAsDataKVIO(dataVIO);
Packit Service 310c69
  if (hasAllocation(dataVIO)) {
Packit Service 310c69
    postDedupeAdvice(dataKVIO);
Packit Service 310c69
  } else {
Packit Service 310c69
    // This block has not actually been written (presumably because we are
Packit Service 310c69
    // full), so attempt to dedupe without posting bogus advice.
Packit Service 310c69
    queryDedupeAdvice(dataKVIO);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoUpdateDedupeAdvice(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  updateDedupeAdvice(dataVIOAsDataKVIO(dataVIO));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Implements BufferFreeFunction.
Packit Service 310c69
 **/
Packit Service 310c69
static void freePooledDataKVIO(void *poolData, void *data)
Packit Service 310c69
{
Packit Service 310c69
  if (data == NULL) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  DataKVIO    *dataKVIO = (DataKVIO *) data;
Packit Service 310c69
  KernelLayer *layer    = (KernelLayer *) poolData;
Packit Service 310c69
  if (WRITE_PROTECT_FREE_POOL) {
Packit Service 310c69
    setWriteProtect(dataKVIO, WP_DATA_KVIO_SIZE, false);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (dataKVIO->dataBlockBio != NULL) {
Packit Service 310c69
    freeBio(dataKVIO->dataBlockBio, layer);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (dataKVIO->readBlock.bio != NULL) {
Packit Service 310c69
    freeBio(dataKVIO->readBlock.bio, layer);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  FREE(dataKVIO->readBlock.buffer);
Packit Service 310c69
  FREE(dataKVIO->dataBlock);
Packit Service 310c69
  FREE(dataKVIO->scratchBlock);
Packit Service 310c69
  FREE(dataKVIO);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Allocate a DataKVIO. This function is the internals of makePooledDataKVIO().
Packit Service 310c69
 *
Packit Service 310c69
 * @param [in]  layer        The layer in which the DataKVIO will operate
Packit Service 310c69
 * @param [out] dataKVIOPtr  A pointer to hold the newly allocated DataKVIO
Packit Service 310c69
 *
Packit Service 310c69
 * @return VDO_SUCCESS or an error
Packit Service 310c69
 **/
Packit Service 310c69
static int allocatePooledDataKVIO(KernelLayer *layer, DataKVIO **dataKVIOPtr)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO;
Packit Service 310c69
  int result;
Packit Service 310c69
  if (WRITE_PROTECT_FREE_POOL) {
Packit Service 310c69
    STATIC_ASSERT(WP_DATA_KVIO_SIZE >= sizeof(DataKVIO));
Packit Service 310c69
    result = allocateMemory(WP_DATA_KVIO_SIZE, 0, __func__, &dataKVIO);
Packit Service 310c69
    if (result == VDO_SUCCESS) {
Packit Service 310c69
      BUG_ON((((size_t) dataKVIO) & (PAGE_SIZE - 1)) != 0);
Packit Service 310c69
    }
Packit Service 310c69
  } else {
Packit Service 310c69
    result = ALLOCATE(1, DataKVIO, __func__, &dataKVIO);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "DataKVIO allocation failure");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  STATIC_ASSERT(VDO_BLOCK_SIZE <= PAGE_SIZE);
Packit Service 310c69
  result = allocateMemory(VDO_BLOCK_SIZE, 0, "kvio data",
Packit Service 310c69
                          &dataKVIO->dataBlock);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    freePooledDataKVIO(layer, dataKVIO);
Packit Service 310c69
    return logErrorWithStringError(result, "DataKVIO data allocation failure");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = createBio(layer, dataKVIO->dataBlock, &dataKVIO->dataBlockBio);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    freePooledDataKVIO(layer, dataKVIO);
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "DataKVIO data bio allocation failure");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = allocateMemory(VDO_BLOCK_SIZE, 0, "kvio read buffer",
Packit Service 310c69
                          &dataKVIO->readBlock.buffer);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    freePooledDataKVIO(layer, dataKVIO);
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "DataKVIO read allocation failure");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = createBio(layer, dataKVIO->readBlock.buffer,
Packit Service 310c69
                     &dataKVIO->readBlock.bio);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    freePooledDataKVIO(layer, dataKVIO);
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "DataKVIO read bio allocation failure");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  dataKVIO->readBlock.bio->bi_private = &dataKVIO->kvio;
Packit Service 310c69
Packit Service 310c69
  result = allocateMemory(VDO_BLOCK_SIZE, 0, "kvio scratch",
Packit Service 310c69
                          &dataKVIO->scratchBlock);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    freePooledDataKVIO(layer, dataKVIO);
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "DataKVIO scratch allocation failure");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *dataKVIOPtr = dataKVIO;
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Implements BufferAllocateFunction.
Packit Service 310c69
 **/
Packit Service 310c69
static int makePooledDataKVIO(void *poolData, void **dataPtr)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = NULL;
Packit Service 310c69
  int result = allocatePooledDataKVIO((KernelLayer *) poolData, &dataKVIO);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    freePooledDataKVIO(poolData, dataKVIO);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *dataPtr = dataKVIO;
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Dump out the waiters on each DataVIO in the DataVIO buffer pool.
Packit Service 310c69
 *
Packit Service 310c69
 * @param queue   The queue to check (logical or physical)
Packit Service 310c69
 * @param waitOn  The label to print for queue (logical or physical)
Packit Service 310c69
 **/
Packit Service 310c69
static void dumpVIOWaiters(WaitQueue *queue, char *waitOn)
Packit Service 310c69
{
Packit Service 310c69
  Waiter *first = getFirstWaiter(queue);
Packit Service 310c69
  if (first == NULL) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  DataVIO *dataVIO = waiterAsDataVIO(first);
Packit Service 310c69
  logInfo("      %s is locked. Waited on by: VIO %" PRIptr " pbn %" PRIu64
Packit Service 310c69
          " lbn %llu d-pbn %llu lastOp %s",
Packit Service 310c69
          waitOn, dataVIO, getDataVIOAllocation(dataVIO),
Packit Service 310c69
          dataVIO->logical.lbn, dataVIO->duplicate.pbn,
Packit Service 310c69
          getOperationName(dataVIO));
Packit Service 310c69
Packit Service 310c69
  Waiter *waiter;
Packit Service 310c69
  for (waiter = first->nextWaiter;
Packit Service 310c69
       waiter != first;
Packit Service 310c69
       waiter = waiter->nextWaiter) {
Packit Service 310c69
    dataVIO = waiterAsDataVIO(waiter);
Packit Service 310c69
    logInfo("     ... and : VIO %" PRIptr " pbn %llu lbn %"
Packit Service 310c69
            PRIu64 " d-pbn %llu lastOp %s",
Packit Service 310c69
            dataVIO, getDataVIOAllocation(dataVIO), dataVIO->logical.lbn,
Packit Service 310c69
            dataVIO->duplicate.pbn, getOperationName(dataVIO));
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Encode various attributes of a VIO as a string of one-character flags for
Packit Service 310c69
 * dump logging. This encoding is for logging brevity:
Packit Service 310c69
 *
Packit Service 310c69
 * R => VIO completion result not VDO_SUCCESS
Packit Service 310c69
 * W => VIO is on a wait queue
Packit Service 310c69
 * D => VIO is a duplicate
Packit Service 310c69
 *
Packit Service 310c69
 * 

The common case of no flags set will result in an empty, null-terminated

Packit Service 310c69
 * buffer. If any flags are encoded, the first character in the string will be
Packit Service 310c69
 * a space character.
Packit Service 310c69
 *
Packit Service 310c69
 * @param dataVIO  The VIO to encode
Packit Service 310c69
 * @param buffer   The buffer to receive a null-terminated string of encoded
Packit Service 310c69
 *                 flag character
Packit Service 310c69
 **/
Packit Service 310c69
static void encodeVIODumpFlags(DataVIO *dataVIO, char buffer[8])
Packit Service 310c69
{
Packit Service 310c69
  char *pFlag = buffer;
Packit Service 310c69
  *pFlag++ = ' ';
Packit Service 310c69
  if (dataVIOAsCompletion(dataVIO)->result != VDO_SUCCESS) {
Packit Service 310c69
    *pFlag++ = 'R';
Packit Service 310c69
  }
Packit Service 310c69
  if (dataVIOAsAllocatingVIO(dataVIO)->waiter.nextWaiter != NULL) {
Packit Service 310c69
    *pFlag++ = 'W';
Packit Service 310c69
  }
Packit Service 310c69
  if (dataVIO->isDuplicate) {
Packit Service 310c69
    *pFlag++ = 'D';
Packit Service 310c69
  }
Packit Service 310c69
  if (pFlag == &buffer[1]) {
Packit Service 310c69
    // No flags, so remove the blank space.
Packit Service 310c69
    pFlag = buffer;
Packit Service 310c69
  }
Packit Service 310c69
  *pFlag = '\0';
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Dump out info on a DataKVIO from the DataKVIO pool.
Packit Service 310c69
 *
Packit Service 310c69
 * 

Implements BufferDumpFunction.

Packit Service 310c69
 *
Packit Service 310c69
 * @param poolData  The pool data
Packit Service 310c69
 * @param data      The DataKVIO to dump
Packit Service 310c69
 **/
Packit Service 310c69
static void dumpPooledDataKVIO(void *poolData __attribute__((unused)),
Packit Service 310c69
                               void *data)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = (DataKVIO *) data;
Packit Service 310c69
  DataVIO  *dataVIO  = &dataKVIO->dataVIO;
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * This just needs to be big enough to hold a queue (thread) name
Packit Service 310c69
   * and a function name (plus a separator character and NUL). The
Packit Service 310c69
   * latter is limited only by taste.
Packit Service 310c69
   *
Packit Service 310c69
   * In making this static, we're assuming only one "dump" will run at
Packit Service 310c69
   * a time. If more than one does run, the log output will be garbled
Packit Service 310c69
   * anyway.
Packit Service 310c69
   */
Packit Service 310c69
  static char vioWorkItemDumpBuffer[100 + MAX_QUEUE_NAME_LEN];
Packit Service 310c69
  /*
Packit Service 310c69
   * We're likely to be logging a couple thousand of these lines, and
Packit Service 310c69
   * in some circumstances syslogd may have trouble keeping up, so
Packit Service 310c69
   * keep it BRIEF rather than user-friendly.
Packit Service 310c69
   */
Packit Service 310c69
  dumpWorkItemToBuffer(&dataKVIO->kvio.enqueueable.workItem,
Packit Service 310c69
                       vioWorkItemDumpBuffer, sizeof(vioWorkItemDumpBuffer));
Packit Service 310c69
  // Another static buffer...
Packit Service 310c69
  // log10(256) = 2.408+, round up:
Packit Service 310c69
  enum { DECIMAL_DIGITS_PER_UINT64_T = (int) (1 + 2.41 * sizeof(uint64_t)) };
Packit Service 310c69
  static char vioBlockNumberDumpBuffer[sizeof("P L D")
Packit Service 310c69
                                       + 3 * DECIMAL_DIGITS_PER_UINT64_T];
Packit Service 310c69
  if (dataVIO->isDuplicate) {
Packit Service 310c69
    snprintf(vioBlockNumberDumpBuffer, sizeof(vioBlockNumberDumpBuffer),
Packit Service 310c69
             "P%llu L%llu D%llu",
Packit Service 310c69
             getDataVIOAllocation(dataVIO), dataVIO->logical.lbn,
Packit Service 310c69
             dataVIO->duplicate.pbn);
Packit Service 310c69
  } else if (hasAllocation(dataVIO)) {
Packit Service 310c69
    snprintf(vioBlockNumberDumpBuffer, sizeof(vioBlockNumberDumpBuffer),
Packit Service 310c69
             "P%llu L%llu",
Packit Service 310c69
             getDataVIOAllocation(dataVIO), dataVIO->logical.lbn);
Packit Service 310c69
  } else {
Packit Service 310c69
    snprintf(vioBlockNumberDumpBuffer, sizeof(vioBlockNumberDumpBuffer),
Packit Service 310c69
             "L%llu",
Packit Service 310c69
             dataVIO->logical.lbn);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  static char vioFlushGenerationBuffer[sizeof(" FG")
Packit Service 310c69
                                       + DECIMAL_DIGITS_PER_UINT64_T] = "";
Packit Service 310c69
  if (dataVIO->flushGeneration != 0) {
Packit Service 310c69
    snprintf(vioFlushGenerationBuffer, sizeof(vioFlushGenerationBuffer),
Packit Service 310c69
             " FG%llu", dataVIO->flushGeneration);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Encode VIO attributes as a string of one-character flags, usually empty.
Packit Service 310c69
  static char flagsDumpBuffer[8];
Packit Service 310c69
  encodeVIODumpFlags(dataVIO, flagsDumpBuffer);
Packit Service 310c69
Packit Service 310c69
  logInfo("  kvio %" PRIptr " %s%s %s %s%s",
Packit Service 310c69
          dataKVIO, vioBlockNumberDumpBuffer, vioFlushGenerationBuffer,
Packit Service 310c69
          getOperationName(dataVIO), vioWorkItemDumpBuffer, flagsDumpBuffer);
Packit Service 310c69
  // might want info on: wantAlbireoAnswer / operation / status
Packit Service 310c69
  // might want info on: bio / bioToSubmit / biosMerged
Packit Service 310c69
Packit Service 310c69
  dumpVIOWaiters(&dataVIO->logical.waiters, "lbn");
Packit Service 310c69
Packit Service 310c69
  // might want to dump more info from VIO here
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int makeDataKVIOBufferPool(KernelLayer  *layer,
Packit Service 310c69
                           uint32_t      poolSize,
Packit Service 310c69
                           BufferPool  **bufferPoolPtr)
Packit Service 310c69
{
Packit Service 310c69
  return makeBufferPool("DataKVIO Pool", poolSize,
Packit Service 310c69
                        makePooledDataKVIO, freePooledDataKVIO,
Packit Service 310c69
                        dumpPooledDataKVIO, layer, bufferPoolPtr);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
DataLocation getDedupeAdvice(const DedupeContext *context)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = container_of(context, DataKVIO, dedupeContext);
Packit Service 310c69
  return (DataLocation) {
Packit Service 310c69
    .state = dataKVIO->dataVIO.newMapped.state,
Packit Service 310c69
    .pbn   = dataKVIO->dataVIO.newMapped.pbn,
Packit Service 310c69
  };
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void setDedupeAdvice(DedupeContext *context, const DataLocation *advice)
Packit Service 310c69
{
Packit Service 310c69
  DataKVIO *dataKVIO = container_of(context, DataKVIO, dedupeContext);
Packit Service 310c69
  receiveDedupeAdvice(&dataKVIO->dataVIO, advice);
Packit Service 310c69
}