Blame source/vdo/kernel/kernelLayer.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/kernelLayer.c#38 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "kernelLayer.h"
Packit Service 310c69
Packit Service 310c69
#include <linux/backing-dev.h>
Packit Service 310c69
#include <linux/blkdev.h>
Packit Service 310c69
#include <linux/crc32.h>
Packit Service 310c69
#include <linux/delay.h>
Packit Service 310c69
#include <linux/module.h>
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 "lz4.h"
Packit Service 310c69
#include "releaseVersions.h"
Packit Service 310c69
#include "volumeGeometry.h"
Packit Service 310c69
#include "statistics.h"
Packit Service 310c69
#include "vdo.h"
Packit Service 310c69
Packit Service 310c69
#include "bio.h"
Packit Service 310c69
#include "dataKVIO.h"
Packit Service 310c69
#include "dedupeIndex.h"
Packit Service 310c69
#include "deviceConfig.h"
Packit Service 310c69
#include "deviceRegistry.h"
Packit Service 310c69
#include "instanceNumber.h"
Packit Service 310c69
#include "ioSubmitter.h"
Packit Service 310c69
#include "kvdoFlush.h"
Packit Service 310c69
#include "kvio.h"
Packit Service 310c69
#include "poolSysfs.h"
Packit Service 310c69
#include "statusProcfs.h"
Packit Service 310c69
#include "stringUtils.h"
Packit Service 310c69
#include "verify.h"
Packit Service 310c69
Packit Service 310c69
enum {
Packit Service 310c69
  DEDUPE_TIMEOUT_REPORT_INTERVAL = 1000,
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
static const KvdoWorkQueueType bioAckQType = {
Packit Service 310c69
  .actionTable = {
Packit Service 310c69
    { .name = "bio_ack",
Packit Service 310c69
      .code = BIO_ACK_Q_ACTION_ACK,
Packit Service 310c69
      .priority = 0 },
Packit Service 310c69
  },
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
static const KvdoWorkQueueType cpuQType = {
Packit Service 310c69
  .actionTable = {
Packit Service 310c69
    { .name = "cpu_complete_kvio",
Packit Service 310c69
      .code = CPU_Q_ACTION_COMPLETE_KVIO,
Packit Service 310c69
      .priority = 0 },
Packit Service 310c69
    { .name = "cpu_compress_block",
Packit Service 310c69
      .code = CPU_Q_ACTION_COMPRESS_BLOCK,
Packit Service 310c69
      .priority = 0 },
Packit Service 310c69
    { .name = "cpu_hash_block",
Packit Service 310c69
      .code = CPU_Q_ACTION_HASH_BLOCK,
Packit Service 310c69
      .priority = 0 },
Packit Service 310c69
    { .name = "cpu_event_reporter",
Packit Service 310c69
      .code = CPU_Q_ACTION_EVENT_REPORTER,
Packit Service 310c69
      .priority = 0 },
Packit Service 310c69
  },
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
// 2000 is half the number of entries currently in our page cache,
Packit Service 310c69
// to allow for each in-progress operation to update two pages.
Packit Service 310c69
int defaultMaxRequestsActive = 2000;
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static CRC32Checksum kvdoUpdateCRC32(CRC32Checksum  crc,
Packit Service 310c69
                                     const byte    *buffer,
Packit Service 310c69
                                     size_t         length)
Packit Service 310c69
{
Packit Service 310c69
  /*
Packit Service 310c69
   * The kernel's CRC 32 implementation does not do pre- and post-
Packit Service 310c69
   * conditioning, so do it ourselves.
Packit Service 310c69
   */
Packit Service 310c69
  return crc32(crc ^ 0xffffffff, buffer, length) ^ 0xffffffff;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static BlockCount kvdoGetBlockCount(PhysicalLayer *header)
Packit Service 310c69
{
Packit Service 310c69
  return asKernelLayer(header)->deviceConfig->physicalBlocks;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool layerIsNamed(KernelLayer *layer, void *context)
Packit Service 310c69
{
Packit Service 310c69
  struct dm_target *ti = layer->deviceConfig->owningTarget;
Packit Service 310c69
  const char *deviceName = dm_device_name(dm_table_get_md(ti->table));
Packit Service 310c69
  return (strcmp(deviceName, (const char *) context) == 0);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Implements LayerFilter.
Packit Service 310c69
 **/
Packit Service 310c69
static bool layerUsesDevice(KernelLayer *layer, void *context)
Packit Service 310c69
{
Packit Service 310c69
  DeviceConfig *config = context;
Packit Service 310c69
  return (layer->deviceConfig->ownedDevice->bdev->bd_dev
Packit Service 310c69
          == config->ownedDevice->bdev->bd_dev);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
int mapToSystemError(int error)
Packit Service 310c69
{
Packit Service 310c69
  // 0 is success, negative a system error code
Packit Service 310c69
  if (likely(error <= 0)) {
Packit Service 310c69
    return error;
Packit Service 310c69
  }
Packit Service 310c69
  if (error < 1024) {
Packit Service 310c69
    // errno macro used without negating - may be a minor bug
Packit Service 310c69
    return -error;
Packit Service 310c69
  }
Packit Service 310c69
  // VDO or UDS error
Packit Service 310c69
  char errorName[80], errorMessage[ERRBUF_SIZE];
Packit Service 310c69
  switch (sansUnrecoverable(error)) {
Packit Service 310c69
  case VDO_NO_SPACE:
Packit Service 310c69
    return -ENOSPC;
Packit Service 310c69
  case VDO_READ_ONLY:
Packit Service 310c69
    return -EIO;
Packit Service 310c69
  default:
Packit Service 310c69
    logInfo("%s: mapping internal status code %d (%s: %s) to EIO",
Packit Service 310c69
            __func__, error,
Packit Service 310c69
            stringErrorName(error, errorName, sizeof(errorName)),
Packit Service 310c69
            stringError(error, errorMessage, sizeof(errorMessage)));
Packit Service 310c69
    return -EIO;
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void setKernelLayerState(KernelLayer *layer, KernelLayerState newState)
Packit Service 310c69
{
Packit Service 310c69
  atomicStore32(&layer->state, newState);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void waitForNoRequestsActive(KernelLayer *layer)
Packit Service 310c69
{
Packit Service 310c69
  // Do nothing if there are no requests active.  This check is not necessary
Packit Service 310c69
  // for correctness but does reduce log message traffic.
Packit Service 310c69
  if (limiterIsIdle(&layer->requestLimiter)) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // We have to make sure to flush the packer before waiting. We do this
Packit Service 310c69
  // by turning off compression, which also means no new entries coming in
Packit Service 310c69
  // while waiting will end up in the packer.
Packit Service 310c69
  bool wasCompressing = setKVDOCompressing(&layer->kvdo, false);
Packit Service 310c69
  // Now wait for there to be no active requests
Packit Service 310c69
  limiterWaitForIdle(&layer->requestLimiter);
Packit Service 310c69
  // Reset the compression state after all requests are done
Packit Service 310c69
  if (wasCompressing) {
Packit Service 310c69
    setKVDOCompressing(&layer->kvdo, true);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Start processing a new data KVIO based on the supplied bio, but from within
Packit Service 310c69
 * a VDO thread context, when we're not allowed to block. Using this path at
Packit Service 310c69
 * all suggests a bug or erroneous usage, but we special-case it to avoid a
Packit Service 310c69
 * deadlock that can apparently result. Message will be logged to alert the
Packit Service 310c69
 * administrator that something has gone wrong, while we attempt to continue
Packit Service 310c69
 * processing other requests.
Packit Service 310c69
 *
Packit Service 310c69
 * If a request permit can be acquired immediately, kvdoLaunchDataKVIOFromBio
Packit Service 310c69
 * will be called. (If the bio is a discard operation, a permit from the
Packit Service 310c69
 * discard limiter will be requested but the call will be made with or without
Packit Service 310c69
 * it.) If the request permit is not available, the bio will be saved on a list
Packit Service 310c69
 * to be launched later. Either way, this function will not block, and will
Packit Service 310c69
 * take responsibility for processing the bio.
Packit Service 310c69
 *
Packit Service 310c69
 * @param layer        The kernel layer
Packit Service 310c69
 * @param bio          The bio to launch
Packit Service 310c69
 * @param arrivalTime  The arrival time of the bio
Packit Service 310c69
 *
Packit Service 310c69
 * @return  DM_MAPIO_SUBMITTED or a system error code
Packit Service 310c69
 **/
Packit Service 310c69
static int launchDataKVIOFromVDOThread(KernelLayer *layer,
Packit Service 310c69
                                       BIO         *bio,
Packit Service 310c69
                                       Jiffies      arrivalTime)
Packit Service 310c69
{
Packit Service 310c69
  logWarning("kvdoMapBio called from within a VDO thread!");
Packit Service 310c69
  /*
Packit Service 310c69
   * We're not yet entirely sure what circumstances are causing this situation
Packit Service 310c69
   * in [ESC-638], but it does appear to be happening and causing VDO to
Packit Service 310c69
   * deadlock.
Packit Service 310c69
   *
Packit Service 310c69
   * Somehow kvdoMapBio is being called from generic_make_request which is
Packit Service 310c69
   * being called from the VDO code to pass a flush on down to the underlying
Packit Service 310c69
   * storage system; we've got 2000 requests in progress, so we have to wait
Packit Service 310c69
   * for one to complete, but none can complete while the bio thread is blocked
Packit Service 310c69
   * from passing more I/O requests down. Near as we can tell, the flush bio
Packit Service 310c69
   * should always have gotten updated to point to the storage system, so we
Packit Service 310c69
   * shouldn't be calling back into VDO unless something's gotten messed up
Packit Service 310c69
   * somewhere.
Packit Service 310c69
   *
Packit Service 310c69
   * To side-step this case, if the limiter says we're busy *and* we're running
Packit Service 310c69
   * on one of VDO's own threads, we'll drop the I/O request in a special queue
Packit Service 310c69
   * for processing as soon as KVIOs become free.
Packit Service 310c69
   *
Packit Service 310c69
   * We don't want to do this in general because it leads to unbounded
Packit Service 310c69
   * buffering, arbitrarily high latencies, inability to push back in a way the
Packit Service 310c69
   * caller can take advantage of, etc. If someone wants huge amounts of
Packit Service 310c69
   * buffering on top of VDO, they're welcome to access it through the kernel
Packit Service 310c69
   * page cache or roll their own.
Packit Service 310c69
   */
Packit Service 310c69
  if (!limiterPoll(&layer->requestLimiter)) {
Packit Service 310c69
    addToDeadlockQueue(&layer->deadlockQueue, bio, arrivalTime);
Packit Service 310c69
    logWarning("queued an I/O request to avoid deadlock!");
Packit Service 310c69
Packit Service 310c69
    return DM_MAPIO_SUBMITTED;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  bool hasDiscardPermit
Packit Service 310c69
    = (isDiscardBio(bio) && limiterPoll(&layer->discardLimiter));
Packit Service 310c69
  int result = kvdoLaunchDataKVIOFromBio(layer, bio, arrivalTime,
Packit Service 310c69
                                         hasDiscardPermit);
Packit Service 310c69
  // Succeed or fail, kvdoLaunchDataKVIOFromBio owns the permit(s) now.
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return DM_MAPIO_SUBMITTED;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int kvdoMapBio(KernelLayer *layer, BIO *bio)
Packit Service 310c69
{
Packit Service 310c69
  Jiffies          arrivalTime = jiffies;
Packit Service 310c69
  KernelLayerState state       = getKernelLayerState(layer);
Packit Service 310c69
  ASSERT_LOG_ONLY(state == LAYER_RUNNING,
Packit Service 310c69
                  "kvdoMapBio should not be called while in state %d", state);
Packit Service 310c69
Packit Service 310c69
  // Count all incoming bios.
Packit Service 310c69
  countBios(&layer->biosIn, bio);
Packit Service 310c69
Packit Service 310c69
  // Handle empty bios.  Empty flush bios are not associated with a VIO.
Packit Service 310c69
  if (isFlushBio(bio)) {
Packit Service 310c69
    if (ASSERT(getBioSize(bio) == 0, "Flush bio is size 0") != VDO_SUCCESS) {
Packit Service 310c69
      // We expect flushes to be of size 0.
Packit Service 310c69
      return -EINVAL;
Packit Service 310c69
    }
Packit Service 310c69
    if (shouldProcessFlush(layer)) {
Packit Service 310c69
      launchKVDOFlush(layer, bio);
Packit Service 310c69
      return DM_MAPIO_SUBMITTED;
Packit Service 310c69
    } else {
Packit Service 310c69
      // We're not acknowledging this bio now, but we'll never touch it
Packit Service 310c69
      // again, so this is the last chance to account for it.
Packit Service 310c69
      countBios(&layer->biosAcknowledged, bio);
Packit Service 310c69
      atomic64_inc(&layer->flushOut);
Packit Service 310c69
      setBioBlockDevice(bio, getKernelLayerBdev(layer));
Packit Service 310c69
      return DM_MAPIO_REMAPPED;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (ASSERT(getBioSize(bio) != 0, "Data bio is not size 0") != VDO_SUCCESS) {
Packit Service 310c69
    // We expect non-flushes to be non-zero in size.
Packit Service 310c69
    return -EINVAL;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (isDiscardBio(bio) && isReadBio(bio)) {
Packit Service 310c69
    // Read and Discard should never occur together
Packit Service 310c69
    return -EIO;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  KvdoWorkQueue *currentWorkQueue = getCurrentWorkQueue();
Packit Service 310c69
  if ((currentWorkQueue != NULL)
Packit Service 310c69
      && (layer == getWorkQueueOwner(currentWorkQueue))) {
Packit Service 310c69
    /*
Packit Service 310c69
     * This prohibits sleeping during I/O submission to VDO from its own
Packit Service 310c69
     * thread.
Packit Service 310c69
     */
Packit Service 310c69
    return launchDataKVIOFromVDOThread(layer, bio, arrivalTime);
Packit Service 310c69
  }
Packit Service 310c69
  bool hasDiscardPermit = false;
Packit Service 310c69
  if (isDiscardBio(bio)) {
Packit Service 310c69
    limiterWaitForOneFree(&layer->discardLimiter);
Packit Service 310c69
    hasDiscardPermit = true;
Packit Service 310c69
  }
Packit Service 310c69
  limiterWaitForOneFree(&layer->requestLimiter);
Packit Service 310c69
Packit Service 310c69
  int result = kvdoLaunchDataKVIOFromBio(layer, bio, arrivalTime,
Packit Service 310c69
                                         hasDiscardPermit);
Packit Service 310c69
  // Succeed or fail, kvdoLaunchDataKVIOFromBio owns the permit(s) now.
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return DM_MAPIO_SUBMITTED;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
struct block_device *getKernelLayerBdev(const KernelLayer *layer)
Packit Service 310c69
{
Packit Service 310c69
  return layer->deviceConfig->ownedDevice->bdev;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void completeManyRequests(KernelLayer *layer, uint32_t count)
Packit Service 310c69
{
Packit Service 310c69
  // If we had to buffer some requests to avoid deadlock, release them now.
Packit Service 310c69
  while (count > 0) {
Packit Service 310c69
    Jiffies arrivalTime = 0;
Packit Service 310c69
    BIO *bio = pollDeadlockQueue(&layer->deadlockQueue, &arrivalTime);
Packit Service 310c69
    if (likely(bio == NULL)) {
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    bool hasDiscardPermit
Packit Service 310c69
      = (isDiscardBio(bio) && limiterPoll(&layer->discardLimiter));
Packit Service 310c69
    int result = kvdoLaunchDataKVIOFromBio(layer, bio, arrivalTime,
Packit Service 310c69
                                           hasDiscardPermit);
Packit Service 310c69
    if (result != VDO_SUCCESS) {
Packit Service 310c69
      completeBio(bio, result);
Packit Service 310c69
    }
Packit Service 310c69
    // Succeed or fail, kvdoLaunchDataKVIOFromBio owns the permit(s) now.
Packit Service 310c69
    count--;
Packit Service 310c69
  }
Packit Service 310c69
  // Notify the limiter, so it can wake any blocked processes.
Packit Service 310c69
  if (count > 0) {
Packit Service 310c69
    limiterReleaseMany(&layer->requestLimiter, count);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void reportEvents(PeriodicEventReporter *reporter)
Packit Service 310c69
{
Packit Service 310c69
  atomic_set(&reporter->workItemQueued, 0);
Packit Service 310c69
  uint64_t newValue = atomic64_read(&reporter->value);
Packit Service 310c69
  uint64_t difference = newValue - reporter->lastReportedValue;
Packit Service 310c69
  if (difference != 0) {
Packit Service 310c69
    logDebug(reporter->format, difference);
Packit Service 310c69
    reporter->lastReportedValue = newValue;
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void reportEventsWork(KvdoWorkItem *item)
Packit Service 310c69
{
Packit Service 310c69
  PeriodicEventReporter *reporter = container_of(item, PeriodicEventReporter,
Packit Service 310c69
                                                 workItem);
Packit Service 310c69
  reportEvents(reporter);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void initPeriodicEventReporter(PeriodicEventReporter *reporter,
Packit Service 310c69
                                      const char            *format,
Packit Service 310c69
                                      unsigned long          reportingInterval,
Packit Service 310c69
                                      KernelLayer           *layer)
Packit Service 310c69
{
Packit Service 310c69
  setupWorkItem(&reporter->workItem, reportEventsWork, NULL,
Packit Service 310c69
                CPU_Q_ACTION_EVENT_REPORTER);
Packit Service 310c69
  reporter->format            = format;
Packit Service 310c69
  reporter->reportingInterval = msecs_to_jiffies(reportingInterval);
Packit Service 310c69
  reporter->layer             = layer;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void addEventCount(PeriodicEventReporter *reporter, unsigned int count)
Packit Service 310c69
{
Packit Service 310c69
  if (count > 0) {
Packit Service 310c69
    atomic64_add(count, &reporter->value);
Packit Service 310c69
    int oldWorkItemQueued = atomic_xchg(&reporter->workItemQueued, 1);
Packit Service 310c69
    if (oldWorkItemQueued == 0) {
Packit Service 310c69
      enqueueWorkQueueDelayed(reporter->layer->cpuQueue,
Packit Service 310c69
                              &reporter->workItem,
Packit Service 310c69
                              jiffies + reporter->reportingInterval);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void stopPeriodicEventReporter(PeriodicEventReporter *reporter)
Packit Service 310c69
{
Packit Service 310c69
  reportEvents(reporter);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void kvdoReportDedupeTimeout(KernelLayer *layer, unsigned int expiredCount)
Packit Service 310c69
{
Packit Service 310c69
  addEventCount(&layer->albireoTimeoutReporter, expiredCount);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int kvdoCreateEnqueueable(VDOCompletion *completion)
Packit Service 310c69
{
Packit Service 310c69
  KvdoEnqueueable *kvdoEnqueueable;
Packit Service 310c69
  int result = ALLOCATE(1, KvdoEnqueueable, "kvdoEnqueueable",
Packit Service 310c69
                        &kvdoEnqueueable);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    logError("kvdoEnqueueable allocation failure %d", result);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  kvdoEnqueueable->enqueueable.completion = completion;
Packit Service 310c69
  completion->enqueueable                 = &kvdoEnqueueable->enqueueable;
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void kvdoDestroyEnqueueable(Enqueueable **enqueueablePtr)
Packit Service 310c69
{
Packit Service 310c69
  Enqueueable *enqueueable = *enqueueablePtr;
Packit Service 310c69
  if (enqueueable != NULL) {
Packit Service 310c69
    KvdoEnqueueable *kvdoEnqueueable
Packit Service 310c69
      = container_of(enqueueable, KvdoEnqueueable, enqueueable);
Packit Service 310c69
    FREE(kvdoEnqueueable);
Packit Service 310c69
    *enqueueablePtr = NULL;
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Implements BufferAllocator.
Packit Service 310c69
 **/
Packit Service 310c69
static int kvdoAllocateIOBuffer(PhysicalLayer  *layer __attribute__((unused)),
Packit Service 310c69
                                size_t          bytes,
Packit Service 310c69
                                const char     *why,
Packit Service 310c69
                                char          **bufferPtr)
Packit Service 310c69
{
Packit Service 310c69
  return ALLOCATE(bytes, char, why, bufferPtr);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Implements ExtentReader. Exists only for the geometry block; is unset after
Packit Service 310c69
 * it is read.
Packit Service 310c69
 **/
Packit Service 310c69
static int kvdoSynchronousRead(PhysicalLayer       *layer,
Packit Service 310c69
                               PhysicalBlockNumber  startBlock,
Packit Service 310c69
                               size_t               blockCount,
Packit Service 310c69
                               char                *buffer,
Packit Service 310c69
                               size_t              *blocksRead)
Packit Service 310c69
{
Packit Service 310c69
  if (blockCount != 1) {
Packit Service 310c69
    return VDO_NOT_IMPLEMENTED;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  KernelLayer *kernelLayer = asKernelLayer(layer);
Packit Service 310c69
Packit Service 310c69
  BIO *bio;
Packit Service 310c69
  int result = createBio(kernelLayer, buffer, &bio;;
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  setBioBlockDevice(bio, getKernelLayerBdev(kernelLayer));
Packit Service 310c69
  setBioSector(bio, blockToSector(kernelLayer, startBlock));
Packit Service 310c69
  setBioOperationRead(bio);
Packit Service 310c69
  result = submitBioAndWait(bio);
Packit Service 310c69
  if (result != 0) {
Packit Service 310c69
    logErrorWithStringError(result, "synchronous read failed");
Packit Service 310c69
    result = -EIO;
Packit Service 310c69
  }
Packit Service 310c69
  freeBio(bio, kernelLayer);
Packit Service 310c69
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  if (blocksRead != NULL) {
Packit Service 310c69
    *blocksRead = blockCount;
Packit Service 310c69
  }
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Implements VIODestructor.
Packit Service 310c69
 **/
Packit Service 310c69
static void kvdoFreeVIO(VIO **vioPtr)
Packit Service 310c69
{
Packit Service 310c69
  VIO *vio = *vioPtr;
Packit Service 310c69
  if (vio == NULL) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  BUG_ON(isDataVIO(vio));
Packit Service 310c69
Packit Service 310c69
  if (isCompressedWriteVIO(vio)) {
Packit Service 310c69
    CompressedWriteKVIO *compressedWriteKVIO
Packit Service 310c69
      = allocatingVIOAsCompressedWriteKVIO(vioAsAllocatingVIO(vio));
Packit Service 310c69
    freeCompressedWriteKVIO(&compressedWriteKVIO);
Packit Service 310c69
  } else {
Packit Service 310c69
    MetadataKVIO *metadataKVIO = vioAsMetadataKVIO(vio);
Packit Service 310c69
    freeMetadataKVIO(&metadataKVIO);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *vioPtr = NULL;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static WritePolicy kvdoGetWritePolicy(PhysicalLayer *common)
Packit Service 310c69
{
Packit Service 310c69
  KernelLayer *layer = asKernelLayer(common);
Packit Service 310c69
  return getKVDOWritePolicy(&layer->kvdo);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Function that is called when a synchronous operation is completed. We let
Packit Service 310c69
 * the waiting thread know it can continue.
Packit Service 310c69
 *
Packit Service 310c69
 * 

Implements OperationComplete.

Packit Service 310c69
 *
Packit Service 310c69
 * @param common  The kernel layer
Packit Service 310c69
 **/
Packit Service 310c69
static void kvdoCompleteSyncOperation(PhysicalLayer *common)
Packit Service 310c69
{
Packit Service 310c69
  KernelLayer *layer = asKernelLayer(common);
Packit Service 310c69
  complete(&layer->callbackSync);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Wait for a synchronous operation to complete.
Packit Service 310c69
 *
Packit Service 310c69
 * 

Implements OperationWaiter.

Packit Service 310c69
 *
Packit Service 310c69
 * @param common  The kernel layer
Packit Service 310c69
 **/
Packit Service 310c69
static void waitForSyncOperation(PhysicalLayer *common)
Packit Service 310c69
{
Packit Service 310c69
  KernelLayer *layer = asKernelLayer(common);
Packit Service 310c69
  // Using the "interruptible" interface means that Linux will not log a
Packit Service 310c69
  // message when we wait for more than 120 seconds.
Packit Service 310c69
  while (wait_for_completion_interruptible(&layer->callbackSync) != 0) {
Packit Service 310c69
    // However, if we get a signal in a user-mode process, we could
Packit Service 310c69
    // spin...
Packit Service 310c69
    msleep(1);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Make the bio set for allocating new bios.
Packit Service 310c69
 *
Packit Service 310c69
 * @param layer  The kernel layer
Packit Service 310c69
 *
Packit Service 310c69
 * @returns VDO_SUCCESS if bio set created, error code otherwise
Packit Service 310c69
 **/
Packit Service 310c69
static int makeDedupeBioSet(KernelLayer *layer)
Packit Service 310c69
{
Packit Service 310c69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
Packit Service 310c69
  int result = ALLOCATE(1, struct bio_set, "bio set", &layer->bioset);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = bioset_init(layer->bioset, 0, 0, BIOSET_NEED_BVECS);
Packit Service 310c69
  if (result != 0) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
#else
Packit Service 310c69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
Packit Service 310c69
  layer->bioset = bioset_create(0, 0, BIOSET_NEED_BVECS);
Packit Service 310c69
#else
Packit Service 310c69
  layer->bioset = bioset_create(0, 0);
Packit Service 310c69
#endif
Packit Service 310c69
  if (layer->bioset == NULL) {
Packit Service 310c69
    return -ENOMEM;
Packit Service 310c69
  }
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int makeKernelLayer(uint64_t        startingSector,
Packit Service 310c69
                    unsigned int    instance,
Packit Service 310c69
                    DeviceConfig   *config,
Packit Service 310c69
                    struct kobject *parentKobject,
Packit Service 310c69
                    ThreadConfig  **threadConfigPointer,
Packit Service 310c69
                    char          **reason,
Packit Service 310c69
                    KernelLayer   **layerPtr)
Packit Service 310c69
{
Packit Service 310c69
  // VDO-3769 - Set a generic reason so we don't ever return garbage.
Packit Service 310c69
  *reason = "Unspecified error";
Packit Service 310c69
Packit Service 310c69
  KernelLayer *oldLayer = findLayerMatching(layerUsesDevice, config);
Packit Service 310c69
  if (oldLayer != NULL) {
Packit Service 310c69
    logError("Existing layer named %s already uses device %s",
Packit Service 310c69
             oldLayer->deviceConfig->poolName,
Packit Service 310c69
	     oldLayer->deviceConfig->parentDeviceName);
Packit Service 310c69
    *reason = "Cannot share storage device with already-running VDO";
Packit Service 310c69
    return VDO_BAD_CONFIGURATION;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Part 1 - Allocate the kernel layer, its essential parts, and setup up the
Packit Service 310c69
   * sysfs node.  These must come first so that the sysfs node works correctly
Packit Service 310c69
   * through the freeing of the kernel layer.  After this part you must use
Packit Service 310c69
   * freeKernelLayer.
Packit Service 310c69
   */
Packit Service 310c69
  KernelLayer *layer;
Packit Service 310c69
  int result = ALLOCATE(1, KernelLayer, "VDO configuration", &layer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot allocate VDO configuration";
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Allow the base VDO to allocate buffers and construct or destroy
Packit Service 310c69
  // enqueuables as part of its allocation.
Packit Service 310c69
  layer->common.allocateIOBuffer   = kvdoAllocateIOBuffer;
Packit Service 310c69
  layer->common.createEnqueueable  = kvdoCreateEnqueueable;
Packit Service 310c69
  layer->common.destroyEnqueueable = kvdoDestroyEnqueueable;
Packit Service 310c69
Packit Service 310c69
  result = allocateVDO(&layer->common, &layer->kvdo.vdo);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot allocate VDO";
Packit Service 310c69
    FREE(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // After this point, calling kobject_put on kobj will decrement its
Packit Service 310c69
  // reference count, and when the count goes to 0 the KernelLayer will
Packit Service 310c69
  // be freed.
Packit Service 310c69
  kobject_init(&layer->kobj, &kernelLayerKobjType);
Packit Service 310c69
  result = kobject_add(&layer->kobj, parentKobject, config->poolName);
Packit Service 310c69
  if (result != 0) {
Packit Service 310c69
    *reason = "Cannot add sysfs node";
Packit Service 310c69
    kobject_put(&layer->kobj);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  kobject_init(&layer->wqDirectory, &workQueueDirectoryKobjType);
Packit Service 310c69
  result = kobject_add(&layer->wqDirectory, &layer->kobj, "work_queues");
Packit Service 310c69
  if (result != 0) {
Packit Service 310c69
    *reason = "Cannot add sysfs node";
Packit Service 310c69
    kobject_put(&layer->wqDirectory);
Packit Service 310c69
    kobject_put(&layer->kobj);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Part 2 - Do all the simple initialization.  These initializations have no
Packit Service 310c69
   * order dependencies and can be done in any order, but freeKernelLayer()
Packit Service 310c69
   * cannot be called until all the simple layer properties are set.
Packit Service 310c69
   *
Packit Service 310c69
   * The KernelLayer structure starts as all zeros.  Pointer initializations
Packit Service 310c69
   * consist of replacing a NULL pointer with a non-NULL pointer, which can be
Packit Service 310c69
   * easily undone by freeing all of the non-NULL pointers (using the proper
Packit Service 310c69
   * free routine).
Packit Service 310c69
   */
Packit Service 310c69
  setKernelLayerState(layer, LAYER_SIMPLE_THINGS_INITIALIZED);
Packit Service 310c69
Packit Service 310c69
  initializeDeadlockQueue(&layer->deadlockQueue);
Packit Service 310c69
Packit Service 310c69
  int requestLimit = defaultMaxRequestsActive;
Packit Service 310c69
  initializeLimiter(&layer->requestLimiter, requestLimit);
Packit Service 310c69
  initializeLimiter(&layer->discardLimiter, requestLimit * 3 / 4);
Packit Service 310c69
Packit Service 310c69
  layer->allocationsAllowed   = true;
Packit Service 310c69
  layer->instance             = instance;
Packit Service 310c69
  layer->deviceConfig         = config;
Packit Service 310c69
  layer->startingSectorOffset = startingSector;
Packit Service 310c69
  initializeRing(&layer->deviceConfigRing);
Packit Service 310c69
Packit Service 310c69
  layer->common.updateCRC32              = kvdoUpdateCRC32;
Packit Service 310c69
  layer->common.getBlockCount            = kvdoGetBlockCount;
Packit Service 310c69
  layer->common.getWritePolicy           = kvdoGetWritePolicy;
Packit Service 310c69
  layer->common.createMetadataVIO        = kvdoCreateMetadataVIO;
Packit Service 310c69
  layer->common.createCompressedWriteVIO = kvdoCreateCompressedWriteVIO;
Packit Service 310c69
  layer->common.freeVIO                  = kvdoFreeVIO;
Packit Service 310c69
  layer->common.completeFlush            = kvdoCompleteFlush;
Packit Service 310c69
  layer->common.enqueue                  = kvdoEnqueue;
Packit Service 310c69
  layer->common.waitForAdminOperation    = waitForSyncOperation;
Packit Service 310c69
  layer->common.completeAdminOperation   = kvdoCompleteSyncOperation;
Packit Service 310c69
  layer->common.getCurrentThreadID       = kvdoGetCurrentThreadID;
Packit Service 310c69
  layer->common.zeroDataVIO              = kvdoZeroDataVIO;
Packit Service 310c69
  layer->common.compareDataVIOs          = kvdoCompareDataVIOs;
Packit Service 310c69
  layer->common.copyData                 = kvdoCopyDataVIO;
Packit Service 310c69
  layer->common.readData                 = kvdoReadDataVIO;
Packit Service 310c69
  layer->common.writeData                = kvdoWriteDataVIO;
Packit Service 310c69
  layer->common.writeCompressedBlock     = kvdoWriteCompressedBlock;
Packit Service 310c69
  layer->common.readMetadata             = kvdoSubmitMetadataVIO;
Packit Service 310c69
  layer->common.writeMetadata            = kvdoSubmitMetadataVIO;
Packit Service 310c69
  layer->common.applyPartialWrite        = kvdoModifyWriteDataVIO;
Packit Service 310c69
  layer->common.flush                    = kvdoFlushVIO;
Packit Service 310c69
  layer->common.hashData                 = kvdoHashDataVIO;
Packit Service 310c69
  layer->common.checkForDuplication      = kvdoCheckForDuplication;
Packit Service 310c69
  layer->common.verifyDuplication        = kvdoVerifyDuplication;
Packit Service 310c69
  layer->common.acknowledgeDataVIO       = kvdoAcknowledgeDataVIO;
Packit Service 310c69
  layer->common.compressDataVIO          = kvdoCompressDataVIO;
Packit Service 310c69
  layer->common.updateAlbireo            = kvdoUpdateDedupeAdvice;
Packit Service 310c69
Packit Service 310c69
  spin_lock_init(&layer->flushLock);
Packit Service 310c69
  mutex_init(&layer->statsMutex);
Packit Service 310c69
  bio_list_init(&layer->waitingFlushes);
Packit Service 310c69
Packit Service 310c69
  result = addLayerToDeviceRegistry(layer);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot add layer to device registry";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  snprintf(layer->threadNamePrefix, sizeof(layer->threadNamePrefix), "%s%u",
Packit Service 310c69
           THIS_MODULE->name, instance);
Packit Service 310c69
Packit Service 310c69
  result = makeThreadConfig(config->threadCounts.logicalZones,
Packit Service 310c69
                            config->threadCounts.physicalZones,
Packit Service 310c69
                            config->threadCounts.hashZones,
Packit Service 310c69
                            threadConfigPointer);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot create thread configuration";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  logInfo("zones: %d logical, %d physical, %d hash; base threads: %d",
Packit Service 310c69
          config->threadCounts.logicalZones,
Packit Service 310c69
          config->threadCounts.physicalZones,
Packit Service 310c69
          config->threadCounts.hashZones,
Packit Service 310c69
          (*threadConfigPointer)->baseThreadCount);
Packit Service 310c69
Packit Service 310c69
  result = makeBatchProcessor(layer, returnDataKVIOBatchToPool, layer,
Packit Service 310c69
                              &layer->dataKVIOReleaser);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot allocate KVIO-freeing batch processor";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Spare KVDOFlush, so that we will always have at least one available
Packit Service 310c69
  result = makeKVDOFlush(&layer->spareKVDOFlush);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot allocate KVDOFlush record";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // BIO pool (needed before the geometry block)
Packit Service 310c69
  result = makeDedupeBioSet(layer);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot allocate dedupe bioset";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Read the geometry block so we know how to set up the index. Allow it to
Packit Service 310c69
  // do synchronous reads.
Packit Service 310c69
  layer->common.reader = kvdoSynchronousRead;
Packit Service 310c69
  result = loadVolumeGeometry(&layer->common, &layer->geometry);
Packit Service 310c69
  layer->common.reader = NULL;
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "Could not load geometry block";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Albireo Timeout Reporter
Packit Service 310c69
  initPeriodicEventReporter(&layer->albireoTimeoutReporter,
Packit Service 310c69
                            "Albireo timeout on %llu requests",
Packit Service 310c69
                            DEDUPE_TIMEOUT_REPORT_INTERVAL, layer);
Packit Service 310c69
Packit Service 310c69
  // Dedupe Index
Packit Service 310c69
  BUG_ON(layer->threadNamePrefix[0] == '\0');
Packit Service 310c69
  result = makeDedupeIndex(&layer->dedupeIndex, layer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot initialize dedupe index";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Compression context storage
Packit Service 310c69
  result = ALLOCATE(config->threadCounts.cpuThreads, char *, "LZ4 context",
Packit Service 310c69
                    &layer->compressionContext);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "cannot allocate LZ4 context";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  for (int i = 0; i < config->threadCounts.cpuThreads; i++) {
Packit Service 310c69
    result = ALLOCATE(LZ4_context_size(), char, "LZ4 context",
Packit Service 310c69
                      &layer->compressionContext[i]);
Packit Service 310c69
    if (result != VDO_SUCCESS) {
Packit Service 310c69
      *reason = "cannot allocate LZ4 context";
Packit Service 310c69
      freeKernelLayer(layer);
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Part 3 - Do initializations that depend upon other previous
Packit Service 310c69
   * initializations, but have no order dependencies at freeing time.
Packit Service 310c69
   * Order dependencies for initialization are identified using BUG_ON.
Packit Service 310c69
   */
Packit Service 310c69
  setKernelLayerState(layer, LAYER_BUFFER_POOLS_INITIALIZED);
Packit Service 310c69
Packit Service 310c69
  // Trace pool
Packit Service 310c69
  BUG_ON(layer->requestLimiter.limit <= 0);
Packit Service 310c69
  result = traceKernelLayerInit(layer);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot initialize trace data";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // KVIO and VIO pool
Packit Service 310c69
  BUG_ON(layer->deviceConfig->logicalBlockSize <= 0);
Packit Service 310c69
  BUG_ON(layer->requestLimiter.limit <= 0);
Packit Service 310c69
  BUG_ON(layer->bioset == NULL);
Packit Service 310c69
  BUG_ON(layer->deviceConfig->ownedDevice == NULL);
Packit Service 310c69
  result = makeDataKVIOBufferPool(layer, layer->requestLimiter.limit,
Packit Service 310c69
                                  &layer->dataKVIOPool);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "Cannot allocate vio data";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Part 4 - Do initializations that depend upon other previous
Packit Service 310c69
   * initialization, that may have order dependencies at freeing time.
Packit Service 310c69
   * These are mostly starting up the workqueue threads.
Packit Service 310c69
   */
Packit Service 310c69
Packit Service 310c69
  // Base-code thread, etc
Packit Service 310c69
  result = initializeKVDO(&layer->kvdo, *threadConfigPointer, reason);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setKernelLayerState(layer, LAYER_REQUEST_QUEUE_INITIALIZED);
Packit Service 310c69
Packit Service 310c69
  // Bio queue
Packit Service 310c69
  result = makeIOSubmitter(layer->threadNamePrefix,
Packit Service 310c69
                           config->threadCounts.bioThreads,
Packit Service 310c69
                           config->threadCounts.bioRotationInterval,
Packit Service 310c69
                           layer->requestLimiter.limit,
Packit Service 310c69
                           layer,
Packit Service 310c69
                           &layer->ioSubmitter);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    // If initialization of the bio-queues failed, they are cleaned
Packit Service 310c69
    // up already, so just free the rest of the kernel layer.
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    *reason = "bio submission initialization failed";
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  setKernelLayerState(layer, LAYER_BIO_DATA_INITIALIZED);
Packit Service 310c69
Packit Service 310c69
  // Bio ack queue
Packit Service 310c69
  if (useBioAckQueue(layer)) {
Packit Service 310c69
    result = makeWorkQueue(layer->threadNamePrefix, "ackQ",
Packit Service 310c69
                           &layer->wqDirectory, layer, layer, &bioAckQType,
Packit Service 310c69
                           config->threadCounts.bioAckThreads,
Packit Service 310c69
                           &layer->bioAckQueue);
Packit Service 310c69
    if (result != VDO_SUCCESS) {
Packit Service 310c69
      *reason = "bio ack queue initialization failed";
Packit Service 310c69
      freeKernelLayer(layer);
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setKernelLayerState(layer, LAYER_BIO_ACK_QUEUE_INITIALIZED);
Packit Service 310c69
Packit Service 310c69
  // CPU Queues
Packit Service 310c69
  result = makeWorkQueue(layer->threadNamePrefix, "cpuQ", &layer->wqDirectory,
Packit Service 310c69
                         layer, NULL, &cpuQType,
Packit Service 310c69
                         config->threadCounts.cpuThreads, &layer->cpuQueue);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "Albireo CPU queue initialization failed";
Packit Service 310c69
    freeKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setKernelLayerState(layer, LAYER_CPU_QUEUE_INITIALIZED);
Packit Service 310c69
Packit Service 310c69
  *layerPtr = layer;
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int prepareToModifyKernelLayer(KernelLayer       *layer,
Packit Service 310c69
                               DeviceConfig      *config,
Packit Service 310c69
                               char             **errorPtr)
Packit Service 310c69
{
Packit Service 310c69
  DeviceConfig *extantConfig = layer->deviceConfig;
Packit Service 310c69
  if (config->owningTarget->begin != extantConfig->owningTarget->begin) {
Packit Service 310c69
    *errorPtr = "Starting sector cannot change";
Packit Service 310c69
    return VDO_PARAMETER_MISMATCH;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (strcmp(config->parentDeviceName, extantConfig->parentDeviceName) != 0) {
Packit Service 310c69
    *errorPtr = "Underlying device cannot change";
Packit Service 310c69
    return VDO_PARAMETER_MISMATCH;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (config->logicalBlockSize != extantConfig->logicalBlockSize) {
Packit Service 310c69
    *errorPtr = "Logical block size cannot change";
Packit Service 310c69
    return VDO_PARAMETER_MISMATCH;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (config->cacheSize != extantConfig->cacheSize) {
Packit Service 310c69
    *errorPtr = "Block map cache size cannot change";
Packit Service 310c69
    return VDO_PARAMETER_MISMATCH;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (config->blockMapMaximumAge != extantConfig->blockMapMaximumAge) {
Packit Service 310c69
    *errorPtr = "Block map maximum age cannot change";
Packit Service 310c69
    return VDO_PARAMETER_MISMATCH;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (config->mdRaid5ModeEnabled != extantConfig->mdRaid5ModeEnabled) {
Packit Service 310c69
    *errorPtr = "mdRaid5Mode cannot change";
Packit Service 310c69
    return VDO_PARAMETER_MISMATCH;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (memcmp(&config->threadCounts, &extantConfig->threadCounts,
Packit Service 310c69
	     sizeof(ThreadCountConfig)) != 0) {
Packit Service 310c69
    *errorPtr = "Thread configuration cannot change";
Packit Service 310c69
    return VDO_PARAMETER_MISMATCH;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Below here are the actions to take when a non-immutable property changes.
Packit Service 310c69
Packit Service 310c69
  if (config->writePolicy != extantConfig->writePolicy) {
Packit Service 310c69
    // Nothing needs doing right now for a write policy change.
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (config->owningTarget->len != extantConfig->owningTarget->len) {
Packit Service 310c69
    size_t logicalBytes = to_bytes(config->owningTarget->len);
Packit Service 310c69
    if ((logicalBytes % VDO_BLOCK_SIZE) != 0) {
Packit Service 310c69
      *errorPtr = "Logical size must be a multiple of 4096";
Packit Service 310c69
      return VDO_PARAMETER_MISMATCH;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    int result = prepareToResizeLogical(layer, logicalBytes / VDO_BLOCK_SIZE);
Packit Service 310c69
    if (result != VDO_SUCCESS) {
Packit Service 310c69
      *errorPtr = "Device prepareToGrowLogical failed";
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (config->physicalBlocks != extantConfig->physicalBlocks) {
Packit Service 310c69
    int result = prepareToResizePhysical(layer, config->physicalBlocks);
Packit Service 310c69
    if (result != VDO_SUCCESS) {
Packit Service 310c69
      if (result == VDO_TOO_MANY_SLABS) {
Packit Service 310c69
        *errorPtr = "Device prepareToGrowPhysical failed (specified physical"
Packit Service 310c69
                    " size too big based on formatted slab size)";
Packit Service 310c69
      } else {
Packit Service 310c69
        *errorPtr = "Device prepareToGrowPhysical failed";
Packit Service 310c69
      }
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************
Packit Service 310c69
 * Modify the pool name of the device.
Packit Service 310c69
 *
Packit Service 310c69
 * @param layer      The kernel layer
Packit Service 310c69
 * @param oldName    The old pool name
Packit Service 310c69
 * @param newName    The new pool name
Packit Service 310c69
 *
Packit Service 310c69
 * @return  VDO_SUCCESS or an error
Packit Service 310c69
 *
Packit Service 310c69
 */
Packit Service 310c69
int modifyPoolName(KernelLayer *layer, char *oldName, char *newName)
Packit Service 310c69
{
Packit Service 310c69
  // We use pool name for sysfs and procfs. Rename them accordingly
Packit Service 310c69
  logInfo("Modify pool name from %s to %s", oldName, newName);
Packit Service 310c69
Packit Service 310c69
  void *procfsPrivate;
Packit Service 310c69
  int result = vdoCreateProcfsEntry(layer, newName, &procfsPrivate);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = kobject_rename(&layer->kobj, newName);
Packit Service 310c69
  if (result != 0) {
Packit Service 310c69
    vdoDestroyProcfsEntry(newName, procfsPrivate);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  void *tmpProcfs = layer->procfsPrivate;
Packit Service 310c69
  layer->procfsPrivate = procfsPrivate;
Packit Service 310c69
Packit Service 310c69
  vdoDestroyProcfsEntry(oldName, tmpProcfs);
Packit Service 310c69
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int modifyKernelLayer(KernelLayer  *layer,
Packit Service 310c69
                      DeviceConfig *config)
Packit Service 310c69
{
Packit Service 310c69
  KernelLayerState state = getKernelLayerState(layer);
Packit Service 310c69
  if (state == LAYER_RUNNING) {
Packit Service 310c69
    return VDO_SUCCESS;
Packit Service 310c69
  } else if (state != LAYER_SUSPENDED) {
Packit Service 310c69
    logError("pre-resume invoked while in unexpected kernel layer state %d",
Packit Service 310c69
             state);
Packit Service 310c69
    return -EINVAL;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setKernelLayerState(layer, LAYER_RESUMING);
Packit Service 310c69
Packit Service 310c69
  DeviceConfig *extantConfig = layer->deviceConfig;
Packit Service 310c69
Packit Service 310c69
  // A failure here is unrecoverable. So there is no problem if it happens.
Packit Service 310c69
Packit Service 310c69
  if (config->writePolicy != extantConfig->writePolicy) {
Packit Service 310c69
    /*
Packit Service 310c69
     * Ordinarily, when going from async to sync, we must flush any metadata
Packit Service 310c69
     * written. However, because the underlying storage must have gone into
Packit Service 310c69
     * sync mode before we suspend VDO, and suspending VDO concludes by
Packit Service 310c69
     * issuing a flush, all metadata written before the suspend is flushed
Packit Service 310c69
     * by the suspend and all metadata between the suspend and the write
Packit Service 310c69
     * policy change is written to synchronous storage.
Packit Service 310c69
     */
Packit Service 310c69
    logInfo("Modifying device '%s' write policy from %s to %s",
Packit Service 310c69
            config->poolName, getConfigWritePolicyString(extantConfig),
Packit Service 310c69
            getConfigWritePolicyString(config));
Packit Service 310c69
    setWritePolicy(layer->kvdo.vdo, config->writePolicy);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (config->owningTarget->len != extantConfig->owningTarget->len) {
Packit Service 310c69
    size_t logicalBytes = to_bytes(config->owningTarget->len);
Packit Service 310c69
    int result = resizeLogical(layer, logicalBytes / VDO_BLOCK_SIZE);
Packit Service 310c69
    if (result != VDO_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Grow physical if the version is 0, so we can't tell if we
Packit Service 310c69
  // got an old-style growPhysical command, or if size changed.
Packit Service 310c69
  if ((config->physicalBlocks != extantConfig->physicalBlocks)
Packit Service 310c69
      || (config->version == 0)) {
Packit Service 310c69
    int result = resizePhysical(layer, config->physicalBlocks);
Packit Service 310c69
    if (result != VDO_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (strcmp(config->poolName, extantConfig->poolName) != 0) {
Packit Service 310c69
    logInfo("Modifying device '%s' pool name from %s to %s",
Packit Service 310c69
	    config->poolName, extantConfig->poolName, config->poolName);
Packit Service 310c69
    int result = modifyPoolName(layer, extantConfig->poolName,
Packit Service 310c69
				config->poolName);
Packit Service 310c69
    if (result != VDO_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
    
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void freeKernelLayer(KernelLayer *layer)
Packit Service 310c69
{
Packit Service 310c69
  // This is not the cleanest implementation, but given the current timing
Packit Service 310c69
  // uncertainties in the shutdown process for work queues, we need to
Packit Service 310c69
  // store information to enable a late-in-process deallocation of
Packit Service 310c69
  // funnel-queue data structures in work queues.
Packit Service 310c69
  bool usedBioAckQueue = false;
Packit Service 310c69
  bool usedCpuQueue    = false;
Packit Service 310c69
  bool usedKVDO        = false;
Packit Service 310c69
  bool releaseInstance = false;
Packit Service 310c69
Packit Service 310c69
  KernelLayerState state = getKernelLayerState(layer);
Packit Service 310c69
  switch (state) {
Packit Service 310c69
  case LAYER_STOPPING:
Packit Service 310c69
    logError("re-entered freeKernelLayer while stopping");
Packit Service 310c69
    break;
Packit Service 310c69
Packit Service 310c69
  case LAYER_RUNNING:
Packit Service 310c69
    suspendKernelLayer(layer);
Packit Service 310c69
    // fall through
Packit Service 310c69
Packit Service 310c69
  case LAYER_STARTING:
Packit Service 310c69
  case LAYER_RESUMING:
Packit Service 310c69
  case LAYER_SUSPENDED:
Packit Service 310c69
    stopKernelLayer(layer);
Packit Service 310c69
    // fall through
Packit Service 310c69
Packit Service 310c69
  case LAYER_STOPPED:
Packit Service 310c69
  case LAYER_CPU_QUEUE_INITIALIZED:
Packit Service 310c69
    finishWorkQueue(layer->cpuQueue);
Packit Service 310c69
    usedCpuQueue = true;
Packit Service 310c69
    releaseInstance = true;
Packit Service 310c69
    // fall through
Packit Service 310c69
Packit Service 310c69
  case LAYER_BIO_ACK_QUEUE_INITIALIZED:
Packit Service 310c69
    if (useBioAckQueue(layer)) {
Packit Service 310c69
      finishWorkQueue(layer->bioAckQueue);
Packit Service 310c69
      usedBioAckQueue = true;
Packit Service 310c69
    }
Packit Service 310c69
    // fall through
Packit Service 310c69
Packit Service 310c69
  case LAYER_BIO_DATA_INITIALIZED:
Packit Service 310c69
    cleanupIOSubmitter(layer->ioSubmitter);
Packit Service 310c69
    // fall through
Packit Service 310c69
Packit Service 310c69
  case LAYER_REQUEST_QUEUE_INITIALIZED:
Packit Service 310c69
    finishKVDO(&layer->kvdo);
Packit Service 310c69
    usedKVDO = true;
Packit Service 310c69
    // fall through
Packit Service 310c69
Packit Service 310c69
  case LAYER_BUFFER_POOLS_INITIALIZED:
Packit Service 310c69
    freeBufferPool(&layer->dataKVIOPool);
Packit Service 310c69
    freeBufferPool(&layer->traceBufferPool);
Packit Service 310c69
    // fall through
Packit Service 310c69
Packit Service 310c69
  case LAYER_SIMPLE_THINGS_INITIALIZED:
Packit Service 310c69
    if (layer->compressionContext != NULL) {
Packit Service 310c69
      for (int i = 0; i < layer->deviceConfig->threadCounts.cpuThreads; i++) {
Packit Service 310c69
        FREE(layer->compressionContext[i]);
Packit Service 310c69
      }
Packit Service 310c69
      FREE(layer->compressionContext);
Packit Service 310c69
    }
Packit Service 310c69
    if (layer->dedupeIndex != NULL) {
Packit Service 310c69
      finishDedupeIndex(layer->dedupeIndex);
Packit Service 310c69
    }
Packit Service 310c69
    FREE(layer->spareKVDOFlush);
Packit Service 310c69
    layer->spareKVDOFlush = NULL;
Packit Service 310c69
    freeBatchProcessor(&layer->dataKVIOReleaser);
Packit Service 310c69
    removeLayerFromDeviceRegistry(layer);
Packit Service 310c69
    break;
Packit Service 310c69
Packit Service 310c69
  default:
Packit Service 310c69
    logError("Unknown Kernel Layer state: %d", state);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Late deallocation of resources in work queues.
Packit Service 310c69
  if (usedCpuQueue) {
Packit Service 310c69
    freeWorkQueue(&layer->cpuQueue);
Packit Service 310c69
  }
Packit Service 310c69
  if (usedBioAckQueue) {
Packit Service 310c69
    freeWorkQueue(&layer->bioAckQueue);
Packit Service 310c69
  }
Packit Service 310c69
  if (layer->ioSubmitter) {
Packit Service 310c69
    freeIOSubmitter(layer->ioSubmitter);
Packit Service 310c69
  }
Packit Service 310c69
  if (usedKVDO) {
Packit Service 310c69
    destroyKVDO(&layer->kvdo);
Packit Service 310c69
  }
Packit Service 310c69
  if (layer->bioset != NULL) {
Packit Service 310c69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
Packit Service 310c69
    bioset_exit(layer->bioset);
Packit Service 310c69
    FREE(layer->bioset);
Packit Service 310c69
#else
Packit Service 310c69
    bioset_free(layer->bioset);
Packit Service 310c69
#endif
Packit Service 310c69
    layer->bioset = NULL;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  freeDedupeIndex(&layer->dedupeIndex);
Packit Service 310c69
Packit Service 310c69
  stopPeriodicEventReporter(&layer->albireoTimeoutReporter);
Packit Service 310c69
  if (releaseInstance) {
Packit Service 310c69
    releaseKVDOInstance(layer->instance);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // The call to kobject_put on the kobj sysfs node will decrement its
Packit Service 310c69
  // reference count; when the count goes to zero the VDO object and
Packit Service 310c69
  // the kernel layer object will be freed as a side effect.
Packit Service 310c69
  kobject_put(&layer->wqDirectory);
Packit Service 310c69
  kobject_put(&layer->kobj);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void poolStatsRelease(struct kobject *kobj)
Packit Service 310c69
{
Packit Service 310c69
  KernelLayer *layer = container_of(kobj, KernelLayer, statsDirectory);
Packit Service 310c69
  complete(&layer->statsShutdown);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int preloadKernelLayer(KernelLayer          *layer,
Packit Service 310c69
                       const VDOLoadConfig  *loadConfig,
Packit Service 310c69
                       char                **reason)
Packit Service 310c69
{
Packit Service 310c69
  if (getKernelLayerState(layer) != LAYER_CPU_QUEUE_INITIALIZED) {
Packit Service 310c69
    *reason = "preloadKernelLayer() may only be invoked after initialization";
Packit Service 310c69
    return UDS_BAD_STATE;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setKernelLayerState(layer, LAYER_STARTING);
Packit Service 310c69
  int result = preloadKVDO(&layer->kvdo, &layer->common, loadConfig,
Packit Service 310c69
                         layer->vioTraceRecording, reason);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    stopKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int startKernelLayer(KernelLayer *layer, char **reason)
Packit Service 310c69
{
Packit Service 310c69
  if (getKernelLayerState(layer) != LAYER_STARTING) {
Packit Service 310c69
    *reason = "Cannot start kernel from non-starting state";
Packit Service 310c69
    stopKernelLayer(layer);
Packit Service 310c69
    return UDS_BAD_STATE;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  int result = startKVDO(&layer->kvdo, &layer->common, reason);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    stopKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setKernelLayerState(layer, LAYER_RUNNING);
Packit Service 310c69
  static struct kobj_type statsDirectoryKobjType = {
Packit Service 310c69
    .release       = poolStatsRelease,
Packit Service 310c69
    .sysfs_ops     = &poolStatsSysfsOps,
Packit Service 310c69
    .default_attrs = poolStatsAttrs,
Packit Service 310c69
  };
Packit Service 310c69
  kobject_init(&layer->statsDirectory, &statsDirectoryKobjType);
Packit Service 310c69
  result = kobject_add(&layer->statsDirectory, &layer->kobj, "statistics");
Packit Service 310c69
  if (result != 0) {
Packit Service 310c69
    *reason = "Cannot add sysfs statistics node";
Packit Service 310c69
    stopKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  layer->statsAdded = true;
Packit Service 310c69
Packit Service 310c69
  if (layer->deviceConfig->deduplication) {
Packit Service 310c69
    // Don't try to load or rebuild the index first (and log scary error
Packit Service 310c69
    // messages) if this is known to be a newly-formatted volume.
Packit Service 310c69
    startDedupeIndex(layer->dedupeIndex, wasNew(layer->kvdo.vdo));
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = vdoCreateProcfsEntry(layer, layer->deviceConfig->poolName,
Packit Service 310c69
                                &layer->procfsPrivate);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    *reason = "Could not create proc filesystem entry";
Packit Service 310c69
    stopKernelLayer(layer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  layer->allocationsAllowed = false;
Packit Service 310c69
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void stopKernelLayer(KernelLayer *layer)
Packit Service 310c69
{
Packit Service 310c69
  layer->allocationsAllowed = true;
Packit Service 310c69
Packit Service 310c69
  // Stop services that need to gather VDO statistics from the worker threads.
Packit Service 310c69
  if (layer->statsAdded) {
Packit Service 310c69
    layer->statsAdded = false;
Packit Service 310c69
    init_completion(&layer->statsShutdown);
Packit Service 310c69
    kobject_put(&layer->statsDirectory);
Packit Service 310c69
    wait_for_completion(&layer->statsShutdown);
Packit Service 310c69
  }
Packit Service 310c69
  vdoDestroyProcfsEntry(layer->deviceConfig->poolName, layer->procfsPrivate);
Packit Service 310c69
Packit Service 310c69
  switch (getKernelLayerState(layer)) {
Packit Service 310c69
  case LAYER_RUNNING:
Packit Service 310c69
    suspendKernelLayer(layer);
Packit Service 310c69
    // fall through
Packit Service 310c69
Packit Service 310c69
  case LAYER_SUSPENDED:
Packit Service 310c69
    setKernelLayerState(layer, LAYER_STOPPING);
Packit Service 310c69
    stopDedupeIndex(layer->dedupeIndex);
Packit Service 310c69
    // fall through
Packit Service 310c69
Packit Service 310c69
  case LAYER_STOPPING:
Packit Service 310c69
  case LAYER_STOPPED:
Packit Service 310c69
  default:
Packit Service 310c69
    setKernelLayerState(layer, LAYER_STOPPED);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int suspendKernelLayer(KernelLayer *layer)
Packit Service 310c69
{
Packit Service 310c69
  // It's important to note any error here does not actually stop device-mapper
Packit Service 310c69
  // from suspending the device. All this work is done post suspend.
Packit Service 310c69
  KernelLayerState state = getKernelLayerState(layer);
Packit Service 310c69
  if (state == LAYER_SUSPENDED) {
Packit Service 310c69
    return VDO_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
  if (state != LAYER_RUNNING) {
Packit Service 310c69
    logError("Suspend invoked while in unexpected kernel layer state %d",
Packit Service 310c69
             state);
Packit Service 310c69
    return -EINVAL;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Attempt to flush all I/O before completing post suspend work. This is
Packit Service 310c69
   * needed so that changing write policy upon resume is safe. Also, we think
Packit Service 310c69
   * a suspended device is expected to have persisted all data written before
Packit Service 310c69
   * the suspend, even if it hasn't been flushed yet.
Packit Service 310c69
   */
Packit Service 310c69
  waitForNoRequestsActive(layer);
Packit Service 310c69
  int result = synchronousFlush(layer);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    setKVDOReadOnly(&layer->kvdo, result);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Suspend the VDO, writing out all dirty metadata if the no-flush flag
Packit Service 310c69
   * was not set on the dmsetup suspend call. This will ensure that we don't
Packit Service 310c69
   * have cause to write while suspended [VDO-4402].
Packit Service 310c69
   */
Packit Service 310c69
  int suspendResult = suspendKVDO(&layer->kvdo);
Packit Service 310c69
  if (result == VDO_SUCCESS) {
Packit Service 310c69
    result = suspendResult;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  suspendDedupeIndex(layer->dedupeIndex, !layer->noFlushSuspend);
Packit Service 310c69
  setKernelLayerState(layer, LAYER_SUSPENDED);
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int resumeKernelLayer(KernelLayer *layer)
Packit Service 310c69
{
Packit Service 310c69
  if (getKernelLayerState(layer) == LAYER_RUNNING) {
Packit Service 310c69
    return VDO_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  resumeDedupeIndex(layer->dedupeIndex);
Packit Service 310c69
  int result = resumeKVDO(&layer->kvdo);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setKernelLayerState(layer, LAYER_RUNNING);
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/***********************************************************************/
Packit Service 310c69
int prepareToResizePhysical(KernelLayer *layer, BlockCount physicalCount)
Packit Service 310c69
{
Packit Service 310c69
  logInfo("Preparing to resize physical to %llu", physicalCount);
Packit Service 310c69
  // Allocations are allowed and permissible through this non-VDO thread,
Packit Service 310c69
  // since IO triggered by this allocation to VDO can finish just fine.
Packit Service 310c69
  int result = kvdoPrepareToGrowPhysical(&layer->kvdo, physicalCount);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    // kvdoPrepareToGrowPhysical logs errors.
Packit Service 310c69
    if (result == VDO_PARAMETER_MISMATCH) {
Packit Service 310c69
      // If we don't trap this case, mapToSystemError() will remap it to -EIO,
Packit Service 310c69
      // which is misleading and ahistorical.
Packit Service 310c69
      return -EINVAL;
Packit Service 310c69
    } else {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  logInfo("Done preparing to resize physical");
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/***********************************************************************/
Packit Service 310c69
int resizePhysical(KernelLayer *layer, BlockCount physicalCount)
Packit Service 310c69
{
Packit Service 310c69
  // We must not mark the layer as allowing allocations when it is suspended
Packit Service 310c69
  // lest an allocation attempt block on writing IO to the suspended VDO.
Packit Service 310c69
  int result = kvdoResizePhysical(&layer->kvdo, physicalCount);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    // kvdoResizePhysical logs errors
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/***********************************************************************/
Packit Service 310c69
int prepareToResizeLogical(KernelLayer *layer, BlockCount logicalCount)
Packit Service 310c69
{
Packit Service 310c69
  logInfo("Preparing to resize logical to %llu", logicalCount);
Packit Service 310c69
  // Allocations are allowed and permissible through this non-VDO thread,
Packit Service 310c69
  // since IO triggered by this allocation to VDO can finish just fine.
Packit Service 310c69
  int result = kvdoPrepareToGrowLogical(&layer->kvdo, logicalCount);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    // kvdoPrepareToGrowLogical logs errors
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  logInfo("Done preparing to resize logical");
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/***********************************************************************/
Packit Service 310c69
int resizeLogical(KernelLayer *layer, BlockCount logicalCount)
Packit Service 310c69
{
Packit Service 310c69
  logInfo("Resizing logical to %llu", logicalCount);
Packit Service 310c69
  // We must not mark the layer as allowing allocations when it is suspended
Packit Service 310c69
  // lest an allocation attempt block on writing IO to the suspended VDO.
Packit Service 310c69
  int result = kvdoResizeLogical(&layer->kvdo, logicalCount);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    // kvdoResizeLogical logs errors
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  logInfo("Logical blocks now %llu", logicalCount);
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69