|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
cbade1 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
cbade1 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
cbade1 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
cbade1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
cbade1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
cbade1 |
* GNU General Public License for more details.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
cbade1 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
cbade1 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
cbade1 |
* 02110-1301, USA.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/deviceConfig.c#14 $
|
|
Packit Service |
cbade1 |
*/
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
#include "deviceConfig.h"
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
#include <linux/device-mapper.h>
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
#include "logger.h"
|
|
Packit Service |
cbade1 |
#include "memoryAlloc.h"
|
|
Packit Service |
cbade1 |
#include "stringUtils.h"
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
#include "kernelLayer.h"
|
|
Packit Service |
cbade1 |
#include "vdoStringUtils.h"
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
#include "constants.h"
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
enum {
|
|
Packit Service |
cbade1 |
// If we bump this, update the arrays below
|
|
Packit Service |
cbade1 |
TABLE_VERSION = 2,
|
|
Packit Service |
cbade1 |
// Limits used when parsing thread-count config spec strings
|
|
Packit Service |
cbade1 |
BIO_ROTATION_INTERVAL_LIMIT = 1024,
|
|
Packit Service |
cbade1 |
LOGICAL_THREAD_COUNT_LIMIT = 60,
|
|
Packit Service |
cbade1 |
PHYSICAL_THREAD_COUNT_LIMIT = 16,
|
|
Packit Service |
cbade1 |
THREAD_COUNT_LIMIT = 100,
|
|
Packit Service |
cbade1 |
// XXX The bio-submission queue configuration defaults are temporarily
|
|
Packit Service |
cbade1 |
// still being defined here until the new runtime-based thread
|
|
Packit Service |
cbade1 |
// configuration has been fully implemented for managed VDO devices.
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// How many bio submission work queues to use
|
|
Packit Service |
cbade1 |
DEFAULT_NUM_BIO_SUBMIT_QUEUES = 4,
|
|
Packit Service |
cbade1 |
// How often to rotate between bio submission work queues
|
|
Packit Service |
cbade1 |
DEFAULT_BIO_SUBMIT_QUEUE_ROTATE_INTERVAL = 64,
|
|
Packit Service |
cbade1 |
};
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// arrays for handling different table versions
|
|
Packit Service |
cbade1 |
static const uint8_t REQUIRED_ARGC[] = {10, 12, 9};
|
|
Packit Service |
cbade1 |
static const uint8_t POOL_NAME_ARG_INDEX[] = {8, 10, 8};
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Decide the version number from argv.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param [in] argc The number of table values
|
|
Packit Service |
cbade1 |
* @param [in] argv The array of table values
|
|
Packit Service |
cbade1 |
* @param [out] errorPtr A pointer to return a error string in
|
|
Packit Service |
cbade1 |
* @param [out] versionPtr A pointer to return the version
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @return VDO_SUCCESS or an error code
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
static int getVersionNumber(int argc,
|
|
Packit Service |
cbade1 |
char **argv,
|
|
Packit Service |
cbade1 |
char **errorPtr,
|
|
Packit Service |
cbade1 |
TableVersion *versionPtr)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
// version, if it exists, is in a form of V<n>
|
|
Packit Service |
cbade1 |
if (sscanf(argv[0], "V%u", versionPtr) == 1) {
|
|
Packit Service |
cbade1 |
if (*versionPtr < 1 || *versionPtr > TABLE_VERSION) {
|
|
Packit Service |
cbade1 |
*errorPtr = "Unknown version number detected";
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
} else {
|
|
Packit Service |
cbade1 |
// V0 actually has no version number in the table string
|
|
Packit Service |
cbade1 |
*versionPtr = 0;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// V0 and V1 have no optional parameters. There will always be
|
|
Packit Service |
cbade1 |
// a parameter for thread config, even if its a "." to show
|
|
Packit Service |
cbade1 |
// its an empty list.
|
|
Packit Service |
cbade1 |
if (*versionPtr <= 1) {
|
|
Packit Service |
cbade1 |
if (argc != REQUIRED_ARGC[*versionPtr]) {
|
|
Packit Service |
cbade1 |
*errorPtr = "Incorrect number of arguments for version";
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
} else if (argc < REQUIRED_ARGC[*versionPtr]) {
|
|
Packit Service |
cbade1 |
*errorPtr = "Incorrect number of arguments for version";
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
if (*versionPtr != TABLE_VERSION) {
|
|
Packit Service |
cbade1 |
logWarning("Detected version mismatch between kernel module and tools "
|
|
Packit Service |
cbade1 |
" kernel: %d, tool: %d", TABLE_VERSION, *versionPtr);
|
|
Packit Service |
cbade1 |
logWarning("Please consider upgrading management tools to match kernel.");
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**********************************************************************/
|
|
Packit Service |
cbade1 |
int getPoolNameFromArgv(int argc,
|
|
Packit Service |
cbade1 |
char **argv,
|
|
Packit Service |
cbade1 |
char **errorPtr,
|
|
Packit Service |
cbade1 |
char **poolNamePtr)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
TableVersion version;
|
|
Packit Service |
cbade1 |
int result = getVersionNumber(argc, argv, errorPtr, &version);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
*poolNamePtr = argv[POOL_NAME_ARG_INDEX[version]];
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Resolve the config with write policy, physical size, and other unspecified
|
|
Packit Service |
cbade1 |
* fields based on the device, if needed.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param [in,out] config The config possibly missing values
|
|
Packit Service |
cbade1 |
* @param [in] verbose Whether to log about the underlying device
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
static void resolveConfigWithDevice(DeviceConfig *config,
|
|
Packit Service |
cbade1 |
bool verbose)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
struct dm_dev *dev = config->ownedDevice;
|
|
Packit Service |
cbade1 |
struct request_queue *requestQueue = bdev_get_queue(dev->bdev);
|
|
Packit Service |
cbade1 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
|
|
Packit Service |
cbade1 |
bool flushSupported
|
|
Packit Service |
cbade1 |
= ((requestQueue->queue_flags & (1ULL << QUEUE_FLAG_WC)) != 0);
|
|
Packit Service |
cbade1 |
bool fuaSupported
|
|
Packit Service |
cbade1 |
= ((requestQueue->queue_flags & (1ULL << QUEUE_FLAG_FUA)) != 0);
|
|
Packit Service |
cbade1 |
#else
|
|
Packit Service |
cbade1 |
bool flushSupported = ((requestQueue->flush_flags & REQ_FLUSH) == REQ_FLUSH);
|
|
Packit Service |
cbade1 |
bool fuaSupported = ((requestQueue->flush_flags & REQ_FUA) == REQ_FUA);
|
|
Packit Service |
cbade1 |
#endif
|
|
Packit Service |
cbade1 |
if (verbose) {
|
|
Packit Service |
cbade1 |
logInfo("underlying device, REQ_FLUSH: %s, REQ_FUA: %s",
|
|
Packit Service |
cbade1 |
(flushSupported ? "supported" : "not supported"),
|
|
Packit Service |
cbade1 |
(fuaSupported ? "supported" : "not supported"));
|
|
Packit Service |
cbade1 |
} else {
|
|
Packit Service |
cbade1 |
// We should probably always log, but need to make sure that makes sense
|
|
Packit Service |
cbade1 |
// before changing behavior.
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
if (config->writePolicy == WRITE_POLICY_AUTO) {
|
|
Packit Service |
cbade1 |
config->writePolicy
|
|
Packit Service |
cbade1 |
= (flushSupported ? WRITE_POLICY_ASYNC : WRITE_POLICY_SYNC);
|
|
Packit Service |
cbade1 |
logInfo("Using write policy %s automatically.",
|
|
Packit Service |
cbade1 |
getConfigWritePolicyString(config));
|
|
Packit Service |
cbade1 |
} else {
|
|
Packit Service |
cbade1 |
logInfo("Using write policy %s.", getConfigWritePolicyString(config));
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
if (flushSupported && (config->writePolicy == WRITE_POLICY_SYNC)) {
|
|
Packit Service |
cbade1 |
logWarning("WARNING: Running in sync mode atop a device supporting flushes"
|
|
Packit Service |
cbade1 |
" is dangerous!");
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
if (config->version == 0) {
|
|
Packit Service |
cbade1 |
uint64_t deviceSize = i_size_read(dev->bdev->bd_inode);
|
|
Packit Service |
cbade1 |
config->physicalBlocks = deviceSize / VDO_BLOCK_SIZE;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Parse a two-valued option into a bool.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param [in] boolStr The string value to convert to a bool
|
|
Packit Service |
cbade1 |
* @param [in] trueStr The string value which should be converted to true
|
|
Packit Service |
cbade1 |
* @param [in] falseStr The string value which should be converted to false
|
|
Packit Service |
cbade1 |
* @param [out] boolPtr A pointer to return the bool value in
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @return VDO_SUCCESS or an error if boolStr is neither trueStr nor falseStr
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
__attribute__((warn_unused_result))
|
|
Packit Service |
cbade1 |
static inline int parseBool(const char *boolStr,
|
|
Packit Service |
cbade1 |
const char *trueStr,
|
|
Packit Service |
cbade1 |
const char *falseStr,
|
|
Packit Service |
cbade1 |
bool *boolPtr)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
bool value = false;
|
|
Packit Service |
cbade1 |
if (strcmp(boolStr, trueStr) == 0) {
|
|
Packit Service |
cbade1 |
value = true;
|
|
Packit Service |
cbade1 |
} else if (strcmp(boolStr, falseStr) == 0) {
|
|
Packit Service |
cbade1 |
value = false;
|
|
Packit Service |
cbade1 |
} else {
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
*boolPtr = value;
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Process one component of a thread parameter configuration string and
|
|
Packit Service |
cbade1 |
* update the configuration data structure.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* If the thread count requested is invalid, a message is logged and
|
|
Packit Service |
cbade1 |
* -EINVAL returned. If the thread name is unknown, a message is logged
|
|
Packit Service |
cbade1 |
* but no error is returned.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param threadParamType The type of thread specified
|
|
Packit Service |
cbade1 |
* @param count The thread count requested
|
|
Packit Service |
cbade1 |
* @param config The configuration data structure to update
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @return VDO_SUCCESS or -EINVAL
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
static int processOneThreadConfigSpec(const char *threadParamType,
|
|
Packit Service |
cbade1 |
unsigned int count,
|
|
Packit Service |
cbade1 |
ThreadCountConfig *config)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
// Handle limited thread parameters
|
|
Packit Service |
cbade1 |
if (strcmp(threadParamType, "bioRotationInterval") == 0) {
|
|
Packit Service |
cbade1 |
if (count == 0) {
|
|
Packit Service |
cbade1 |
logError("thread config string error:"
|
|
Packit Service |
cbade1 |
" 'bioRotationInterval' of at least 1 is required");
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
} else if (count > BIO_ROTATION_INTERVAL_LIMIT) {
|
|
Packit Service |
cbade1 |
logError("thread config string error:"
|
|
Packit Service |
cbade1 |
" 'bioRotationInterval' cannot be higher than %d",
|
|
Packit Service |
cbade1 |
BIO_ROTATION_INTERVAL_LIMIT);
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
config->bioRotationInterval = count;
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
} else if (strcmp(threadParamType, "logical") == 0) {
|
|
Packit Service |
cbade1 |
if (count > LOGICAL_THREAD_COUNT_LIMIT) {
|
|
Packit Service |
cbade1 |
logError("thread config string error: at most %d 'logical' threads"
|
|
Packit Service |
cbade1 |
" are allowed",
|
|
Packit Service |
cbade1 |
LOGICAL_THREAD_COUNT_LIMIT);
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
config->logicalZones = count;
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
} else if (strcmp(threadParamType, "physical") == 0) {
|
|
Packit Service |
cbade1 |
if (count > PHYSICAL_THREAD_COUNT_LIMIT) {
|
|
Packit Service |
cbade1 |
logError("thread config string error: at most %d 'physical' threads"
|
|
Packit Service |
cbade1 |
" are allowed",
|
|
Packit Service |
cbade1 |
PHYSICAL_THREAD_COUNT_LIMIT);
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
config->physicalZones = count;
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
} else {
|
|
Packit Service |
cbade1 |
// Handle other thread count parameters
|
|
Packit Service |
cbade1 |
if (count > THREAD_COUNT_LIMIT) {
|
|
Packit Service |
cbade1 |
logError("thread config string error: at most %d '%s' threads"
|
|
Packit Service |
cbade1 |
" are allowed",
|
|
Packit Service |
cbade1 |
THREAD_COUNT_LIMIT, threadParamType);
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
if (strcmp(threadParamType, "hash") == 0) {
|
|
Packit Service |
cbade1 |
config->hashZones = count;
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
} else if (strcmp(threadParamType, "cpu") == 0) {
|
|
Packit Service |
cbade1 |
if (count == 0) {
|
|
Packit Service |
cbade1 |
logError("thread config string error:"
|
|
Packit Service |
cbade1 |
" at least one 'cpu' thread required");
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
config->cpuThreads = count;
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
} else if (strcmp(threadParamType, "ack") == 0) {
|
|
Packit Service |
cbade1 |
config->bioAckThreads = count;
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
} else if (strcmp(threadParamType, "bio") == 0) {
|
|
Packit Service |
cbade1 |
if (count == 0) {
|
|
Packit Service |
cbade1 |
logError("thread config string error:"
|
|
Packit Service |
cbade1 |
" at least one 'bio' thread required");
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
config->bioThreads = count;
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Don't fail, just log. This will handle version mismatches between
|
|
Packit Service |
cbade1 |
// user mode tools and kernel.
|
|
Packit Service |
cbade1 |
logInfo("unknown thread parameter type \"%s\"", threadParamType);
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Parse one component of a thread parameter configuration string and
|
|
Packit Service |
cbade1 |
* update the configuration data structure.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param spec The thread parameter specification string
|
|
Packit Service |
cbade1 |
* @param config The configuration data to be updated
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
static int parseOneThreadConfigSpec(const char *spec,
|
|
Packit Service |
cbade1 |
ThreadCountConfig *config)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
char **fields;
|
|
Packit Service |
cbade1 |
int result = splitString(spec, '=', &fields);
|
|
Packit Service |
cbade1 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
if ((fields[0] == NULL) || (fields[1] == NULL) || (fields[2] != NULL)) {
|
|
Packit Service |
cbade1 |
logError("thread config string error:"
|
|
Packit Service |
cbade1 |
" expected thread parameter assignment, saw \"%s\"",
|
|
Packit Service |
cbade1 |
spec);
|
|
Packit Service |
cbade1 |
freeStringArray(fields);
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
unsigned int count;
|
|
Packit Service |
cbade1 |
result = stringToUInt(fields[1], &count);
|
|
Packit Service |
cbade1 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
cbade1 |
logError("thread config string error: integer value needed, found \"%s\"",
|
|
Packit Service |
cbade1 |
fields[1]);
|
|
Packit Service |
cbade1 |
freeStringArray(fields);
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
result = processOneThreadConfigSpec(fields[0], count, config);
|
|
Packit Service |
cbade1 |
freeStringArray(fields);
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Parse the configuration string passed and update the specified
|
|
Packit Service |
cbade1 |
* counts and other parameters of various types of threads to be created.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* The configuration string should contain one or more comma-separated specs
|
|
Packit Service |
cbade1 |
* of the form "typename=number"; the supported type names are "cpu", "ack",
|
|
Packit Service |
cbade1 |
* "bio", "bioRotationInterval", "logical", "physical", and "hash".
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* If an error occurs during parsing of a single key/value pair, we deem
|
|
Packit Service |
cbade1 |
* it serious enough to stop further parsing.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* This function can't set the "reason" value the caller wants to pass
|
|
Packit Service |
cbade1 |
* back, because we'd want to format it to say which field was
|
|
Packit Service |
cbade1 |
* invalid, and we can't allocate the "reason" strings dynamically. So
|
|
Packit Service |
cbade1 |
* if an error occurs, we'll log the details and pass back an error.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param string Thread parameter configuration string
|
|
Packit Service |
cbade1 |
* @param config The thread configuration data to update
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @return VDO_SUCCESS or -EINVAL or -ENOMEM
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
static int parseThreadConfigString(const char *string,
|
|
Packit Service |
cbade1 |
ThreadCountConfig *config)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
int result = VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
char **specs;
|
|
Packit Service |
cbade1 |
if (strcmp(".", string) != 0) {
|
|
Packit Service |
cbade1 |
result = splitString(string, ',', &specs);
|
|
Packit Service |
cbade1 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
for (unsigned int i = 0; specs[i] != NULL; i++) {
|
|
Packit Service |
cbade1 |
result = parseOneThreadConfigSpec(specs[i], config);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
break;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
freeStringArray(specs);
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Process one component of an optional parameter string and
|
|
Packit Service |
cbade1 |
* update the configuration data structure.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* If the value requested is invalid, a message is logged and
|
|
Packit Service |
cbade1 |
* -EINVAL returned. If the key is unknown, a message is logged
|
|
Packit Service |
cbade1 |
* but no error is returned.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param key The optional parameter key name
|
|
Packit Service |
cbade1 |
* @param value The optional parameter value
|
|
Packit Service |
cbade1 |
* @param config The configuration data structure to update
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @return VDO_SUCCESS or -EINVAL
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
static int processOneKeyValuePair(const char *key,
|
|
Packit Service |
cbade1 |
unsigned int value,
|
|
Packit Service |
cbade1 |
DeviceConfig *config)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
// Non thread optional parameters
|
|
Packit Service |
cbade1 |
if (strcmp(key, "maxDiscard") == 0) {
|
|
Packit Service |
cbade1 |
if (value == 0) {
|
|
Packit Service |
cbade1 |
logError("optional parameter error:"
|
|
Packit Service |
cbade1 |
" at least one max discard block required");
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
// Max discard sectors in blkdev_issue_discard is UINT_MAX >> 9
|
|
Packit Service |
cbade1 |
if (value > (UINT_MAX / VDO_BLOCK_SIZE)) {
|
|
Packit Service |
cbade1 |
logError("optional parameter error: at most %d max discard"
|
|
Packit Service |
cbade1 |
" blocks are allowed", UINT_MAX / VDO_BLOCK_SIZE);
|
|
Packit Service |
cbade1 |
return -EINVAL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
config->maxDiscardBlocks = value;
|
|
Packit Service |
cbade1 |
return VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
// Handles unknown key names
|
|
Packit Service |
cbade1 |
return processOneThreadConfigSpec(key, value, &config->threadCounts);
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Parse one key/value pair and update the configuration
|
|
Packit Service |
cbade1 |
* data structure.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param key The optional key name
|
|
Packit Service |
cbade1 |
* @param value The optional value
|
|
Packit Service |
cbade1 |
* @param config The configuration data to be updated
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @return VDO_SUCCESS or error
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
static int parseOneKeyValuePair(const char *key,
|
|
Packit Service |
cbade1 |
const char *value,
|
|
Packit Service |
cbade1 |
DeviceConfig *config)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
if (strcmp(key, "deduplication") == 0) {
|
|
Packit Service |
cbade1 |
return parseBool(value, "on", "off", &config->deduplication);
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// The remaining arguments must have integral values.
|
|
Packit Service |
cbade1 |
unsigned int count;
|
|
Packit Service |
cbade1 |
int result = stringToUInt(value, &count);
|
|
Packit Service |
cbade1 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
cbade1 |
logError("optional config string error: integer value needed, found \"%s\"",
|
|
Packit Service |
cbade1 |
value);
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
return processOneKeyValuePair(key, count, config);
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Parse all key/value pairs from a list of arguments.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* If an error occurs during parsing of a single key/value pair, we deem
|
|
Packit Service |
cbade1 |
* it serious enough to stop further parsing.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* This function can't set the "reason" value the caller wants to pass
|
|
Packit Service |
cbade1 |
* back, because we'd want to format it to say which field was
|
|
Packit Service |
cbade1 |
* invalid, and we can't allocate the "reason" strings dynamically. So
|
|
Packit Service |
cbade1 |
* if an error occurs, we'll log the details and return the error.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param argc The total number of arguments in list
|
|
Packit Service |
cbade1 |
* @param argv The list of key/value pairs
|
|
Packit Service |
cbade1 |
* @param config The device configuration data to update
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @return VDO_SUCCESS or error
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
static int parseKeyValuePairs(int argc,
|
|
Packit Service |
cbade1 |
char **argv,
|
|
Packit Service |
cbade1 |
DeviceConfig *config)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
int result = VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
while (argc) {
|
|
Packit Service |
cbade1 |
result = parseOneKeyValuePair(argv[0], argv[1], config);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
break;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
argc -= 2;
|
|
Packit Service |
cbade1 |
argv += 2;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Parse the configuration string passed in for optional arguments.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* For V0/V1 configurations, there will only be one optional parameter;
|
|
Packit Service |
cbade1 |
* the thread configuration. The configuration string should contain
|
|
Packit Service |
cbade1 |
* one or more comma-separated specs of the form "typename=number"; the
|
|
Packit Service |
cbade1 |
* supported type names are "cpu", "ack", "bio", "bioRotationInterval",
|
|
Packit Service |
cbade1 |
* "logical", "physical", and "hash".
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* For V2 configurations and beyond, there could be any number of
|
|
Packit Service |
cbade1 |
* arguments. They should contain one or more key/value pairs
|
|
Packit Service |
cbade1 |
* separated by a space.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param argSet The structure holding the arguments to parse
|
|
Packit Service |
cbade1 |
* @param errorPtr Pointer to a buffer to hold the error string
|
|
Packit Service |
cbade1 |
* @param config Pointer to device configuration data to update
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @return VDO_SUCCESS or error
|
|
Packit Service |
cbade1 |
*/
|
|
Packit Service |
cbade1 |
int parseOptionalArguments(struct dm_arg_set *argSet,
|
|
Packit Service |
cbade1 |
char **errorPtr,
|
|
Packit Service |
cbade1 |
DeviceConfig *config)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
int result = VDO_SUCCESS;
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
if (config->version == 0 || config->version == 1) {
|
|
Packit Service |
cbade1 |
result = parseThreadConfigString(argSet->argv[0],
|
|
Packit Service |
cbade1 |
&config->threadCounts);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
*errorPtr = "Invalid thread-count configuration";
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
} else {
|
|
Packit Service |
cbade1 |
if ((argSet->argc % 2) != 0) {
|
|
Packit Service |
cbade1 |
*errorPtr = "Odd number of optional arguments given but they"
|
|
Packit Service |
cbade1 |
" should be <key> <value> pairs";
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
result = parseKeyValuePairs(argSet->argc, argSet->argv, config);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
*errorPtr = "Invalid optional argument configuration";
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**
|
|
Packit Service |
cbade1 |
* Handle a parsing error.
|
|
Packit Service |
cbade1 |
*
|
|
Packit Service |
cbade1 |
* @param configPtr A pointer to the config to free
|
|
Packit Service |
cbade1 |
* @param errorPtr A place to store a constant string about the error
|
|
Packit Service |
cbade1 |
* @param errorStr A constant string to store in errorPtr
|
|
Packit Service |
cbade1 |
**/
|
|
Packit Service |
cbade1 |
static void handleParseError(DeviceConfig **configPtr,
|
|
Packit Service |
cbade1 |
char **errorPtr,
|
|
Packit Service |
cbade1 |
char *errorStr)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
freeDeviceConfig(configPtr);
|
|
Packit Service |
cbade1 |
*errorPtr = errorStr;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**********************************************************************/
|
|
Packit Service |
cbade1 |
int parseDeviceConfig(int argc,
|
|
Packit Service |
cbade1 |
char **argv,
|
|
Packit Service |
cbade1 |
struct dm_target *ti,
|
|
Packit Service |
cbade1 |
bool verbose,
|
|
Packit Service |
cbade1 |
DeviceConfig **configPtr)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
char **errorPtr = &ti->error;
|
|
Packit Service |
cbade1 |
DeviceConfig *config = NULL;
|
|
Packit Service |
cbade1 |
int result = ALLOCATE(1, DeviceConfig, "DeviceConfig", &config);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Could not allocate config structure");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
config->owningTarget = ti;
|
|
Packit Service |
cbade1 |
initializeRing(&config->configNode);
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Save the original string.
|
|
Packit Service |
cbade1 |
result = joinStrings(argv, argc, ' ', &config->originalString);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Could not populate string");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Set defaults.
|
|
Packit Service |
cbade1 |
//
|
|
Packit Service |
cbade1 |
// XXX Defaults for bioThreads and bioRotationInterval are currently defined
|
|
Packit Service |
cbade1 |
// using the old configuration scheme of constants. These values are relied
|
|
Packit Service |
cbade1 |
// upon for performance testing on MGH machines currently.
|
|
Packit Service |
cbade1 |
// This should be replaced with the normally used testing defaults being
|
|
Packit Service |
cbade1 |
// defined in the file-based thread-configuration settings. The values used
|
|
Packit Service |
cbade1 |
// as defaults internally should really be those needed for VDO in its
|
|
Packit Service |
cbade1 |
// default shipped-product state.
|
|
Packit Service |
cbade1 |
config->threadCounts = (ThreadCountConfig) {
|
|
Packit Service |
cbade1 |
.bioAckThreads = 1,
|
|
Packit Service |
cbade1 |
.bioThreads = DEFAULT_NUM_BIO_SUBMIT_QUEUES,
|
|
Packit Service |
cbade1 |
.bioRotationInterval = DEFAULT_BIO_SUBMIT_QUEUE_ROTATE_INTERVAL,
|
|
Packit Service |
cbade1 |
.cpuThreads = 1,
|
|
Packit Service |
cbade1 |
.logicalZones = 0,
|
|
Packit Service |
cbade1 |
.physicalZones = 0,
|
|
Packit Service |
cbade1 |
.hashZones = 0,
|
|
Packit Service |
cbade1 |
};
|
|
Packit Service |
cbade1 |
config->maxDiscardBlocks = 1;
|
|
Packit Service |
cbade1 |
config->deduplication = true;
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
struct dm_arg_set argSet;
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
argSet.argc = argc;
|
|
Packit Service |
cbade1 |
argSet.argv = argv;
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
result = getVersionNumber(argc, argv, errorPtr, &config->version);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
// getVersionNumber sets errorPtr itself.
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, *errorPtr);
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
// Move the arg pointer forward only if the argument was there.
|
|
Packit Service |
cbade1 |
if (config->version >= 1) {
|
|
Packit Service |
cbade1 |
dm_shift_arg(&argSet);
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
result = duplicateString(dm_shift_arg(&argSet), "parent device name",
|
|
Packit Service |
cbade1 |
&config->parentDeviceName);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Could not copy parent device name");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Get the physical blocks, if known.
|
|
Packit Service |
cbade1 |
if (config->version >= 1) {
|
|
Packit Service |
cbade1 |
result = kstrtoull(dm_shift_arg(&argSet), 10, &config->physicalBlocks);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Invalid physical block count");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Get the logical block size and validate
|
|
Packit Service |
cbade1 |
bool enable512e;
|
|
Packit Service |
cbade1 |
result = parseBool(dm_shift_arg(&argSet), "512", "4096", &enable512e);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Invalid logical block size");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
config->logicalBlockSize = (enable512e ? 512 : 4096);
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Skip past the two no longer used read cache options.
|
|
Packit Service |
cbade1 |
if (config->version <= 1) {
|
|
Packit Service |
cbade1 |
dm_consume_args(&argSet, 2);
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Get the page cache size.
|
|
Packit Service |
cbade1 |
result = stringToUInt(dm_shift_arg(&argSet), &config->cacheSize);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Invalid block map page cache size");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Get the block map era length.
|
|
Packit Service |
cbade1 |
result = stringToUInt(dm_shift_arg(&argSet), &config->blockMapMaximumAge);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Invalid block map maximum age");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Get the MD RAID5 optimization mode and validate
|
|
Packit Service |
cbade1 |
result = parseBool(dm_shift_arg(&argSet), "on", "off",
|
|
Packit Service |
cbade1 |
&config->mdRaid5ModeEnabled);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Invalid MD RAID5 mode");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Get the write policy and validate.
|
|
Packit Service |
cbade1 |
if (strcmp(argSet.argv[0], "async") == 0) {
|
|
Packit Service |
cbade1 |
config->writePolicy = WRITE_POLICY_ASYNC;
|
|
Packit Service |
cbade1 |
} else if (strcmp(argSet.argv[0], "async-unsafe") == 0) {
|
|
Packit Service |
cbade1 |
config->writePolicy = WRITE_POLICY_ASYNC_UNSAFE;
|
|
Packit Service |
cbade1 |
} else if (strcmp(argSet.argv[0], "sync") == 0) {
|
|
Packit Service |
cbade1 |
config->writePolicy = WRITE_POLICY_SYNC;
|
|
Packit Service |
cbade1 |
} else if (strcmp(argSet.argv[0], "auto") == 0) {
|
|
Packit Service |
cbade1 |
config->writePolicy = WRITE_POLICY_AUTO;
|
|
Packit Service |
cbade1 |
} else {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Invalid write policy");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
dm_shift_arg(&argSet);
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Make sure the enum to get the pool name from argv directly is still in
|
|
Packit Service |
cbade1 |
// sync with the parsing of the table line.
|
|
Packit Service |
cbade1 |
if (&argSet.argv[0] != &argv[POOL_NAME_ARG_INDEX[config->version]]) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Pool name not in expected location");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Get the address where the albserver is running. Check for validation
|
|
Packit Service |
cbade1 |
// is done in dedupe.c code during startKernelLayer call
|
|
Packit Service |
cbade1 |
result = duplicateString(dm_shift_arg(&argSet), "pool name",
|
|
Packit Service |
cbade1 |
&config->poolName);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Could not copy pool name");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Get the optional arguments and validate.
|
|
Packit Service |
cbade1 |
result = parseOptionalArguments(&argSet, errorPtr, config);
|
|
Packit Service |
cbade1 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
cbade1 |
// parseOptionalArguments sets errorPtr itself.
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, *errorPtr);
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/*
|
|
Packit Service |
cbade1 |
* Logical, physical, and hash zone counts can all be zero; then we get one
|
|
Packit Service |
cbade1 |
* thread doing everything, our older configuration. If any zone count is
|
|
Packit Service |
cbade1 |
* non-zero, the others must be as well.
|
|
Packit Service |
cbade1 |
*/
|
|
Packit Service |
cbade1 |
if (((config->threadCounts.logicalZones == 0)
|
|
Packit Service |
cbade1 |
!= (config->threadCounts.physicalZones == 0))
|
|
Packit Service |
cbade1 |
|| ((config->threadCounts.physicalZones == 0)
|
|
Packit Service |
cbade1 |
!= (config->threadCounts.hashZones == 0))
|
|
Packit Service |
cbade1 |
) {
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr,
|
|
Packit Service |
cbade1 |
"Logical, physical, and hash zones counts must all be"
|
|
Packit Service |
cbade1 |
" zero or all non-zero");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
result = dm_get_device(ti, config->parentDeviceName,
|
|
Packit Service |
cbade1 |
dm_table_get_mode(ti->table), &config->ownedDevice);
|
|
Packit Service |
cbade1 |
if (result != 0) {
|
|
Packit Service |
cbade1 |
logError("couldn't open device \"%s\": error %d",
|
|
Packit Service |
cbade1 |
config->parentDeviceName, result);
|
|
Packit Service |
cbade1 |
handleParseError(&config, errorPtr, "Unable to open storage device");
|
|
Packit Service |
cbade1 |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
resolveConfigWithDevice(config, verbose);
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
*configPtr = config;
|
|
Packit Service |
cbade1 |
return result;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**********************************************************************/
|
|
Packit Service |
cbade1 |
void freeDeviceConfig(DeviceConfig **configPtr)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
if (configPtr == NULL) {
|
|
Packit Service |
cbade1 |
return;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
DeviceConfig *config = *configPtr;
|
|
Packit Service |
cbade1 |
if (config == NULL) {
|
|
Packit Service |
cbade1 |
*configPtr = NULL;
|
|
Packit Service |
cbade1 |
return;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
if (config->ownedDevice != NULL) {
|
|
Packit Service |
cbade1 |
dm_put_device(config->owningTarget, config->ownedDevice);
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
FREE(config->poolName);
|
|
Packit Service |
cbade1 |
FREE(config->parentDeviceName);
|
|
Packit Service |
cbade1 |
FREE(config->originalString);
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
// Reduce the chance a use-after-free (as in BZ 1669960) happens to work.
|
|
Packit Service |
cbade1 |
memset(config, 0, sizeof(*config));
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
FREE(config);
|
|
Packit Service |
cbade1 |
*configPtr = NULL;
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**********************************************************************/
|
|
Packit Service |
cbade1 |
const char *getConfigWritePolicyString(DeviceConfig *config)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
switch (config->writePolicy) {
|
|
Packit Service |
cbade1 |
case WRITE_POLICY_AUTO:
|
|
Packit Service |
cbade1 |
return "auto";
|
|
Packit Service |
cbade1 |
case WRITE_POLICY_ASYNC:
|
|
Packit Service |
cbade1 |
return "async";
|
|
Packit Service |
cbade1 |
case WRITE_POLICY_ASYNC_UNSAFE:
|
|
Packit Service |
cbade1 |
return "async-unsafe";
|
|
Packit Service |
cbade1 |
case WRITE_POLICY_SYNC:
|
|
Packit Service |
cbade1 |
return "sync";
|
|
Packit Service |
cbade1 |
default:
|
|
Packit Service |
cbade1 |
return "unknown";
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
|
|
Packit Service |
cbade1 |
/**********************************************************************/
|
|
Packit Service |
cbade1 |
void setDeviceConfigLayer(DeviceConfig *config, KernelLayer *layer)
|
|
Packit Service |
cbade1 |
{
|
|
Packit Service |
cbade1 |
unspliceRingNode(&config->configNode);
|
|
Packit Service |
cbade1 |
if (layer != NULL) {
|
|
Packit Service |
cbade1 |
pushRingNode(&layer->deviceConfigRing, &config->configNode);
|
|
Packit Service |
cbade1 |
}
|
|
Packit Service |
cbade1 |
config->layer = layer;
|
|
Packit Service |
cbade1 |
}
|