|
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 |
|