|
Packit Service |
d40955 |
/*
|
|
Packit Service |
d40955 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
d40955 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
d40955 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
d40955 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
d40955 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
d40955 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
d40955 |
* GNU General Public License for more details.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
d40955 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
d40955 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
d40955 |
* 02110-1301, USA.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/kernelVDO.c#7 $
|
|
Packit Service |
d40955 |
*/
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "kernelVDOInternals.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include <linux/delay.h>
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "memoryAlloc.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "statistics.h"
|
|
Packit Service |
d40955 |
#include "threadConfig.h"
|
|
Packit Service |
d40955 |
#include "vdo.h"
|
|
Packit Service |
d40955 |
#include "vdoDebug.h"
|
|
Packit Service |
d40955 |
#include "vdoLoad.h"
|
|
Packit Service |
d40955 |
#include "vdoResize.h"
|
|
Packit Service |
d40955 |
#include "vdoResizeLogical.h"
|
|
Packit Service |
d40955 |
#include "vdoResume.h"
|
|
Packit Service |
d40955 |
#include "vdoSuspend.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "kernelLayer.h"
|
|
Packit Service |
d40955 |
#include "kvio.h"
|
|
Packit Service |
d40955 |
#include "logger.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
enum { PARANOID_THREAD_CONSISTENCY_CHECKS = 0 };
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
static void startKVDORequestQueue(void *ptr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
KVDOThread *thread = ptr;
|
|
Packit Service |
d40955 |
KVDO *kvdo = thread->kvdo;
|
|
Packit Service |
d40955 |
KernelLayer *layer = container_of(kvdo, KernelLayer, kvdo);
|
|
Packit Service |
d40955 |
registerAllocatingThread(&thread->allocatingThread,
|
|
Packit Service |
d40955 |
&layer->allocationsAllowed);
|
|
Packit Service |
d40955 |
setWorkQueuePrivateData(thread);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
static void finishKVDORequestQueue(void *ptr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
unregisterAllocatingThread();
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
static const KvdoWorkQueueType requestQueueType = {
|
|
Packit Service |
d40955 |
.start = startKVDORequestQueue,
|
|
Packit Service |
d40955 |
.finish = finishKVDORequestQueue,
|
|
Packit Service |
d40955 |
.actionTable = {
|
|
Packit Service |
d40955 |
{ .name = "req_completion",
|
|
Packit Service |
d40955 |
.code = REQ_Q_ACTION_COMPLETION,
|
|
Packit Service |
d40955 |
.priority = 1 },
|
|
Packit Service |
d40955 |
{ .name = "req_flush",
|
|
Packit Service |
d40955 |
.code = REQ_Q_ACTION_FLUSH,
|
|
Packit Service |
d40955 |
.priority = 2 },
|
|
Packit Service |
d40955 |
{ .name = "req_map_bio",
|
|
Packit Service |
d40955 |
.code = REQ_Q_ACTION_MAP_BIO,
|
|
Packit Service |
d40955 |
.priority = 0 },
|
|
Packit Service |
d40955 |
{ .name = "req_sync",
|
|
Packit Service |
d40955 |
.code = REQ_Q_ACTION_SYNC,
|
|
Packit Service |
d40955 |
.priority = 2 },
|
|
Packit Service |
d40955 |
{ .name = "req_vio_callback",
|
|
Packit Service |
d40955 |
.code = REQ_Q_ACTION_VIO_CALLBACK,
|
|
Packit Service |
d40955 |
.priority = 1 },
|
|
Packit Service |
d40955 |
},
|
|
Packit Service |
d40955 |
};
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int initializeKVDO(KVDO *kvdo,
|
|
Packit Service |
d40955 |
const ThreadConfig *threadConfig,
|
|
Packit Service |
d40955 |
char **reason)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
unsigned int baseThreads = threadConfig->baseThreadCount;
|
|
Packit Service |
d40955 |
int result = ALLOCATE(baseThreads, KVDOThread,
|
|
Packit Service |
d40955 |
"request processing work queue",
|
|
Packit Service |
d40955 |
&kvdo->threads);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
*reason = "Cannot allocation thread structures";
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
KernelLayer *layer = container_of(kvdo, KernelLayer, kvdo);
|
|
Packit Service |
d40955 |
for (kvdo->initializedThreadCount = 0;
|
|
Packit Service |
d40955 |
kvdo->initializedThreadCount < baseThreads;
|
|
Packit Service |
d40955 |
kvdo->initializedThreadCount++) {
|
|
Packit Service |
d40955 |
KVDOThread *thread = &kvdo->threads[kvdo->initializedThreadCount];
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
thread->kvdo = kvdo;
|
|
Packit Service |
d40955 |
thread->threadID = kvdo->initializedThreadCount;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
char queueName[MAX_QUEUE_NAME_LEN];
|
|
Packit Service |
d40955 |
// Copy only LEN - 1 bytes and ensure NULL termination.
|
|
Packit Service |
d40955 |
getVDOThreadName(threadConfig, kvdo->initializedThreadCount,
|
|
Packit Service |
d40955 |
queueName, sizeof(queueName));
|
|
Packit Service |
d40955 |
int result = makeWorkQueue(layer->threadNamePrefix, queueName,
|
|
Packit Service |
d40955 |
&layer->wqDirectory, layer, thread,
|
|
Packit Service |
d40955 |
&requestQueueType, 1, &thread->requestQueue);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
*reason = "Cannot initialize request queue";
|
|
Packit Service |
d40955 |
while (kvdo->initializedThreadCount > 0) {
|
|
Packit Service |
d40955 |
unsigned int threadToDestroy = kvdo->initializedThreadCount - 1;
|
|
Packit Service |
d40955 |
thread = &kvdo->threads[threadToDestroy];
|
|
Packit Service |
d40955 |
finishWorkQueue(thread->requestQueue);
|
|
Packit Service |
d40955 |
freeWorkQueue(&thread->requestQueue);
|
|
Packit Service |
d40955 |
kvdo->initializedThreadCount--;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
FREE(kvdo->threads);
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int preloadKVDO(KVDO *kvdo,
|
|
Packit Service |
d40955 |
PhysicalLayer *common,
|
|
Packit Service |
d40955 |
const VDOLoadConfig *loadConfig,
|
|
Packit Service |
d40955 |
bool vioTraceRecording,
|
|
Packit Service |
d40955 |
char **reason)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
KernelLayer *layer = asKernelLayer(common);
|
|
Packit Service |
d40955 |
init_completion(&layer->callbackSync);
|
|
Packit Service |
d40955 |
int result = prepareToLoadVDO(kvdo->vdo, loadConfig);
|
|
Packit Service |
d40955 |
if ((result != VDO_SUCCESS) && (result != VDO_READ_ONLY)) {
|
|
Packit Service |
d40955 |
*reason = "Cannot load metadata from device";
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
setVDOTracingFlags(kvdo->vdo, vioTraceRecording);
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int startKVDO(KVDO *kvdo, PhysicalLayer *common, char **reason)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
KernelLayer *layer = asKernelLayer(common);
|
|
Packit Service |
d40955 |
init_completion(&layer->callbackSync);
|
|
Packit Service |
d40955 |
int result = performVDOLoad(kvdo->vdo);
|
|
Packit Service |
d40955 |
if ((result != VDO_SUCCESS) && (result != VDO_READ_ONLY)) {
|
|
Packit Service |
d40955 |
*reason = "Cannot load metadata from device";
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int suspendKVDO(KVDO *kvdo)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
if (kvdo->vdo == NULL) {
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
KernelLayer *layer = container_of(kvdo, KernelLayer, kvdo);
|
|
Packit Service |
d40955 |
init_completion(&layer->callbackSync);
|
|
Packit Service |
d40955 |
int result = performVDOSuspend(kvdo->vdo, !layer->noFlushSuspend);
|
|
Packit Service |
d40955 |
if ((result != VDO_SUCCESS) && (result != VDO_READ_ONLY)) {
|
|
Packit Service |
d40955 |
char errorName[80] = "";
|
|
Packit Service |
d40955 |
char errorMessage[ERRBUF_SIZE] = "";
|
|
Packit Service |
d40955 |
logError("%s: Suspend device failed %d (%s: %s)",
|
|
Packit Service |
d40955 |
__func__, result,
|
|
Packit Service |
d40955 |
stringErrorName(result, errorName, sizeof(errorName)),
|
|
Packit Service |
d40955 |
stringError(result, errorMessage, sizeof(errorMessage)));
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Convert VDO_READ_ONLY to VDO_SUCCESS since a read-only suspension still
|
|
Packit Service |
d40955 |
// leaves the VDO suspended.
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int resumeKVDO(KVDO *kvdo)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
if (kvdo->vdo == NULL) {
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
KernelLayer *layer = container_of(kvdo, KernelLayer, kvdo);
|
|
Packit Service |
d40955 |
init_completion(&layer->callbackSync);
|
|
Packit Service |
d40955 |
return performVDOResume(kvdo->vdo);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void finishKVDO(KVDO *kvdo)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
for (int i = 0; i < kvdo->initializedThreadCount; i++) {
|
|
Packit Service |
d40955 |
finishWorkQueue(kvdo->threads[i].requestQueue);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void destroyKVDO(KVDO *kvdo)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
destroyVDO(kvdo->vdo);
|
|
Packit Service |
d40955 |
for (int i = 0; i < kvdo->initializedThreadCount; i++) {
|
|
Packit Service |
d40955 |
freeWorkQueue(&kvdo->threads[i].requestQueue);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
FREE(kvdo->threads);
|
|
Packit Service |
d40955 |
kvdo->threads = NULL;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void dumpKVDOWorkQueue(KVDO *kvdo)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
for (int i = 0; i < kvdo->initializedThreadCount; i++) {
|
|
Packit Service |
d40955 |
dumpWorkQueue(kvdo->threads[i].requestQueue);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
typedef struct {
|
|
Packit Service |
d40955 |
KvdoWorkItem workItem;
|
|
Packit Service |
d40955 |
KVDO *kvdo;
|
|
Packit Service |
d40955 |
void *data;
|
|
Packit Service |
d40955 |
struct completion *completion;
|
|
Packit Service |
d40955 |
} SyncQueueWork;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Initiate an arbitrary asynchronous base-code operation and wait for
|
|
Packit Service |
d40955 |
* it.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* An async queue operation is performed and we wait for completion.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param kvdo The kvdo data handle
|
|
Packit Service |
d40955 |
* @param action The operation to perform
|
|
Packit Service |
d40955 |
* @param data Unique data that can be used by the operation
|
|
Packit Service |
d40955 |
* @param threadID The thread on which to perform the operation
|
|
Packit Service |
d40955 |
* @param completion The completion to wait on
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return VDO_SUCCESS of an error code
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void performKVDOOperation(KVDO *kvdo,
|
|
Packit Service |
d40955 |
KvdoWorkFunction action,
|
|
Packit Service |
d40955 |
void *data,
|
|
Packit Service |
d40955 |
ThreadID threadID,
|
|
Packit Service |
d40955 |
struct completion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SyncQueueWork sync;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
memset(&sync, 0, sizeof(sync));
|
|
Packit Service |
d40955 |
setupWorkItem(&sync.workItem, action, NULL, REQ_Q_ACTION_SYNC);
|
|
Packit Service |
d40955 |
sync.kvdo = kvdo;
|
|
Packit Service |
d40955 |
sync.data = data;
|
|
Packit Service |
d40955 |
sync.completion = completion;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
init_completion(completion);
|
|
Packit Service |
d40955 |
enqueueKVDOWork(kvdo, &sync.workItem, threadID);
|
|
Packit Service |
d40955 |
wait_for_completion(completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
typedef struct {
|
|
Packit Service |
d40955 |
bool enable;
|
|
Packit Service |
d40955 |
bool wasEnabled;
|
|
Packit Service |
d40955 |
} VDOCompressData;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Does the work of calling the base code to set compress state, then
|
|
Packit Service |
d40955 |
* tells the function waiting on completion to go ahead.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param item The work item
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void setCompressingWork(KvdoWorkItem *item)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SyncQueueWork *work = container_of(item, SyncQueueWork, workItem);
|
|
Packit Service |
d40955 |
VDOCompressData *data = (VDOCompressData *)work->data;
|
|
Packit Service |
d40955 |
data->wasEnabled = setVDOCompressing(getVDO(work->kvdo), data->enable);
|
|
Packit Service |
d40955 |
complete(work->completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/***********************************************************************/
|
|
Packit Service |
d40955 |
bool setKVDOCompressing(KVDO *kvdo, bool enableCompression)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
struct completion compressWait;
|
|
Packit Service |
d40955 |
VDOCompressData data;
|
|
Packit Service |
d40955 |
data.enable = enableCompression;
|
|
Packit Service |
d40955 |
performKVDOOperation(kvdo, setCompressingWork, &data,
|
|
Packit Service |
d40955 |
getPackerZoneThread(getThreadConfig(kvdo->vdo)),
|
|
Packit Service |
d40955 |
&compressWait);
|
|
Packit Service |
d40955 |
return data.wasEnabled;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
typedef struct {
|
|
Packit Service |
d40955 |
int result;
|
|
Packit Service |
d40955 |
} VDOReadOnlyData;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
static void enterReadOnlyModeWork(KvdoWorkItem *item)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SyncQueueWork *work = container_of(item, SyncQueueWork, workItem);
|
|
Packit Service |
d40955 |
VDOReadOnlyData *data = work->data;
|
|
Packit Service |
d40955 |
makeVDOReadOnly(getVDO(work->kvdo), data->result);
|
|
Packit Service |
d40955 |
complete(work->completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/***********************************************************************/
|
|
Packit Service |
d40955 |
void setKVDOReadOnly(KVDO *kvdo, int result)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
struct completion readOnlyWait;
|
|
Packit Service |
d40955 |
VDOReadOnlyData data;
|
|
Packit Service |
d40955 |
data.result = result;
|
|
Packit Service |
d40955 |
performKVDOOperation(kvdo, enterReadOnlyModeWork, &data,
|
|
Packit Service |
d40955 |
getAdminThread(getThreadConfig(kvdo->vdo)),
|
|
Packit Service |
d40955 |
&readOnlyWait);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Does the work of calling the vdo statistics gathering tool
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param item The work item
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void getVDOStatisticsWork(KvdoWorkItem *item)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SyncQueueWork *work = container_of(item, SyncQueueWork, workItem);
|
|
Packit Service |
d40955 |
VDOStatistics *stats = (VDOStatistics *)work->data;
|
|
Packit Service |
d40955 |
getVDOStatistics(getVDO(work->kvdo), stats);
|
|
Packit Service |
d40955 |
complete(work->completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/***********************************************************************/
|
|
Packit Service |
d40955 |
void getKVDOStatistics(KVDO *kvdo, VDOStatistics *stats)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
struct completion statsWait;
|
|
Packit Service |
d40955 |
memset(stats, 0, sizeof(VDOStatistics));
|
|
Packit Service |
d40955 |
performKVDOOperation(kvdo, getVDOStatisticsWork, stats,
|
|
Packit Service |
d40955 |
getAdminThread(getThreadConfig(kvdo->vdo)),
|
|
Packit Service |
d40955 |
&statsWait);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* A structure to invoke an arbitrary VDO action.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
typedef struct vdoActionData {
|
|
Packit Service |
d40955 |
VDOAction *action;
|
|
Packit Service |
d40955 |
VDOCompletion *vdoCompletion;
|
|
Packit Service |
d40955 |
struct completion waiter;
|
|
Packit Service |
d40955 |
} VDOActionData;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Initialize a VDOActionData structure so that the specified action
|
|
Packit Service |
d40955 |
* can be invoked on the specified completion.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param data A VDOActionData.
|
|
Packit Service |
d40955 |
* @param action The VDOAction to execute.
|
|
Packit Service |
d40955 |
* @param vdoCompletion The VDO completion upon which the action acts.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void initializeVDOActionData(VDOActionData *data,
|
|
Packit Service |
d40955 |
VDOAction *action,
|
|
Packit Service |
d40955 |
VDOCompletion *vdoCompletion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
*data = (VDOActionData) {
|
|
Packit Service |
d40955 |
.action = action,
|
|
Packit Service |
d40955 |
.vdoCompletion = vdoCompletion,
|
|
Packit Service |
d40955 |
};
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* The VDO callback that completes the KVDO completion.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param vdoCompletion The VDO completion which was acted upon.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void finishVDOAction(VDOCompletion *vdoCompletion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SyncQueueWork *work = vdoCompletion->parent;
|
|
Packit Service |
d40955 |
complete(work->completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Perform a VDO base code action as specified by a VDOActionData.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* Sets the completion callback and parent inside the VDOActionData
|
|
Packit Service |
d40955 |
* so that the corresponding kernel completion is completed when
|
|
Packit Service |
d40955 |
* the VDO completion is.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param item A KVDO work queue item.
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void performVDOActionWork(KvdoWorkItem *item)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
SyncQueueWork *work = container_of(item, SyncQueueWork, workItem);
|
|
Packit Service |
d40955 |
VDOActionData *data = work->data;
|
|
Packit Service |
d40955 |
ThreadID id = getPhysicalLayer()->getCurrentThreadID();
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
setCallbackWithParent(data->vdoCompletion, finishVDOAction, id, work);
|
|
Packit Service |
d40955 |
data->action(data->vdoCompletion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int performKVDOExtendedCommand(KVDO *kvdo, int argc, char **argv)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
VDOActionData data;
|
|
Packit Service |
d40955 |
VDOCommandCompletion cmd;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
int result = initializeVDOCommandCompletion(&cmd, getVDO(kvdo), argc, argv);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
initializeVDOActionData(&data, executeVDOExtendedCommand, &cmd.completion);
|
|
Packit Service |
d40955 |
performKVDOOperation(kvdo, performVDOActionWork, &data,
|
|
Packit Service |
d40955 |
getAdminThread(getThreadConfig(kvdo->vdo)),
|
|
Packit Service |
d40955 |
&data.waiter);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return destroyVDOCommandCompletion(&cmd);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void dumpKVDOStatus(KVDO *kvdo)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
dumpVDOStatus(kvdo->vdo);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
bool getKVDOCompressing(KVDO *kvdo)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
return getVDOCompressing(kvdo->vdo);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int kvdoPrepareToGrowPhysical(KVDO *kvdo, BlockCount physicalCount)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
VDO *vdo = kvdo->vdo;
|
|
Packit Service |
d40955 |
return prepareToGrowPhysical(vdo, physicalCount);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int kvdoResizePhysical(KVDO *kvdo, BlockCount physicalCount)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
KernelLayer *layer = container_of(kvdo, KernelLayer, kvdo);
|
|
Packit Service |
d40955 |
init_completion(&layer->callbackSync);
|
|
Packit Service |
d40955 |
int result = performGrowPhysical(kvdo->vdo, physicalCount);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
logError("resize operation failed, result = %d", result);
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int kvdoPrepareToGrowLogical(KVDO *kvdo, BlockCount logicalCount)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
VDO *vdo = kvdo->vdo;
|
|
Packit Service |
d40955 |
return prepareToGrowLogical(vdo, logicalCount);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
int kvdoResizeLogical(KVDO *kvdo, BlockCount logicalCount)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
KernelLayer *layer = container_of(kvdo, KernelLayer, kvdo);
|
|
Packit Service |
d40955 |
init_completion(&layer->callbackSync);
|
|
Packit Service |
d40955 |
int result = performGrowLogical(kvdo->vdo, logicalCount);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
logError("grow logical operation failed, result = %d", result);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
WritePolicy getKVDOWritePolicy(KVDO *kvdo)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
return getWritePolicy(kvdo->vdo);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void enqueueKVDOThreadWork(KVDOThread *thread,
|
|
Packit Service |
d40955 |
KvdoWorkItem *item)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
enqueueWorkQueue(thread->requestQueue, item);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void enqueueKVDOWork(KVDO *kvdo, KvdoWorkItem *item, ThreadID threadID)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
enqueueKVDOThreadWork(&kvdo->threads[threadID], item);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void enqueueKVIO(KVIO *kvio,
|
|
Packit Service |
d40955 |
KvdoWorkFunction work,
|
|
Packit Service |
d40955 |
void *statsFunction,
|
|
Packit Service |
d40955 |
unsigned int action)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
ThreadID threadID = vioAsCompletion(kvio->vio)->callbackThreadID;
|
|
Packit Service |
d40955 |
BUG_ON(threadID >= kvio->layer->kvdo.initializedThreadCount);
|
|
Packit Service |
d40955 |
launchKVIO(kvio, work, statsFunction, action,
|
|
Packit Service |
d40955 |
kvio->layer->kvdo.threads[threadID].requestQueue);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
static void kvdoEnqueueWork(KvdoWorkItem *workItem)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
KvdoEnqueueable *kvdoEnqueueable = container_of(workItem,
|
|
Packit Service |
d40955 |
KvdoEnqueueable,
|
|
Packit Service |
d40955 |
workItem);
|
|
Packit Service |
d40955 |
runCallback(kvdoEnqueueable->enqueueable.completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void kvdoEnqueue(Enqueueable *enqueueable)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
KvdoEnqueueable *kvdoEnqueueable = container_of(enqueueable,
|
|
Packit Service |
d40955 |
KvdoEnqueueable,
|
|
Packit Service |
d40955 |
enqueueable);
|
|
Packit Service |
d40955 |
KernelLayer *layer = asKernelLayer(enqueueable->completion->layer);
|
|
Packit Service |
d40955 |
ThreadID threadID = enqueueable->completion->callbackThreadID;
|
|
Packit Service |
d40955 |
if (ASSERT(threadID < layer->kvdo.initializedThreadCount,
|
|
Packit Service |
d40955 |
"threadID %u (completion type %d) is less than thread count %u",
|
|
Packit Service |
d40955 |
threadID, enqueueable->completion->type,
|
|
Packit Service |
d40955 |
layer->kvdo.initializedThreadCount) != UDS_SUCCESS) {
|
|
Packit Service |
d40955 |
BUG();
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
if (enqueueable->completion->type == VIO_COMPLETION) {
|
|
Packit Service |
d40955 |
vioAddTraceRecord(asVIO(enqueueable->completion),
|
|
Packit Service |
d40955 |
THIS_LOCATION("$F($cb)"));
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
setupWorkItem(&kvdoEnqueueable->workItem, kvdoEnqueueWork,
|
|
Packit Service |
d40955 |
(KvdoWorkFunction) enqueueable->completion->callback,
|
|
Packit Service |
d40955 |
REQ_Q_ACTION_COMPLETION);
|
|
Packit Service |
d40955 |
enqueueKVDOThreadWork(&layer->kvdo.threads[threadID],
|
|
Packit Service |
d40955 |
&kvdoEnqueueable->workItem);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
ThreadID kvdoGetCurrentThreadID(void)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
KVDOThread *thread = getWorkQueuePrivateData();
|
|
Packit Service |
d40955 |
if (thread == NULL) {
|
|
Packit Service |
d40955 |
return INVALID_THREAD_ID;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
ThreadID threadID = thread->threadID;
|
|
Packit Service |
d40955 |
if (PARANOID_THREAD_CONSISTENCY_CHECKS) {
|
|
Packit Service |
d40955 |
KVDO *kvdo = thread->kvdo;
|
|
Packit Service |
d40955 |
KernelLayer *kernelLayer = asKernelLayer(getPhysicalLayer());
|
|
Packit Service |
d40955 |
BUG_ON(&kernelLayer->kvdo != kvdo);
|
|
Packit Service |
d40955 |
BUG_ON(threadID >= kvdo->initializedThreadCount);
|
|
Packit Service |
d40955 |
BUG_ON(thread != &kvdo->threads[threadID]);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
return threadID;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
static PhysicalLayer *getKernelPhysicalLayer(void)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
KVDOThread *thread = getWorkQueuePrivateData();
|
|
Packit Service |
d40955 |
if (thread == NULL) {
|
|
Packit Service |
d40955 |
return NULL;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
KVDO *kvdo = thread->kvdo;
|
|
Packit Service |
d40955 |
KernelLayer *layer = container_of(kvdo, KernelLayer, kvdo);
|
|
Packit Service |
d40955 |
return &layer->common;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
void initKernelVDOOnce(void)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
registerPhysicalLayerGetter(getKernelPhysicalLayer);
|
|
Packit Service |
d40955 |
}
|