
This reverts commit f34328adf2
.
Signed-off-by: Robert Baldyga <robert.baldyga@huawei.com>
2480 lines
68 KiB
C
2480 lines
68 KiB
C
/*
|
|
* Copyright(c) 2012-2022 Intel Corporation
|
|
* Copyright(c) 2024 Huawei Technologies
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <inttypes.h>
|
|
#include <limits.h>
|
|
#include <fstab.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <linux/fs.h>
|
|
#include "argp.h"
|
|
#include "cas_lib.h"
|
|
#include "cas_lib_utils.h"
|
|
#include "safeclib/safe_str_lib.h"
|
|
#include <cas_ioctl_codes.h>
|
|
#include "statistics_view.h"
|
|
|
|
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
|
|
|
#define HELP_HEADER OCF_PREFIX_LONG
|
|
|
|
#define WRONG_DEVICE_ERROR "Specified caching device '%s' is not supported.\n"
|
|
#define NOT_BLOCK_ERROR "Please use block device file.\n"
|
|
|
|
extern cas_printf_t cas_printf;
|
|
|
|
#define PARAM_TYPE_CORE 1
|
|
#define PARAM_TYPE_CACHE 2
|
|
|
|
/* struct with all the commands parameters/flags with default values */
|
|
struct command_args{
|
|
int force;
|
|
int cache_id;
|
|
int core_id;
|
|
int state;
|
|
int cache_mode;
|
|
int stats_filters;
|
|
int output_format;
|
|
int io_class_id;
|
|
int line_size;
|
|
int cache_state_flush;
|
|
int flush_data;
|
|
int cleaning_policy_type;
|
|
int promotion_policy_type;
|
|
int script_subcmd;
|
|
int try_add;
|
|
int update_path;
|
|
int detach;
|
|
int no_flush;
|
|
const char* cache_device;
|
|
const char* core_device;
|
|
uint32_t params_type;
|
|
uint32_t params_count;
|
|
bool verbose;
|
|
bool by_id_path;
|
|
};
|
|
|
|
static struct command_args command_args_values = {
|
|
.force = 0,
|
|
.cache_id = OCF_CACHE_ID_INVALID,
|
|
.core_id = OCF_CORE_ID_INVALID,
|
|
.state = CACHE_INIT_NEW,
|
|
.cache_mode = ocf_cache_mode_none,
|
|
.stats_filters = STATS_FILTER_DEFAULT,
|
|
.output_format = OUTPUT_FORMAT_DEFAULT,
|
|
.io_class_id = OCF_IO_CLASS_INVALID,
|
|
.line_size = ocf_cache_line_size_none,
|
|
.cache_state_flush = UNDEFINED, /* three state logic: YES NO UNDEFINED */
|
|
.flush_data = 1,
|
|
.cleaning_policy_type = 0,
|
|
.promotion_policy_type = 0,
|
|
.script_subcmd = -1,
|
|
.try_add = false,
|
|
.update_path = false,
|
|
.detach = false,
|
|
.no_flush = false,
|
|
.cache_device = NULL,
|
|
.core_device = NULL,
|
|
.by_id_path = false,
|
|
|
|
.params_type = 0,
|
|
.params_count = 0,
|
|
.verbose = false,
|
|
};
|
|
|
|
int validate_device_name(const char *dev_name) {
|
|
if (strnlen(dev_name, MAX_STR_LEN) >= MAX_STR_LEN) {
|
|
cas_printf(LOG_ERR, "Illegal device name\n");
|
|
return FAILURE;
|
|
}
|
|
|
|
if (validate_dev(dev_name))
|
|
return FAILURE;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int command_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "cache-id")) {
|
|
if (validate_str_num(arg[0], "cache id", OCF_CACHE_ID_MIN,
|
|
OCF_CACHE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.cache_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "core-id")) {
|
|
if (validate_str_num(arg[0], "core id", 0, OCF_CORE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.core_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "core-device")) {
|
|
if (validate_device_name(arg[0]) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.core_device = arg[0];
|
|
} else if (!strcmp(opt, "cache-device")) {
|
|
if (validate_device_name(arg[0]) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.cache_device = arg[0];
|
|
} else if (!strcmp(opt, "no-data-flush")) {
|
|
command_args_values.flush_data = 0;
|
|
} else if (!strcmp(opt, "output-format")) {
|
|
command_args_values.output_format
|
|
= validate_str_output_format(arg[0]);
|
|
|
|
if (OUTPUT_FORMAT_INVALID == command_args_values.output_format)
|
|
return FAILURE;
|
|
} else if (!strcmp(opt, "cleaning-policy-type")) {
|
|
command_args_values.cleaning_policy_type = validate_str_cln_policy((const char*)arg[0]);
|
|
|
|
if (command_args_values.cleaning_policy_type < 0)
|
|
return FAILURE;
|
|
} else if (!strcmp(opt, "try-add")) {
|
|
command_args_values.try_add = true;
|
|
} else if (!strcmp(opt, "update-path")) {
|
|
command_args_values.update_path = true;
|
|
} else if (!strcmp(opt, "detach")) {
|
|
command_args_values.detach = true;
|
|
} else if (!strcmp(opt, "no-flush")) {
|
|
command_args_values.no_flush = true;
|
|
} else if (!strcmp(opt, "by-id-path")) {
|
|
command_args_values.by_id_path = true;
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/* Filler to print sub-commands */
|
|
int cmd_subcmd_print_subcmd(cli_option* option, int flag)
|
|
{
|
|
return !!(option->flags & CLI_OPTION_SUBCMD);
|
|
}
|
|
|
|
/* Filler to print parameters of given sub-command */
|
|
int cmd_subcmd_print_param(cli_option* option, int flag)
|
|
{
|
|
return (flag == (option->priv & flag));
|
|
}
|
|
|
|
static inline void cmd_subcmd_print_invalid_subcmd(cli_option* options)
|
|
{
|
|
cas_printf(LOG_ERR, "Invalid or missing first sub-command parameter. ");
|
|
cas_printf(LOG_ERR, "Expected one of the: {");
|
|
print_options_usage(LOG_ERR, options, "|", cmd_subcmd_print_subcmd, 0);
|
|
cas_printf(LOG_ERR, "}\n");
|
|
}
|
|
|
|
/* Print help for command with subcommands */
|
|
void cmd_subcmd_help(app *app_values, cli_command *cmd, int flag_required)
|
|
{
|
|
int i, flag = 0, all_ops, printed_ops;
|
|
char option_name[MAX_STR_LEN];
|
|
cli_option* iter = &(cmd->options[0]);
|
|
|
|
/* Print usage */
|
|
cas_printf(LOG_INFO, "Usage: %s --%s {", app_values->name, cmd->name);
|
|
print_options_usage(LOG_INFO, cmd->options, "|", cmd_subcmd_print_subcmd, 0);
|
|
cas_printf(LOG_INFO, "}\n\n");
|
|
|
|
print_command_header(app_values, cmd);
|
|
|
|
for (;iter->long_name; iter++, flag++) {
|
|
if (!(iter->flags & CLI_OPTION_SUBCMD)) {
|
|
continue;
|
|
}
|
|
|
|
cas_printf(LOG_INFO, "\n");
|
|
|
|
cas_printf(LOG_INFO, "%s:\n", iter->desc);
|
|
|
|
cas_printf(LOG_INFO, "Usage: %s --%s --%s ", app_values->name,
|
|
cmd->name, iter->long_name);
|
|
|
|
all_ops = printed_ops = 0;
|
|
for (i = 0; cmd->options[i].long_name != NULL; i++) {
|
|
if (0 == cmd->options[i].priv) {
|
|
continue;
|
|
}
|
|
|
|
if (1 == cmd_subcmd_print_param(&cmd->options[i], (1 << flag))) {
|
|
all_ops++;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if (1 == cmd_subcmd_print_param(&cmd->options[i], (1 << flag_required))) {
|
|
printed_ops++;
|
|
}
|
|
}
|
|
|
|
print_options_usage(LOG_INFO, cmd->options, " ", cmd_subcmd_print_param,
|
|
(1 << flag) | (1 << flag_required));
|
|
|
|
if (all_ops != printed_ops) {
|
|
cas_printf(LOG_INFO, " [option...]");
|
|
}
|
|
command_name_in_brackets(option_name, MAX_STR_LEN, iter->short_name, iter->long_name);
|
|
cas_printf(LOG_INFO, "\nOptions that are valid with %s are:\n", option_name);
|
|
|
|
print_list_options(cmd->options, (1 << flag), cmd_subcmd_print_param);
|
|
|
|
cas_printf(LOG_INFO, "\n");
|
|
}
|
|
}
|
|
|
|
int remove_core_command_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "cache-id")){
|
|
if (validate_str_num(arg[0], "cache id", OCF_CACHE_ID_MIN, OCF_CACHE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.cache_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "core-id")){
|
|
if (validate_str_num(arg[0], "core id", 0, OCF_CORE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.core_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "force")){
|
|
command_args_values.force = 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int core_pool_remove_command_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "device")) {
|
|
if (strnlen_s(arg[0], MAX_STR_LEN) >= MAX_STR_LEN) {
|
|
cas_printf(LOG_ERR, "Illegal device %s\n", arg[0]);
|
|
return FAILURE;
|
|
}
|
|
|
|
command_args_values.core_device = arg[0];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int start_cache_command_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "force")) {
|
|
command_args_values.force = 1;
|
|
} else if (!strcmp(opt, "cache-id")) {
|
|
if (validate_str_num(arg[0], "cache id", OCF_CACHE_ID_MIN, OCF_CACHE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.cache_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "load")) {
|
|
|
|
command_args_values.state = CACHE_INIT_LOAD;
|
|
} else if (!strcmp(opt, "cache-device")) {
|
|
if(validate_device_name(arg[0]) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.cache_device = arg[0];
|
|
} else if (!strcmp(opt, "cache-mode")) {
|
|
command_args_values.cache_mode =
|
|
validate_str_cache_mode((const char*)arg[0]);
|
|
|
|
if (command_args_values.cache_mode < 0)
|
|
return FAILURE;
|
|
} else if (!strcmp(opt, "cache-line-size")) {
|
|
if (validate_str_num_sbd(arg[0], "cache line size", ocf_cache_line_size_min / KiB,
|
|
ocf_cache_line_size_max / KiB) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.line_size = atoi((const char*)arg[0]) * KiB;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define xstr(s) str(s)
|
|
#define str(s) #s
|
|
|
|
#define CACHE_ID_DESC "Identifier of cache instance <"xstr(OCF_CACHE_ID_MIN)"-"xstr(OCF_CACHE_ID_MAX)">"
|
|
#define CACHE_ID_DESC_LONG CACHE_ID_DESC " (if not provided, the first available number will be used)"
|
|
|
|
/* OCF_CORE_ID_MAX is defined by arithmetic operations on OCF_CORE_MAX. As a result there is no easy way
|
|
* to stringify OCF_CORE_ID_MAX. To work around this, additional definition for max core id is introduced here.
|
|
* In case of mismatch between header and local definition preprocessor error is triggered. */
|
|
#define _CASADM_CORE_ID_MAX 4095
|
|
#if (_CASADM_CORE_ID_MAX != OCF_CORE_ID_MAX)
|
|
#error "Max core id definitions discrepancy. Please update above definition."
|
|
#endif
|
|
#define CORE_ID_DESC "Identifier of core <0-"xstr(_CASADM_CORE_ID_MAX)"> within given cache instance"
|
|
|
|
#define CACHE_DEVICE_DESC "Caching device to be used"
|
|
#define CORE_DEVICE_DESC "Path to core device"
|
|
#define CACHE_LINE_SIZE_DESC "Set cache line size in kibibytes: {4,8,16,32,64}[KiB] (default: %d)"
|
|
|
|
|
|
static cli_option start_options[] = {
|
|
{'d', "cache-device", CACHE_DEVICE_DESC, 1, "DEVICE", CLI_OPTION_REQUIRED},
|
|
{'i', "cache-id", CACHE_ID_DESC_LONG, 1, "ID", 0},
|
|
{'l', "load", "Load cache metadata from caching device (DANGEROUS - see manual or Admin Guide for details)"},
|
|
{'f', "force", "Force the creation of cache instance"},
|
|
{'c', "cache-mode", "Set cache mode from available: {"CAS_CLI_HELP_START_CACHE_MODES"} "CAS_CLI_HELP_START_CACHE_MODES_FULL"; without this parameter Write-Through will be set by default", 1, "NAME"},
|
|
{'x', "cache-line-size", CACHE_LINE_SIZE_DESC, 1, "NUMBER", CLI_OPTION_DEFAULT_INT, 0, 0, ocf_cache_line_size_default / KiB},
|
|
{0}
|
|
};
|
|
|
|
static cli_option attach_cache_options[] = {
|
|
{'d', "cache-device", CACHE_DEVICE_DESC, 1, "DEVICE", CLI_OPTION_REQUIRED},
|
|
{'i', "cache-id", CACHE_ID_DESC_LONG, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'f', "force", "Force attaching the cache device"},
|
|
{0}
|
|
};
|
|
|
|
static int check_fs(const char* device, bool force)
|
|
{
|
|
char cache_dev_path[MAX_STR_LEN];
|
|
static const char fsck_cmd[] = "/sbin/fsck -n %s > /dev/null 2>&1";
|
|
static const uint32_t size = MAX_STR_LEN + sizeof(fsck_cmd) + 1;
|
|
char buff[size];
|
|
|
|
if (get_dev_path(device, cache_dev_path, sizeof(cache_dev_path))) {
|
|
cas_printf(LOG_ERR, "Device does not exist\n");
|
|
return FAILURE;
|
|
}
|
|
|
|
snprintf(buff, sizeof(buff), fsck_cmd, cache_dev_path);
|
|
|
|
if (!system(buff)) {
|
|
if (force) {
|
|
cas_printf(LOG_INFO, "A filesystem existed on %s. "
|
|
"Data may have been lost\n",
|
|
device);
|
|
} else {
|
|
/* file system on cache device */
|
|
cas_printf(LOG_ERR, "A filesystem exists on %s. "
|
|
"Specify the --force option if you "
|
|
"wish to add the cache anyway.\n"
|
|
"Note: this may result in loss of data\n",
|
|
device);
|
|
return FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int validate_cache_path(const char* path, bool force)
|
|
{
|
|
int cache_device;
|
|
struct stat device_info;
|
|
|
|
|
|
cache_device = open(path, O_RDONLY);
|
|
|
|
if (cache_device < 0) {
|
|
cas_printf(LOG_ERR, "Couldn't open cache device %s.\n", path);
|
|
return FAILURE;
|
|
}
|
|
|
|
if (fstat(cache_device, &device_info)) {
|
|
close(cache_device);
|
|
cas_printf(LOG_ERR, "Could not stat target device:%s!\n",
|
|
path);
|
|
return FAILURE;
|
|
}
|
|
|
|
if (!S_ISBLK(device_info.st_mode)) {
|
|
close(cache_device);
|
|
cas_printf(LOG_ERR, WRONG_DEVICE_ERROR NOT_BLOCK_ERROR,
|
|
path);
|
|
return FAILURE;
|
|
}
|
|
|
|
if (check_fs(path, force)) {
|
|
close(cache_device);
|
|
return FAILURE;
|
|
}
|
|
|
|
if (close(cache_device) < 0) {
|
|
cas_printf(LOG_ERR, "Couldn't close the cache device.\n");
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int handle_cache_attach(void)
|
|
{
|
|
return attach_cache(
|
|
command_args_values.cache_id,
|
|
command_args_values.cache_device,
|
|
command_args_values.force
|
|
);
|
|
}
|
|
|
|
int handle_cache_detach(void)
|
|
{
|
|
return detach_cache(command_args_values.cache_id);
|
|
}
|
|
|
|
int handle_start()
|
|
{
|
|
int status;
|
|
|
|
if (command_args_values.state == CACHE_INIT_LOAD) {
|
|
if (command_args_values.force ||
|
|
command_args_values.line_size != ocf_cache_line_size_none ||
|
|
command_args_values.cache_mode != ocf_cache_mode_none ||
|
|
command_args_values.cache_id != OCF_CACHE_ID_INVALID) {
|
|
cas_printf(LOG_ERR, "Use of 'load' with 'force', 'cache-id',"
|
|
" 'cache-mode' or 'cache-line-size'"
|
|
" simultaneously is forbidden.\n");
|
|
return FAILURE;
|
|
}
|
|
} else {
|
|
if (command_args_values.line_size == ocf_cache_line_size_none) {
|
|
command_args_values.line_size = ocf_cache_line_size_default;
|
|
}
|
|
|
|
if (command_args_values.cache_mode == ocf_cache_mode_none) {
|
|
command_args_values.cache_mode = ocf_cache_mode_default;
|
|
}
|
|
}
|
|
|
|
if (validate_cache_path(command_args_values.cache_device,
|
|
command_args_values.force) == FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
|
|
status = start_cache(command_args_values.cache_id,
|
|
command_args_values.state,
|
|
command_args_values.cache_device,
|
|
command_args_values.cache_mode,
|
|
command_args_values.line_size,
|
|
command_args_values.force);
|
|
|
|
return status;
|
|
}
|
|
|
|
static cli_option list_options[] = {
|
|
{'o', "output-format", "Output format: {table|csv}", 1, "FORMAT", 0},
|
|
{'b', "by-id-path", "Display by-id path to disks instead of short form /dev/sdx"},
|
|
{0}
|
|
};
|
|
|
|
int handle_list()
|
|
{
|
|
return list_caches(command_args_values.output_format, command_args_values.by_id_path);
|
|
}
|
|
|
|
static cli_option stats_options[] = {
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'j', "core-id", "Limit display of core-specific statistics to only ones pertaining to a specific core. If this option is not given, casadm will display statistics pertaining to all cores assigned to given cache instance.", 1, "ID", 0},
|
|
{'d', "io-class-id", "Display per IO class statistics", 1, "ID", CLI_OPTION_OPTIONAL_ARG},
|
|
{'f', "filter", "Apply filters from the following set: {all, conf, usage, req, blk, err}", 1, "FILTER-SPEC"},
|
|
{'o', "output-format", "Output format: {table|csv}", 1, "FORMAT"},
|
|
{'b', "by-id-path", "Display by-id path to disks instead of short form /dev/sdx"},
|
|
{0}
|
|
};
|
|
|
|
int stats_command_handle_option(char *opt, const char **arg)
|
|
{
|
|
int stats_filters;
|
|
|
|
if (!strcmp(opt, "cache-id")) {
|
|
if (validate_str_num(arg[0], "cache id", OCF_CACHE_ID_MIN,
|
|
OCF_CACHE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.cache_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "core-id")) {
|
|
if (validate_str_num(arg[0], "core id", 0,
|
|
OCF_CORE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.core_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "io-class-id")) {
|
|
if (NULL != arg[0]) {
|
|
if (validate_str_num(arg[0], "IO class id",
|
|
0, OCF_IO_CLASS_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.io_class_id = atoi(arg[0]);
|
|
}
|
|
command_args_values.stats_filters |= STATS_FILTER_IOCLASS;
|
|
} else if (!strcmp(opt, "filter")) {
|
|
stats_filters = validate_str_stats_filters(arg[0]);
|
|
if (STATS_FILTER_INVALID == stats_filters)
|
|
return FAILURE;
|
|
stats_filters |= (command_args_values.stats_filters & STATS_FILTER_IOCLASS);
|
|
command_args_values.stats_filters = stats_filters;
|
|
} else if (!strcmp(opt, "output-format")) {
|
|
command_args_values.output_format = validate_str_output_format(arg[0]);
|
|
if (OUTPUT_FORMAT_INVALID == command_args_values.output_format)
|
|
return FAILURE;
|
|
} else if (!strcmp(opt, "by-id-path")) {
|
|
command_args_values.by_id_path = true;
|
|
if (command_args_values.by_id_path == false)
|
|
return FAILURE;
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int handle_stats()
|
|
{
|
|
return cache_status(command_args_values.cache_id,
|
|
command_args_values.core_id,
|
|
command_args_values.io_class_id,
|
|
command_args_values.stats_filters,
|
|
command_args_values.output_format,
|
|
command_args_values.by_id_path);
|
|
}
|
|
|
|
static cli_option stop_options[] = {
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'n', "no-data-flush", "Do not flush dirty data (may be dangerous)"},
|
|
{0}
|
|
};
|
|
|
|
static cli_option detach_options[] = {
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{0}
|
|
};
|
|
|
|
int handle_stop()
|
|
{
|
|
return stop_cache(command_args_values.cache_id,
|
|
command_args_values.flush_data);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* GET/SET PARAM HELPERS *
|
|
*****************************************************************************/
|
|
|
|
#define SELECT_PARAM(_array, _index) ({ \
|
|
_array[_index].select = true; \
|
|
})
|
|
|
|
#define SELECT_CORE_PARAM(_index) \
|
|
SELECT_PARAM(cas_core_params, _index)
|
|
|
|
#define SELECT_CACHE_PARAM(_index) \
|
|
SELECT_PARAM(cas_cache_params, _index)
|
|
|
|
#define SET_PARAM(_array, _index, _value) ({ \
|
|
SELECT_PARAM(_array, _index); \
|
|
_array[_index].value = _value; \
|
|
command_args_values.params_count++; \
|
|
})
|
|
|
|
#define SET_CORE_PARAM(_index, _value) \
|
|
SET_PARAM(cas_core_params, _index, _value)
|
|
|
|
#define SET_CACHE_PARAM(_index, _value) \
|
|
SET_PARAM(cas_cache_params, _index, _value)
|
|
|
|
#define CORE_PARAMS_NS_BEGIN(_name, _desc) { \
|
|
.name = _name, \
|
|
.desc = _desc, \
|
|
.options = { \
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED}, \
|
|
{'j', "core-id", CORE_ID_DESC, 1, "ID"},
|
|
|
|
#define CORE_PARAMS_NS_END() \
|
|
{0}, \
|
|
},\
|
|
},
|
|
|
|
#define GET_CORE_PARAMS_NS(_name, _desc) { \
|
|
.name = _name, \
|
|
.desc = _desc, \
|
|
.options = { \
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED}, \
|
|
{'j', "core-id", CORE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED}, \
|
|
{'o', "output-format", "Output format: {table|csv}", 1, "FORMAT"}, \
|
|
CORE_PARAMS_NS_END()
|
|
|
|
#define CACHE_PARAMS_NS_BEGIN(_name, _desc) { \
|
|
.name = _name, \
|
|
.desc = _desc, \
|
|
.options = { \
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED}, \
|
|
|
|
#define CACHE_PARAMS_NS_END() \
|
|
{0}, \
|
|
},\
|
|
},
|
|
|
|
#define GET_CACHE_PARAMS_NS(_name, _desc) \
|
|
CACHE_PARAMS_NS_BEGIN(_name, _desc) \
|
|
{'o', "output-format", "Output format: {table|csv}", 1, "FORMAT"}, \
|
|
CACHE_PARAMS_NS_END()
|
|
|
|
|
|
static int core_param_handle_option_generic(char *opt, const char **arg, int (*handler)(char *opt, const char **arg))
|
|
{
|
|
command_args_values.params_type = PARAM_TYPE_CORE;
|
|
|
|
if (!strcmp(opt, "cache-id")) {
|
|
if (validate_str_num(arg[0], "cache id", OCF_CACHE_ID_MIN,
|
|
OCF_CACHE_ID_MAX) == FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
|
|
command_args_values.cache_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "core-id")) {
|
|
if (validate_str_num(arg[0], "core id", OCF_CORE_ID_MIN,
|
|
OCF_CORE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.core_id = atoi(arg[0]);
|
|
} else {
|
|
return handler ? handler(opt, arg) : FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
static int cache_param_handle_option_generic(char *opt, const char **arg, int (*handler)(char *opt, const char **arg))
|
|
{
|
|
command_args_values.params_type = PARAM_TYPE_CACHE;
|
|
|
|
if (!strcmp(opt, "cache-id")) {
|
|
if (validate_str_num(arg[0], "cache id", OCF_CACHE_ID_MIN,
|
|
OCF_CACHE_ID_MAX) == FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
|
|
command_args_values.cache_id = atoi(arg[0]);
|
|
} else {
|
|
return handler ? handler(opt, arg) : FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* PARAMS DEFINITIONS *
|
|
*****************************************************************************/
|
|
|
|
uint32_t seq_cutoff_threshold_transform(uint32_t value)
|
|
{
|
|
return value / KiB;
|
|
}
|
|
|
|
static char *seq_cutoff_policy_values[] = {
|
|
[ocf_seq_cutoff_policy_always] = "always",
|
|
[ocf_seq_cutoff_policy_full] = "full",
|
|
[ocf_seq_cutoff_policy_never] = "never",
|
|
NULL,
|
|
};
|
|
|
|
static struct cas_param cas_core_params[] = {
|
|
/* Sequential cutoff params */
|
|
[core_param_seq_cutoff_threshold] = {
|
|
.name = "Sequential cutoff threshold [KiB]" ,
|
|
.transform_value = seq_cutoff_threshold_transform,
|
|
},
|
|
[core_param_seq_cutoff_policy] = {
|
|
.name = "Sequential cutoff policy",
|
|
.value_names = seq_cutoff_policy_values,
|
|
},
|
|
[core_param_seq_cutoff_promotion_count] = {
|
|
.name = "Sequential cutoff promotion request count threshold",
|
|
},
|
|
{0},
|
|
};
|
|
|
|
static char *cleaning_policy_type_values[] = {
|
|
[ocf_cleaning_nop] = "nop",
|
|
[ocf_cleaning_alru] = "alru",
|
|
[ocf_cleaning_acp] = "acp",
|
|
NULL,
|
|
};
|
|
|
|
static char *promotion_policy_type_values[] = {
|
|
[ocf_promotion_always] = "always",
|
|
[ocf_promotion_nhit] = "nhit",
|
|
NULL,
|
|
};
|
|
|
|
static struct cas_param cas_cache_params[] = {
|
|
/* Cleaning policy type */
|
|
[cache_param_cleaning_policy_type] = {
|
|
.name = "Cleaning policy type" ,
|
|
.value_names = cleaning_policy_type_values,
|
|
},
|
|
|
|
/* Cleaning policy ALRU params */
|
|
[cache_param_cleaning_alru_wake_up_time] = {
|
|
.name = "Wake up time [s]" ,
|
|
},
|
|
[cache_param_cleaning_alru_stale_buffer_time] = {
|
|
.name = "Stale buffer time [s]" ,
|
|
},
|
|
[cache_param_cleaning_alru_flush_max_buffers] = {
|
|
.name = "Flush max buffers" ,
|
|
},
|
|
[cache_param_cleaning_alru_activity_threshold] = {
|
|
.name = "Activity threshold [ms]" ,
|
|
},
|
|
|
|
/* Cleaning policy ACP params */
|
|
[cache_param_cleaning_acp_wake_up_time] = {
|
|
.name = "Wake up time [ms]" ,
|
|
},
|
|
[cache_param_cleaning_acp_flush_max_buffers] = {
|
|
.name = "Flush max buffers" ,
|
|
},
|
|
|
|
/* Promotion policy type */
|
|
[cache_param_promotion_policy_type] = {
|
|
.name = "Promotion policy type",
|
|
.value_names = promotion_policy_type_values,
|
|
},
|
|
|
|
/*Promotion policy NHIT params */
|
|
[cache_param_promotion_nhit_insertion_threshold] = {
|
|
.name = "Insertion threshold",
|
|
},
|
|
[cache_param_promotion_nhit_trigger_threshold] = {
|
|
.name = "Policy trigger [%]",
|
|
},
|
|
{0},
|
|
};
|
|
|
|
/*****************************************************************************
|
|
* SET PARAM NAMESPACE *
|
|
*****************************************************************************/
|
|
|
|
#define SEQ_CUT_OFF_THRESHOLD_DESC "Sequential cutoff activation threshold [KiB]"
|
|
#define SEQ_CUT_OFF_POLICY_DESC "Sequential cutoff policy. " \
|
|
"Available policies: {always|full|never}"
|
|
#define SEQ_CUT_OFF_PROMO_COUNT_DESC "Sequential cutoff stream promotion request count threshold"
|
|
|
|
#define CLEANING_POLICY_TYPE_DESC "Cleaning policy type. " \
|
|
"Available policy types: {nop|alru|acp}"
|
|
|
|
#define CLEANING_ALRU_WAKE_UP_DESC "Cleaning thread sleep time after an idle wake up <%d-%d>[s] (default: %d s)"
|
|
#define CLEANING_ALRU_STALENESS_TIME_DESC "Time that has to pass from the last write operation before a dirty cache" \
|
|
" block can be scheduled to be flushed <%d-%d>[s] (default: %d s)"
|
|
#define CLEANING_ALRU_FLUSH_MAX_BUFFERS_DESC "Number of dirty cache blocks to be flushed in one cleaning cycle" \
|
|
" <%d-%d> (default: %d)"
|
|
#define CLEANING_ALRU_ACTIVITY_THRESHOLD_DESC "Cache idle time before flushing thread can start <%d-%d>[ms]" \
|
|
" (default: %d ms)"
|
|
|
|
#define CLEANING_ACP_WAKE_UP_DESC "Time between ACP cleaning thread iterations <%d-%d>[ms] (default: %d ms)"
|
|
#define CLEANING_ACP_MAX_BUFFERS_DESC "Number of cache lines flushed in single ACP cleaning thread iteration" \
|
|
" <%d-%d> (default: %d)"
|
|
|
|
#define PROMOTION_POLICY_TYPE_DESC "Promotion policy type. "\
|
|
"Available policy types: {always|nhit}"
|
|
|
|
#define PROMOTION_NHIT_TRIGGER_DESC "Cache occupancy value over which NHIT promotion is active " \
|
|
"<%d-%d>[%] (default: %d%)"
|
|
|
|
#define PROMOTION_NHIT_THRESHOLD_DESC "Number of requests for given core line " \
|
|
"after which NHIT policy allows insertion into cache <%d-%d> (default: %d)"
|
|
|
|
static cli_namespace set_param_namespace = {
|
|
.short_name = 'n',
|
|
.long_name = "name",
|
|
.entries = {
|
|
CORE_PARAMS_NS_BEGIN("seq-cutoff", "Sequential cutoff parameters")
|
|
{'t', "threshold", SEQ_CUT_OFF_THRESHOLD_DESC, 1, "KiB", 0},
|
|
{'p', "policy", SEQ_CUT_OFF_POLICY_DESC, 1, "POLICY", 0},
|
|
{0, "promotion-count", SEQ_CUT_OFF_PROMO_COUNT_DESC, 1, "NUMBER", 0},
|
|
CORE_PARAMS_NS_END()
|
|
|
|
CACHE_PARAMS_NS_BEGIN("cleaning", "Cleaning policy parameters")
|
|
{'p', "policy", CLEANING_POLICY_TYPE_DESC, 1, "POLICY", 0},
|
|
CACHE_PARAMS_NS_END()
|
|
|
|
CACHE_PARAMS_NS_BEGIN("promotion", "Promotion policy parameters")
|
|
{'p', "policy", PROMOTION_POLICY_TYPE_DESC, 1, "POLICY", 0},
|
|
CACHE_PARAMS_NS_END()
|
|
|
|
CACHE_PARAMS_NS_BEGIN("promotion-nhit", "Promotion policy NHIT parameters")
|
|
{'t', "threshold", PROMOTION_NHIT_THRESHOLD_DESC, 1, "NUMBER",
|
|
CLI_OPTION_RANGE_INT | CLI_OPTION_DEFAULT_INT,
|
|
OCF_NHIT_MIN_THRESHOLD, OCF_NHIT_MAX_THRESHOLD,
|
|
OCF_NHIT_THRESHOLD_DEFAULT},
|
|
{'o', "trigger", PROMOTION_NHIT_TRIGGER_DESC, 1, "NUMBER",
|
|
CLI_OPTION_RANGE_INT | CLI_OPTION_DEFAULT_INT,
|
|
OCF_NHIT_MIN_TRIGGER, OCF_NHIT_MAX_TRIGGER,
|
|
OCF_NHIT_TRIGGER_DEFAULT},
|
|
CACHE_PARAMS_NS_END()
|
|
|
|
CACHE_PARAMS_NS_BEGIN("cleaning-alru", "Cleaning policy ALRU parameters")
|
|
{'w', "wake-up", CLEANING_ALRU_WAKE_UP_DESC, 1, "NUMBER",
|
|
CLI_OPTION_RANGE_INT | CLI_OPTION_DEFAULT_INT,
|
|
OCF_ALRU_MIN_WAKE_UP, OCF_ALRU_MAX_WAKE_UP,
|
|
OCF_ALRU_DEFAULT_WAKE_UP},
|
|
{'s', "staleness-time", CLEANING_ALRU_STALENESS_TIME_DESC, 1, "NUMBER",
|
|
CLI_OPTION_RANGE_INT | CLI_OPTION_DEFAULT_INT,
|
|
OCF_ALRU_MIN_STALENESS_TIME, OCF_ALRU_MAX_STALENESS_TIME,
|
|
OCF_ALRU_DEFAULT_STALENESS_TIME},
|
|
{'b', "flush-max-buffers", CLEANING_ALRU_FLUSH_MAX_BUFFERS_DESC, 1, "NUMBER",
|
|
CLI_OPTION_RANGE_INT | CLI_OPTION_DEFAULT_INT,
|
|
OCF_ALRU_MIN_FLUSH_MAX_BUFFERS, OCF_ALRU_MAX_FLUSH_MAX_BUFFERS,
|
|
OCF_ALRU_DEFAULT_FLUSH_MAX_BUFFERS},
|
|
{'t', "activity-threshold", CLEANING_ALRU_ACTIVITY_THRESHOLD_DESC, 1, "NUMBER",
|
|
CLI_OPTION_RANGE_INT | CLI_OPTION_DEFAULT_INT,
|
|
OCF_ALRU_MIN_ACTIVITY_THRESHOLD, OCF_ALRU_MAX_ACTIVITY_THRESHOLD,
|
|
OCF_ALRU_DEFAULT_ACTIVITY_THRESHOLD},
|
|
CACHE_PARAMS_NS_END()
|
|
|
|
CACHE_PARAMS_NS_BEGIN("cleaning-acp", "Cleaning policy ACP parameters")
|
|
{'w', "wake-up", CLEANING_ACP_WAKE_UP_DESC, 1, "NUMBER",
|
|
CLI_OPTION_RANGE_INT | CLI_OPTION_DEFAULT_INT,
|
|
OCF_ACP_MIN_WAKE_UP, OCF_ACP_MAX_WAKE_UP,
|
|
OCF_ACP_DEFAULT_WAKE_UP},
|
|
{'b', "flush-max-buffers", CLEANING_ACP_MAX_BUFFERS_DESC, 1, "NUMBER",
|
|
CLI_OPTION_RANGE_INT | CLI_OPTION_DEFAULT_INT,
|
|
OCF_ACP_MIN_FLUSH_MAX_BUFFERS, OCF_ACP_MAX_FLUSH_MAX_BUFFERS,
|
|
OCF_ACP_DEFAULT_FLUSH_MAX_BUFFERS},
|
|
CACHE_PARAMS_NS_END()
|
|
|
|
{0},
|
|
},
|
|
};
|
|
|
|
int set_param_seq_cutoff_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "threshold")) {
|
|
if (validate_str_num(arg[0], "sequential cutoff threshold",
|
|
DIV_ROUND_UP(OCF_SEQ_CUTOFF_MIN_THRESHOLD, KiB),
|
|
OCF_SEQ_CUTOFF_MAX_THRESHOLD / KiB) == FAILURE)
|
|
return FAILURE;
|
|
|
|
SET_CORE_PARAM(core_param_seq_cutoff_threshold, atoi(arg[0]) * KiB);
|
|
} else if (!strcmp(opt, "policy")) {
|
|
if (!strcmp("always", arg[0])) {
|
|
SET_CORE_PARAM(core_param_seq_cutoff_policy,
|
|
ocf_seq_cutoff_policy_always);
|
|
} else if (!strcmp("full", arg[0])) {
|
|
SET_CORE_PARAM(core_param_seq_cutoff_policy,
|
|
ocf_seq_cutoff_policy_full);
|
|
} else if (!strcmp("never", arg[0])) {
|
|
SET_CORE_PARAM(core_param_seq_cutoff_policy,
|
|
ocf_seq_cutoff_policy_never);
|
|
} else {
|
|
cas_printf(LOG_ERR, "Error: Invalid policy name.\n");
|
|
return FAILURE;
|
|
}
|
|
} else if (!strcmp(opt, "promotion-count")) {
|
|
if (validate_str_num(arg[0], "sequential cutoff promotion request count",
|
|
OCF_SEQ_CUTOFF_MIN_PROMOTION_COUNT,
|
|
OCF_SEQ_CUTOFF_MAX_PROMOTION_COUNT) == FAILURE)
|
|
return FAILURE;
|
|
|
|
SET_CORE_PARAM(core_param_seq_cutoff_promotion_count, atoi(arg[0]));
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int set_param_cleaning_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "policy")) {
|
|
if (!strcmp("nop", arg[0])) {
|
|
SET_CACHE_PARAM(cache_param_cleaning_policy_type,
|
|
ocf_cleaning_nop);
|
|
} else if (!strcmp("alru", arg[0])) {
|
|
SET_CACHE_PARAM(cache_param_cleaning_policy_type,
|
|
ocf_cleaning_alru);
|
|
} else if (!strcmp("acp", arg[0])) {
|
|
SET_CACHE_PARAM(cache_param_cleaning_policy_type,
|
|
ocf_cleaning_acp);
|
|
} else {
|
|
cas_printf(LOG_ERR, "Error: Invalid policy name.\n");
|
|
return FAILURE;
|
|
}
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int set_param_cleaning_alru_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "wake-up")) {
|
|
if (validate_str_num(arg[0], "wake-up time",
|
|
OCF_ALRU_MIN_WAKE_UP, OCF_ALRU_MAX_WAKE_UP)) {
|
|
return FAILURE;
|
|
}
|
|
|
|
SET_CACHE_PARAM(cache_param_cleaning_alru_wake_up_time,
|
|
strtoul(arg[0], NULL, 10));
|
|
} else if (!strcmp(opt, "staleness-time")) {
|
|
if (validate_str_num(arg[0], "staleness time",
|
|
OCF_ALRU_MIN_STALENESS_TIME, OCF_ALRU_MAX_STALENESS_TIME)) {
|
|
return FAILURE;
|
|
}
|
|
|
|
SET_CACHE_PARAM(cache_param_cleaning_alru_stale_buffer_time,
|
|
strtoul(arg[0], NULL, 10));
|
|
} else if (!strcmp(opt, "flush-max-buffers")) {
|
|
if (validate_str_num(arg[0], "flush max buffers",
|
|
OCF_ALRU_MIN_FLUSH_MAX_BUFFERS, OCF_ALRU_MAX_FLUSH_MAX_BUFFERS)) {
|
|
return FAILURE;
|
|
}
|
|
|
|
SET_CACHE_PARAM(cache_param_cleaning_alru_flush_max_buffers,
|
|
strtoul(arg[0], NULL, 10));
|
|
} else if (!strcmp(opt, "activity-threshold")) {
|
|
if (validate_str_num(arg[0], "activity threshold",
|
|
OCF_ALRU_MIN_ACTIVITY_THRESHOLD, OCF_ALRU_MAX_ACTIVITY_THRESHOLD)) {
|
|
return FAILURE;
|
|
}
|
|
|
|
SET_CACHE_PARAM(cache_param_cleaning_alru_activity_threshold,
|
|
strtoul(arg[0], NULL, 10));
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int set_param_cleaning_acp_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "wake-up")) {
|
|
if (validate_str_num(arg[0], "wake-up time",
|
|
OCF_ACP_MIN_WAKE_UP, OCF_ACP_MAX_WAKE_UP)) {
|
|
return FAILURE;
|
|
}
|
|
|
|
SET_CACHE_PARAM(cache_param_cleaning_acp_wake_up_time,
|
|
strtoul(arg[0], NULL, 10));
|
|
} else if (!strcmp(opt, "flush-max-buffers")) {
|
|
if (validate_str_num(arg[0], "flush max buffers",
|
|
OCF_ACP_MIN_FLUSH_MAX_BUFFERS, OCF_ACP_MAX_FLUSH_MAX_BUFFERS)) {
|
|
return FAILURE;
|
|
}
|
|
|
|
SET_CACHE_PARAM(cache_param_cleaning_acp_flush_max_buffers,
|
|
strtoul(arg[0], NULL, 10));
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int set_param_promotion_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "policy")) {
|
|
if (!strcmp("always", arg[0])) {
|
|
SET_CACHE_PARAM(cache_param_promotion_policy_type,
|
|
ocf_promotion_always);
|
|
} else if (!strcmp("nhit", arg[0])) {
|
|
SET_CACHE_PARAM(cache_param_promotion_policy_type,
|
|
ocf_promotion_nhit);
|
|
} else {
|
|
cas_printf(LOG_ERR, "Error: Invalid policy name.\n");
|
|
return FAILURE;
|
|
}
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int set_param_promotion_nhit_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "threshold")) {
|
|
if (validate_str_num(arg[0], "threshold",
|
|
OCF_NHIT_MIN_THRESHOLD, OCF_NHIT_MAX_THRESHOLD)) {
|
|
return FAILURE;
|
|
}
|
|
|
|
SET_CACHE_PARAM(cache_param_promotion_nhit_insertion_threshold,
|
|
strtoul(arg[0], NULL, 10));
|
|
} else if (!strcmp(opt, "trigger")) {
|
|
if (validate_str_num(arg[0], "trigger",
|
|
OCF_NHIT_MIN_TRIGGER, OCF_NHIT_MAX_TRIGGER)) {
|
|
return FAILURE;
|
|
}
|
|
|
|
SET_CACHE_PARAM(cache_param_promotion_nhit_trigger_threshold,
|
|
strtoul(arg[0], NULL, 10));
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int set_param_namespace_handle_option(char *namespace, char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(namespace, "seq-cutoff")) {
|
|
return core_param_handle_option_generic(opt, arg,
|
|
set_param_seq_cutoff_handle_option);
|
|
} else if (!strcmp(namespace, "cleaning")) {
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
set_param_cleaning_handle_option);
|
|
} else if (!strcmp(namespace, "cleaning-alru")) {
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
set_param_cleaning_alru_handle_option);
|
|
} else if (!strcmp(namespace, "cleaning-acp")) {
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
set_param_cleaning_acp_handle_option);
|
|
} else if (!strcmp(namespace, "promotion")) {
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
set_param_promotion_handle_option);
|
|
} else if (!strcmp(namespace, "promotion-nhit")) {
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
set_param_promotion_nhit_handle_option);
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
}
|
|
|
|
|
|
int handle_set_param()
|
|
{
|
|
int err = 0;
|
|
|
|
if (command_args_values.params_count == 0) {
|
|
cas_printf(LOG_ERR, "Error: No parameters specified!\n");
|
|
return FAILURE;
|
|
}
|
|
|
|
switch (command_args_values.params_type) {
|
|
case PARAM_TYPE_CORE:
|
|
err = core_params_set(command_args_values.cache_id,
|
|
command_args_values.core_id,
|
|
cas_core_params);
|
|
break;
|
|
case PARAM_TYPE_CACHE:
|
|
err = cache_params_set(command_args_values.cache_id,
|
|
cas_cache_params);
|
|
break;
|
|
default:
|
|
err = FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (err)
|
|
cas_printf(LOG_ERR, "Setting runtime parameter failed!\n");
|
|
|
|
return err;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* GET PARAM NAMESPACE *
|
|
*****************************************************************************/
|
|
|
|
static cli_namespace get_param_namespace = {
|
|
.short_name = 'n',
|
|
.long_name = "name",
|
|
.entries = {
|
|
GET_CORE_PARAMS_NS("seq-cutoff", "Sequential cutoff parameters")
|
|
GET_CACHE_PARAMS_NS("cleaning", "Cleaning policy parameters")
|
|
GET_CACHE_PARAMS_NS("cleaning-alru", "Cleaning policy ALRU parameters")
|
|
GET_CACHE_PARAMS_NS("cleaning-acp", "Cleaning policy ACP parameters")
|
|
GET_CACHE_PARAMS_NS("promotion", "Promotion policy parameters")
|
|
GET_CACHE_PARAMS_NS("promotion-nhit", "Promotion policy NHIT parameters")
|
|
|
|
{0},
|
|
},
|
|
};
|
|
|
|
int get_param_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "output-format")) {
|
|
command_args_values.output_format = validate_str_output_format(arg[0]);
|
|
if (OUTPUT_FORMAT_INVALID == command_args_values.output_format)
|
|
return FAILURE;
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
int get_param_namespace_handle_option(char *namespace, char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(namespace, "seq-cutoff")) {
|
|
SELECT_CORE_PARAM(core_param_seq_cutoff_threshold);
|
|
SELECT_CORE_PARAM(core_param_seq_cutoff_policy);
|
|
SELECT_CORE_PARAM(core_param_seq_cutoff_promotion_count);
|
|
return core_param_handle_option_generic(opt, arg,
|
|
get_param_handle_option);
|
|
} else if (!strcmp(namespace, "cleaning")) {
|
|
SELECT_CACHE_PARAM(cache_param_cleaning_policy_type);
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
get_param_handle_option);
|
|
} else if (!strcmp(namespace, "cleaning-alru")) {
|
|
SELECT_CACHE_PARAM(cache_param_cleaning_alru_wake_up_time);
|
|
SELECT_CACHE_PARAM(cache_param_cleaning_alru_stale_buffer_time);
|
|
SELECT_CACHE_PARAM(cache_param_cleaning_alru_flush_max_buffers);
|
|
SELECT_CACHE_PARAM(cache_param_cleaning_alru_activity_threshold);
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
get_param_handle_option);
|
|
} else if (!strcmp(namespace, "cleaning-acp")) {
|
|
SELECT_CACHE_PARAM(cache_param_cleaning_acp_wake_up_time);
|
|
SELECT_CACHE_PARAM(cache_param_cleaning_acp_flush_max_buffers);
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
get_param_handle_option);
|
|
} else if (!strcmp(namespace, "promotion")) {
|
|
SELECT_CACHE_PARAM(cache_param_promotion_policy_type);
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
get_param_handle_option);
|
|
} else if (!strcmp(namespace, "promotion-nhit")) {
|
|
SELECT_CACHE_PARAM(cache_param_promotion_nhit_insertion_threshold);
|
|
SELECT_CACHE_PARAM(cache_param_promotion_nhit_trigger_threshold);
|
|
return cache_param_handle_option_generic(opt, arg,
|
|
get_param_handle_option);
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
}
|
|
|
|
int handle_get_param()
|
|
{
|
|
int format = TEXT;
|
|
int err = 0;
|
|
|
|
if (OUTPUT_FORMAT_CSV == command_args_values.output_format) {
|
|
format = RAW_CSV;
|
|
}
|
|
|
|
switch (command_args_values.params_type) {
|
|
case PARAM_TYPE_CORE:
|
|
err = core_params_get(command_args_values.cache_id,
|
|
command_args_values.core_id,
|
|
cas_core_params, format);
|
|
break;
|
|
case PARAM_TYPE_CACHE:
|
|
err = cache_params_get(command_args_values.cache_id,
|
|
cas_cache_params, format);
|
|
break;
|
|
default:
|
|
err = FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (err)
|
|
cas_printf(LOG_ERR, "Getting runtime parameter failed!\n");
|
|
|
|
return err;
|
|
}
|
|
|
|
static cli_option set_state_cache_mode_options[] = {
|
|
{'c', "cache-mode", "Cache mode. Available cache modes: {"CAS_CLI_HELP_SET_CACHE_MODES"}", 1, "NAME", CLI_OPTION_REQUIRED},
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'f', "flush-cache", "Flush all dirty data from cache before switching to new mode. Option is required when switching from Write-Back or Write-Only mode", 1, "yes|no",0},
|
|
{0},
|
|
};
|
|
|
|
int set_cache_mode_command_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "cache-mode")) {
|
|
command_args_values.cache_mode =
|
|
validate_str_cache_mode((const char*)arg[0]);
|
|
|
|
if (command_args_values.cache_mode < 0)
|
|
return FAILURE;
|
|
} else if (!strcmp(opt, "cache-id")) {
|
|
if (validate_str_num(arg[0], "cache id", OCF_CACHE_ID_MIN,
|
|
OCF_CACHE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
command_args_values.cache_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "flush-cache")) {
|
|
if (!strcmp("yes", arg[0]))
|
|
command_args_values.cache_state_flush = YES;
|
|
else if (!strcmp("no", arg[0]))
|
|
command_args_values.cache_state_flush = NO;
|
|
else {
|
|
cas_printf(LOG_ERR, "Error: 'yes' or 'no' required as an argument for -f option.\n");
|
|
return FAILURE;
|
|
}
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int handle_set_cache_mode()
|
|
{
|
|
return set_cache_mode(command_args_values.cache_mode,
|
|
command_args_values.cache_id,
|
|
command_args_values.cache_state_flush);
|
|
}
|
|
|
|
static cli_option add_options[] = {
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'j', "core-id", CORE_ID_DESC, 1, "ID", 0},
|
|
{'d', "core-device", CORE_DEVICE_DESC, 1, "DEVICE", CLI_OPTION_REQUIRED},
|
|
{0}
|
|
};
|
|
|
|
int handle_add()
|
|
{
|
|
return add_core(command_args_values.cache_id,
|
|
command_args_values.core_id,
|
|
command_args_values.core_device,
|
|
false, false);
|
|
}
|
|
|
|
static cli_option remove_options[] = {
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'j', "core-id", CORE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'f', "force", "Force active core removal without data flush"},
|
|
{0}
|
|
};
|
|
|
|
int handle_remove()
|
|
{
|
|
return remove_core(command_args_values.cache_id,
|
|
command_args_values.core_id,
|
|
false,
|
|
command_args_values.force);
|
|
}
|
|
|
|
static cli_option remove_inactive_options[] = {
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'j', "core-id", CORE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'f', "force", "Force dirty inactive core removal"},
|
|
{0}
|
|
};
|
|
|
|
int handle_remove_inactive()
|
|
{
|
|
return remove_inactive_core(command_args_values.cache_id,
|
|
command_args_values.core_id, command_args_values.force);
|
|
}
|
|
|
|
static cli_option core_pool_remove_options[] = {
|
|
{'d', "device", CORE_DEVICE_DESC, 1, "DEVICE", CLI_OPTION_REQUIRED},
|
|
{0}
|
|
};
|
|
|
|
int handle_core_pool_remove()
|
|
{
|
|
return core_pool_remove(command_args_values.core_device);
|
|
}
|
|
|
|
#define RESET_COUNTERS_CORE_ID_DESC "Identifier of core <0-"xstr(_CASADM_CORE_ID_MAX) \
|
|
"> within given cache instance. If not specified, statistics are reset " \
|
|
"for all cores in cache instance."
|
|
|
|
static cli_option reset_counters_options[] = {
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'j', "core-id", RESET_COUNTERS_CORE_ID_DESC, 1, "ID", 0},
|
|
{0}
|
|
};
|
|
|
|
int handle_reset_counters()
|
|
{
|
|
return reset_counters(command_args_values.cache_id,
|
|
command_args_values.core_id);
|
|
}
|
|
|
|
static cli_option flush_cache_options[] = {
|
|
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
|
|
{'j', "core-id", CORE_ID_DESC, 1, "ID", CLI_OPTION_OPTIONAL_ARG},
|
|
{0}
|
|
};
|
|
|
|
int handle_flush_cache()
|
|
{
|
|
if(command_args_values.core_id != OCF_CORE_ID_INVALID)
|
|
return flush_core(command_args_values.cache_id, command_args_values.core_id);
|
|
return flush_cache(command_args_values.cache_id);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* IO Classes Commands
|
|
******************************************************************************/
|
|
|
|
enum {
|
|
io_class_opt_subcmd_configure = 0,
|
|
io_class_opt_subcmd_list,
|
|
|
|
io_class_opt_cache_id,
|
|
io_class_opt_cache_file_load,
|
|
io_class_opt_output_format,
|
|
|
|
io_class_opt_io_class_id,
|
|
io_class_opt_prio,
|
|
io_class_opt_min_size,
|
|
io_class_opt_max_size,
|
|
io_class_opt_name,
|
|
io_class_opt_cache_mode,
|
|
|
|
io_class_opt_flag_required,
|
|
io_class_opt_flag_set,
|
|
|
|
io_class_opt_subcmd_unknown,
|
|
};
|
|
|
|
/* IO class command options */
|
|
static cli_option io_class_params_options[] = {
|
|
[io_class_opt_subcmd_configure] = {
|
|
.short_name = 'C',
|
|
.long_name = "load-config",
|
|
.desc = "Loads configuration for IO classes",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = 0,
|
|
.flags = CLI_OPTION_SUBCMD,
|
|
},
|
|
[io_class_opt_subcmd_list] = {
|
|
.short_name = 'L',
|
|
.long_name = "list",
|
|
.desc = "Lists currently configured IO classes",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = 0,
|
|
.flags = CLI_OPTION_SUBCMD,
|
|
},
|
|
[io_class_opt_cache_id] = {
|
|
.short_name = 'i',
|
|
.long_name = "cache-id",
|
|
.desc = CACHE_ID_DESC,
|
|
.args_count = 1,
|
|
.arg = "ID",
|
|
.priv = (1 << io_class_opt_subcmd_configure)
|
|
| (1 << io_class_opt_subcmd_list)
|
|
| (1 << io_class_opt_flag_required),
|
|
.flags = CLI_OPTION_RANGE_INT,
|
|
.max_value = 0,
|
|
.min_value = OCF_CACHE_ID_MAX,
|
|
},
|
|
[io_class_opt_cache_file_load] = {
|
|
.short_name = 'f',
|
|
.long_name = "file",
|
|
.desc = "Configuration file containing IO class definition",
|
|
.args_count = 1,
|
|
.arg = "FILE",
|
|
.priv = (1 << io_class_opt_subcmd_configure)
|
|
| (1 << io_class_opt_flag_required)
|
|
},
|
|
[io_class_opt_output_format] = {
|
|
.short_name = 'o',
|
|
.long_name = "output-format",
|
|
.desc = "Output format: {table|csv}",
|
|
.args_count = 1,
|
|
.arg = "FORMAT",
|
|
.priv = (1 << io_class_opt_subcmd_list)
|
|
},
|
|
|
|
[io_class_opt_io_class_id] = {
|
|
.short_name = 'd',
|
|
.long_name = "io-class-id",
|
|
.desc = "IO class ID",
|
|
.args_count = 1,
|
|
.arg = "ID",
|
|
.priv = (1 << io_class_opt_flag_required),
|
|
},
|
|
[io_class_opt_prio] = {
|
|
.short_name = 'p',
|
|
.long_name = "priority",
|
|
.desc = "IO class priority",
|
|
.args_count = 1,
|
|
.arg = xstr(OCF_IO_CLASS_PRIO_HIGHEST)"-"xstr(OCF_IO_CLASS_PRIO_LOWEST),
|
|
.flags = CLI_OPTION_RANGE_INT,
|
|
.min_value = OCF_IO_CLASS_PRIO_HIGHEST,
|
|
.max_value = OCF_IO_CLASS_PRIO_LOWEST,
|
|
},
|
|
[io_class_opt_min_size] = {
|
|
.short_name = 'm',
|
|
.long_name = "min-size",
|
|
.desc = "Guaranteed size of cache space for this IO class",
|
|
.args_count = 1,
|
|
.arg = "SIZE",
|
|
},
|
|
[io_class_opt_max_size] = {
|
|
.short_name = 'x',
|
|
.long_name = "max-size",
|
|
.desc = "Maximum size of cache space for this IO class",
|
|
.args_count = 1,
|
|
.arg = "SIZE",
|
|
},
|
|
[io_class_opt_name] = {
|
|
.short_name = 'n',
|
|
.long_name = "name",
|
|
.desc = "Optional textual name for this IO class",
|
|
.args_count = 1,
|
|
.arg = "NAME",
|
|
},
|
|
[io_class_opt_cache_mode] = {
|
|
.short_name = 'c',
|
|
.long_name = "cache-mode",
|
|
.desc = "Overwrite cache mode for this IO class from available: {"CAS_CLI_HELP_START_CACHE_MODES"}",
|
|
.args_count = 1,
|
|
.arg = "NAME",
|
|
},
|
|
|
|
{0}
|
|
};
|
|
|
|
struct {
|
|
int subcmd;
|
|
int cache_id;
|
|
int io_class_id;
|
|
int cache_mode;
|
|
int io_class_prio;
|
|
int output_format;
|
|
uint32_t min;
|
|
uint32_t max;
|
|
char file[MAX_STR_LEN];
|
|
char name[OCF_IO_CLASS_NAME_MAX];
|
|
} static io_class_params = {
|
|
.subcmd = io_class_opt_subcmd_unknown,
|
|
.cache_id = 0,
|
|
.file = "",
|
|
.output_format = OUTPUT_FORMAT_DEFAULT
|
|
};
|
|
|
|
/* Parser of option for IO class command */
|
|
int io_class_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (io_class_opt_subcmd_unknown == io_class_params.subcmd) {
|
|
/* First parameters which defines sub-command */
|
|
if (!strcmp(opt, "load-config")) {
|
|
io_class_params.subcmd = io_class_opt_subcmd_configure;
|
|
return 0;
|
|
} else if (!strcmp(opt, "list")) {
|
|
io_class_params.subcmd = io_class_opt_subcmd_list;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (!strcmp(opt, "cache-id")) {
|
|
if (command_handle_option(opt, arg))
|
|
return FAILURE;
|
|
|
|
io_class_params_options[io_class_opt_cache_id].priv |= (1 << io_class_opt_flag_set);
|
|
io_class_params.cache_id = command_args_values.cache_id;
|
|
} else if (!strcmp(opt, "file")) {
|
|
if (validate_path(arg[0], 0))
|
|
return FAILURE;
|
|
|
|
io_class_params_options[io_class_opt_cache_file_load].priv |= (1 << io_class_opt_flag_set);
|
|
|
|
strncpy_s(io_class_params.file, sizeof(io_class_params.file), arg[0], strnlen_s(arg[0], sizeof(io_class_params.file)));
|
|
} else if (!strcmp(opt, "output-format")) {
|
|
io_class_params.output_format = validate_str_output_format(arg[0]);
|
|
if (OUTPUT_FORMAT_INVALID == io_class_params.output_format)
|
|
return FAILURE;
|
|
|
|
io_class_params_options[io_class_opt_output_format].priv |= (1 << io_class_opt_flag_set);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Check if all required command were set depending on command type */
|
|
int io_class_is_missing() {
|
|
int result = 0;
|
|
int mask;
|
|
cli_option* iter = io_class_params_options;
|
|
|
|
for (;iter->long_name; iter++) {
|
|
char option_name[MAX_STR_LEN];
|
|
if (iter->flags & CLI_OPTION_DEFAULT_INT) {
|
|
continue;
|
|
}
|
|
|
|
command_name_in_brackets(option_name, MAX_STR_LEN, iter->short_name, iter->long_name);
|
|
|
|
if (iter->priv & (1 << io_class_opt_flag_set)) {
|
|
/* Option is set, check if this option is allowed */
|
|
mask = (1 << io_class_params.subcmd);
|
|
if (0 == (mask & iter->priv)) {
|
|
cas_printf(LOG_ERR, "Option '%s' is not allowed\n", option_name);
|
|
result = -1;
|
|
}
|
|
|
|
} else {
|
|
/* Option is missing, check if it is required for this sub-command*/
|
|
mask = (1 << io_class_params.subcmd) | (1 << io_class_opt_flag_required);
|
|
if (mask == (iter->priv & mask)) {
|
|
cas_printf(LOG_ERR, "Option '%s' is missing\n", option_name);
|
|
result = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Command handler */
|
|
int io_class_handle() {
|
|
/* Check if sub-command was specified */
|
|
if (io_class_opt_subcmd_unknown == io_class_params.subcmd) {
|
|
cmd_subcmd_print_invalid_subcmd(io_class_params_options);
|
|
return FAILURE;
|
|
}
|
|
|
|
/* Check if all required options are set */
|
|
if (io_class_is_missing()) {
|
|
return FAILURE;
|
|
}
|
|
|
|
switch (io_class_params.subcmd) {
|
|
case io_class_opt_subcmd_configure:
|
|
return partition_setup(io_class_params.cache_id,
|
|
io_class_params.file);
|
|
case io_class_opt_subcmd_list:
|
|
return partition_list(io_class_params.cache_id,
|
|
io_class_params.output_format);
|
|
}
|
|
|
|
return FAILURE;
|
|
}
|
|
|
|
void io_class_help(app *app_values, cli_command *cmd)
|
|
{
|
|
cmd_subcmd_help(app_values, cmd, io_class_opt_flag_required);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Script Commands
|
|
******************************************************************************/
|
|
enum {
|
|
script_cmd_unknown = -1,
|
|
|
|
script_cmd_min_id = 0,
|
|
|
|
script_cmd_check_cache_device = script_cmd_min_id,
|
|
|
|
script_cmd_add_core,
|
|
script_cmd_remove_core,
|
|
script_cmd_purge_cache,
|
|
script_cmd_purge_core,
|
|
|
|
script_cmd_max_id,
|
|
|
|
script_opt_min_id = script_cmd_max_id,
|
|
|
|
script_opt_cache_device = script_opt_min_id,
|
|
script_opt_cache_id,
|
|
script_opt_core_id,
|
|
script_opt_core_device,
|
|
script_opt_try_add,
|
|
script_opt_update_path,
|
|
script_opt_detach,
|
|
script_opt_no_flush,
|
|
|
|
script_opt_max_id,
|
|
|
|
script_opt_flag_set,
|
|
};
|
|
|
|
/*
|
|
* Field .priv in script_cmd_* elements contains id of required options,
|
|
* script_opt_* .priv fields contains id of commands, where they can be used
|
|
*/
|
|
static cli_option script_params_options[] = {
|
|
[script_cmd_check_cache_device] = {
|
|
.short_name = 0,
|
|
.long_name = "check-cache-device",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = (1 << script_opt_cache_device),
|
|
.flags = CLI_COMMAND_HIDDEN,
|
|
},
|
|
[script_cmd_add_core] = {
|
|
.short_name = 0,
|
|
.long_name = "add-core",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = (1 << script_opt_core_device)
|
|
| (1 << script_opt_cache_id),
|
|
.flags = CLI_COMMAND_HIDDEN,
|
|
},
|
|
[script_cmd_remove_core] = {
|
|
.short_name = 0,
|
|
.long_name = "remove-core",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = (1 << script_opt_cache_id)
|
|
| (1 << script_opt_core_id),
|
|
.flags = CLI_COMMAND_HIDDEN,
|
|
},
|
|
[script_cmd_purge_cache] = {
|
|
.short_name = 0,
|
|
.long_name = "purge-cache",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = (1 << script_opt_cache_id),
|
|
.flags = CLI_COMMAND_HIDDEN,
|
|
},
|
|
[script_cmd_purge_core] = {
|
|
.short_name = 0,
|
|
.long_name = "purge-core",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = (1 << script_opt_cache_id)
|
|
| (1 << script_opt_core_id),
|
|
.flags = CLI_COMMAND_HIDDEN,
|
|
},
|
|
[script_opt_cache_device] = {
|
|
.short_name = 0,
|
|
.long_name = "cache-device",
|
|
.args_count = 1,
|
|
.arg = "DEVICE",
|
|
.priv = (1 << script_cmd_check_cache_device),
|
|
.flags = CLI_OPTION_HIDDEN,
|
|
},
|
|
[script_opt_cache_id] = {
|
|
.short_name = 0,
|
|
.long_name = "cache-id",
|
|
.args_count = 1,
|
|
.arg = "ID",
|
|
.priv = (1 << script_cmd_remove_core)
|
|
| (1 << script_cmd_add_core)
|
|
| (1 << script_cmd_purge_cache)
|
|
| (1 << script_cmd_purge_core),
|
|
.flags = (CLI_OPTION_RANGE_INT | CLI_OPTION_HIDDEN),
|
|
.min_value = OCF_CACHE_ID_MIN,
|
|
.max_value = OCF_CACHE_ID_MAX,
|
|
},
|
|
[script_opt_core_id] = {
|
|
.short_name = 0,
|
|
.long_name = "core-id",
|
|
.args_count = 1,
|
|
.arg = "ID",
|
|
.priv = (1 << script_cmd_remove_core)
|
|
| (1 << script_cmd_add_core)
|
|
| (1 << script_cmd_purge_core),
|
|
.flags = (CLI_OPTION_RANGE_INT | CLI_OPTION_HIDDEN),
|
|
.min_value = OCF_CORE_ID_MIN,
|
|
.max_value = OCF_CORE_ID_MAX,
|
|
},
|
|
[script_opt_core_device] = {
|
|
.short_name = 0,
|
|
.long_name = "core-device",
|
|
.args_count = 1,
|
|
.arg = "DEVICE",
|
|
.priv = (1 << script_cmd_add_core),
|
|
.flags = CLI_OPTION_HIDDEN,
|
|
},
|
|
[script_opt_try_add] = {
|
|
.short_name = 0,
|
|
.long_name = "try-add",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = (1 << script_cmd_add_core),
|
|
.flags = CLI_OPTION_HIDDEN,
|
|
},
|
|
[script_opt_update_path] = {
|
|
.short_name = 0,
|
|
.long_name = "update-path",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = (1 << script_cmd_add_core),
|
|
.flags = CLI_OPTION_HIDDEN,
|
|
},
|
|
[script_opt_detach] = {
|
|
.short_name = 0,
|
|
.long_name = "detach",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = (1 << script_cmd_remove_core),
|
|
.flags = CLI_OPTION_HIDDEN,
|
|
},
|
|
[script_opt_no_flush] = {
|
|
.short_name = 0,
|
|
.long_name = "no-flush",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = (1 << script_cmd_remove_core),
|
|
.flags = CLI_OPTION_HIDDEN,
|
|
},
|
|
|
|
{0}
|
|
};
|
|
|
|
int script_handle_option(char *opt, const char **arg)
|
|
{
|
|
int id;
|
|
if (script_cmd_unknown == command_args_values.script_subcmd) {
|
|
for (id = script_cmd_min_id; id < script_cmd_max_id; id++) {
|
|
if (!strcmp(opt, script_params_options[id].long_name)) {
|
|
command_args_values.script_subcmd = id;
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
return FAILURE;
|
|
}
|
|
|
|
for (id = script_opt_min_id; id < script_opt_max_id; id++) {
|
|
if (!strcmp(opt, script_params_options[id].long_name)) {
|
|
if (command_handle_option(opt, arg) == FAILURE)
|
|
return FAILURE;
|
|
|
|
script_params_options[id].priv |= (1 << script_opt_flag_set);
|
|
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
|
|
return FAILURE;
|
|
}
|
|
|
|
int is_option_allowed(int option_id) {
|
|
cli_option option = script_params_options[option_id];
|
|
int commands_compatible_with_option = option.priv;
|
|
int selected_command = command_args_values.script_subcmd;
|
|
int command_flag = 1 << selected_command;
|
|
int option_is_allowed = command_flag & commands_compatible_with_option;
|
|
|
|
return option_is_allowed;
|
|
}
|
|
|
|
int is_option_required(int option_id) {
|
|
int option_flag = (1 << option_id);
|
|
int selected_command = command_args_values.script_subcmd;
|
|
int command_required_options = script_params_options[selected_command].priv;
|
|
int option_is_required = command_required_options & option_flag;
|
|
|
|
return option_is_required;
|
|
}
|
|
|
|
int script_command_is_valid() {
|
|
int result = SUCCESS;
|
|
int option_id;
|
|
cli_option* option = &script_params_options[script_opt_min_id];
|
|
|
|
for (option_id = script_opt_min_id; option_id < script_opt_max_id; option++, option_id++) {
|
|
char option_name[MAX_STR_LEN];
|
|
int option_is_set = option->priv & (1 << script_opt_flag_set);
|
|
int option_has_default_value = option->flags & CLI_OPTION_DEFAULT_INT;
|
|
|
|
if (option_has_default_value)
|
|
continue;
|
|
|
|
command_name_in_brackets(option_name, MAX_STR_LEN, option->short_name, option->long_name);
|
|
|
|
if (option_is_set) {
|
|
if (!is_option_allowed(option_id)) {
|
|
cas_printf(LOG_ERR, "Option '%s' is not allowed\n", option_name);
|
|
result = FAILURE;
|
|
}
|
|
} else {
|
|
if (is_option_required(option_id)) {
|
|
cas_printf(LOG_ERR, "Option '%s' is missing\n", option_name);
|
|
result = FAILURE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int script_handle() {
|
|
if (script_cmd_unknown == command_args_values.script_subcmd) {
|
|
cas_printf(LOG_ERR, "Invalid or missing first sub-command parameter\n");
|
|
return FAILURE;
|
|
}
|
|
|
|
if (script_command_is_valid() == FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
|
|
switch (command_args_values.script_subcmd) {
|
|
case script_cmd_check_cache_device:
|
|
return check_cache_device(command_args_values.cache_device);
|
|
case script_cmd_add_core:
|
|
return add_core(
|
|
command_args_values.cache_id,
|
|
command_args_values.core_id,
|
|
command_args_values.core_device,
|
|
command_args_values.try_add,
|
|
command_args_values.update_path
|
|
);
|
|
case script_cmd_remove_core:
|
|
return remove_core(
|
|
command_args_values.cache_id,
|
|
command_args_values.core_id,
|
|
command_args_values.detach,
|
|
command_args_values.no_flush
|
|
);
|
|
case script_cmd_purge_cache:
|
|
return purge_cache(command_args_values.cache_id);
|
|
case script_cmd_purge_core:
|
|
return purge_core(
|
|
command_args_values.cache_id,
|
|
command_args_values.core_id
|
|
);
|
|
}
|
|
|
|
return FAILURE;
|
|
}
|
|
|
|
static cli_option version_options[] = {
|
|
{
|
|
.short_name = 'o',
|
|
.long_name = "output-format",
|
|
.desc = "Output format: {table|csv}",
|
|
.args_count = 1,
|
|
.arg = "FORMAT",
|
|
},
|
|
{0}
|
|
};
|
|
|
|
int version_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "output-format")) {
|
|
command_args_values.output_format = validate_str_output_format(arg[0]);
|
|
if (OUTPUT_FORMAT_INVALID == command_args_values.output_format)
|
|
return FAILURE;
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int handle_version(void)
|
|
{
|
|
char buff[MAX_STR_LEN];
|
|
|
|
FILE *intermediate_file[2];
|
|
if (create_pipe_pair(intermediate_file)) {
|
|
cas_printf(LOG_ERR,"Failed to create unidirectional pipe.\n");
|
|
return FAILURE;
|
|
}
|
|
|
|
fprintf(intermediate_file[1], TAG(TABLE_HEADER) "Name,Version\n");
|
|
|
|
fprintf(intermediate_file[1], TAG(TABLE_ROW) OCF_LOGO " Cache Kernel Module,");
|
|
if (cas_module_version(buff, MAX_STR_LEN)) {
|
|
fprintf(intermediate_file[1], "Not Loaded\n");
|
|
} else {
|
|
fprintf(intermediate_file[1], "%s\n", buff);
|
|
}
|
|
|
|
fprintf(intermediate_file[1], TAG(TABLE_ROW) OCF_LOGO " CLI Utility,");
|
|
fprintf(intermediate_file[1], "%s\n", CAS_VERSION);
|
|
|
|
int format = TEXT;
|
|
if (OUTPUT_FORMAT_CSV == command_args_values.output_format) {
|
|
format = RAW_CSV;
|
|
}
|
|
|
|
fclose(intermediate_file[1]);
|
|
stat_format_output(intermediate_file[0], stdout, format);
|
|
fclose(intermediate_file[0]);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
static int handle_help();
|
|
|
|
/*******************************************************************************
|
|
* Standby commands
|
|
******************************************************************************/
|
|
|
|
enum {
|
|
standby_opt_subcmd_init = 0,
|
|
standby_opt_subcmd_load,
|
|
standby_opt_subcmd_detach,
|
|
standby_opt_subcmd_activate,
|
|
|
|
standby_opt_cache_id,
|
|
standby_opt_cache_line_size,
|
|
standby_opt_cache_device,
|
|
|
|
standby_opt_force,
|
|
|
|
standby_opt_flag_required,
|
|
standby_opt_flag_set,
|
|
|
|
standby_opt_subcmd_unknown,
|
|
};
|
|
|
|
/* Standby command options */
|
|
static cli_option standby_params_options[] = {
|
|
[standby_opt_subcmd_init] = {
|
|
.long_name = "init",
|
|
.desc = "Initialize cache in standby mode",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = 0,
|
|
.flags = CLI_OPTION_SUBCMD,
|
|
},
|
|
[standby_opt_subcmd_load] = {
|
|
.long_name = "load",
|
|
.desc = "Load cache in standby mode",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = 0,
|
|
.flags = CLI_OPTION_SUBCMD,
|
|
},
|
|
[standby_opt_subcmd_detach] = {
|
|
.long_name = "detach",
|
|
.desc = "Detach cache device in standby mode",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = 0,
|
|
.flags = CLI_OPTION_SUBCMD,
|
|
},
|
|
[standby_opt_subcmd_activate] = {
|
|
.long_name = "activate",
|
|
.desc = "Activate standby cache",
|
|
.args_count = 0,
|
|
.arg = NULL,
|
|
.priv = 0,
|
|
.flags = CLI_OPTION_SUBCMD,
|
|
},
|
|
|
|
[standby_opt_cache_id] = {
|
|
.short_name = 'i',
|
|
.long_name = "cache-id",
|
|
.desc = CACHE_ID_DESC,
|
|
.args_count = 1,
|
|
.arg = "ID",
|
|
.priv = (1 << standby_opt_subcmd_init)
|
|
| (1 << standby_opt_subcmd_detach)
|
|
| (1 << standby_opt_subcmd_activate)
|
|
| (1 << standby_opt_flag_required),
|
|
.flags = CLI_OPTION_RANGE_INT,
|
|
.max_value = 0,
|
|
.min_value = OCF_CACHE_ID_MAX,
|
|
},
|
|
[standby_opt_cache_line_size] = {
|
|
.short_name = 'x',
|
|
.long_name = "cache-line-size",
|
|
.desc = CACHE_LINE_SIZE_DESC,
|
|
.args_count = 1,
|
|
.arg = "NUMBER",
|
|
.priv = (1 << standby_opt_subcmd_init)
|
|
| (1 << standby_opt_flag_required),
|
|
.flags = CLI_OPTION_DEFAULT_INT,
|
|
.default_value = ocf_cache_line_size_default / KiB,
|
|
},
|
|
[standby_opt_cache_device] = {
|
|
.short_name = 'd',
|
|
.long_name = "cache-device",
|
|
.desc = CACHE_DEVICE_DESC,
|
|
.args_count = 1,
|
|
.arg = "DEVICE",
|
|
.priv = (1 << standby_opt_subcmd_init)
|
|
| (1 << standby_opt_subcmd_load)
|
|
| (1 << standby_opt_subcmd_activate)
|
|
| (1 << standby_opt_flag_required),
|
|
},
|
|
|
|
[standby_opt_force] = {
|
|
.short_name = 'f',
|
|
.long_name = "force",
|
|
.desc = "Force the initialization of cache instance",
|
|
.priv = (1 << standby_opt_subcmd_init),
|
|
},
|
|
|
|
{0}
|
|
};
|
|
|
|
struct {
|
|
int subcmd;
|
|
int cache_id;
|
|
int line_size;
|
|
const char* cache_device;
|
|
int force;
|
|
} static standby_params = {
|
|
.subcmd = standby_opt_subcmd_unknown,
|
|
.cache_id = OCF_CACHE_ID_INVALID,
|
|
.line_size = ocf_cache_line_size_none,
|
|
.cache_device = NULL,
|
|
.force = 0,
|
|
};
|
|
|
|
/* Parser of option for IO class command */
|
|
int standby_handle_option(char *opt, const char **arg)
|
|
{
|
|
/* First parameters which defines sub-command */
|
|
if (!strcmp(opt, "init")) {
|
|
if (standby_opt_subcmd_unknown != standby_params.subcmd)
|
|
goto err;
|
|
|
|
standby_params.subcmd = standby_opt_subcmd_init;
|
|
return 0;
|
|
} else if (!strcmp(opt, "load")) {
|
|
if (standby_opt_subcmd_unknown != standby_params.subcmd)
|
|
goto err;
|
|
|
|
standby_params.subcmd = standby_opt_subcmd_load;
|
|
return 0;
|
|
} else if (!strcmp(opt, "detach")) {
|
|
if (standby_opt_subcmd_unknown != standby_params.subcmd)
|
|
goto err;
|
|
|
|
standby_params.subcmd = standby_opt_subcmd_detach;
|
|
return 0;
|
|
} else if (!strcmp(opt, "activate")) {
|
|
if (standby_opt_subcmd_unknown != standby_params.subcmd)
|
|
goto err;
|
|
|
|
standby_params.subcmd = standby_opt_subcmd_activate;
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(opt, "cache-id")) {
|
|
if (validate_str_num(arg[0], "cache id", OCF_CACHE_ID_MIN,
|
|
OCF_CACHE_ID_MAX) == FAILURE)
|
|
return FAILURE;
|
|
|
|
standby_params_options[standby_opt_cache_id].priv |=
|
|
(1 << standby_opt_flag_set);
|
|
standby_params.cache_id = atoi(arg[0]);
|
|
} else if (!strcmp(opt, "cache-line-size")) {
|
|
if (validate_str_num_sbd(arg[0], "cache line size",
|
|
ocf_cache_line_size_min / KiB,
|
|
ocf_cache_line_size_max / KiB) == FAILURE)
|
|
return FAILURE;
|
|
|
|
standby_params_options[standby_opt_cache_line_size].priv |=
|
|
(1 << standby_opt_flag_set);
|
|
standby_params.line_size = atoi((const char*)arg[0]) * KiB;
|
|
} else if (!strcmp(opt, "cache-device")) {
|
|
if (validate_device_name(arg[0]) == FAILURE)
|
|
return FAILURE;
|
|
|
|
standby_params_options[standby_opt_cache_device].priv |=
|
|
(1 << standby_opt_flag_set);
|
|
standby_params.cache_device = arg[0];
|
|
} else if (!strcmp(opt, "force")) {
|
|
standby_params_options[standby_opt_force].priv |=
|
|
(1 << standby_opt_flag_set);
|
|
standby_params.force = 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
err:
|
|
cas_printf(LOG_ERR, "Can't use '%s' and '%s' options simultaneously\n",
|
|
opt, standby_params_options[standby_params.subcmd].long_name);
|
|
|
|
return FAILURE;
|
|
}
|
|
|
|
/* Check if all required command were set depending on command type */
|
|
int standby_is_missing() {
|
|
int result = 0;
|
|
int mask;
|
|
cli_option* iter = standby_params_options;
|
|
|
|
for (;iter->long_name; iter++) {
|
|
char option_name[MAX_STR_LEN];
|
|
if (!iter->priv) {
|
|
continue;
|
|
}
|
|
|
|
command_name_in_brackets(option_name, MAX_STR_LEN, iter->short_name, iter->long_name);
|
|
|
|
if (iter->priv & (1 << standby_opt_flag_set)) {
|
|
/* Option is set, check if this option is allowed */
|
|
mask = (1 << standby_params.subcmd);
|
|
if (0 == (mask & iter->priv)) {
|
|
cas_printf(LOG_ERR, "Option '%s' is not allowed\n", option_name);
|
|
result = -1;
|
|
}
|
|
|
|
} else {
|
|
/* Option is missing, check if it is required for this sub-command*/
|
|
mask = (1 << standby_params.subcmd) | (1 << standby_opt_flag_required);
|
|
if (mask == (iter->priv & mask)) {
|
|
cas_printf(LOG_ERR, "Option '%s' is missing\n", option_name);
|
|
result = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Command handler */
|
|
int standby_handle() {
|
|
/* Check if sub-command was specified */
|
|
if (standby_opt_subcmd_unknown == standby_params.subcmd) {
|
|
cmd_subcmd_print_invalid_subcmd(standby_params_options);
|
|
return FAILURE;
|
|
}
|
|
|
|
if (standby_params.subcmd == standby_opt_subcmd_load &&
|
|
(standby_params.force ||
|
|
standby_params.line_size != ocf_cache_line_size_none ||
|
|
standby_params.cache_id != OCF_CACHE_ID_INVALID)) {
|
|
cas_printf(LOG_ERR, "Use of 'load' with 'force', 'cache-id'"
|
|
" or 'cache-line-size' simultaneously is"
|
|
" forbidden.\n");
|
|
return FAILURE;
|
|
}
|
|
|
|
/* Check if all required options are set */
|
|
if (standby_is_missing()) {
|
|
return FAILURE;
|
|
}
|
|
|
|
if (standby_params.subcmd != standby_opt_subcmd_detach) {
|
|
if (validate_cache_path(standby_params.cache_device,
|
|
standby_params.force) == FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
}
|
|
|
|
switch (standby_params.subcmd) {
|
|
case standby_opt_subcmd_init:
|
|
return standby_init(standby_params.cache_id,
|
|
standby_params.line_size,
|
|
standby_params.cache_device,
|
|
standby_params.force);
|
|
case standby_opt_subcmd_load:
|
|
return standby_load(standby_params.cache_id,
|
|
standby_params.line_size,
|
|
standby_params.cache_device);
|
|
case standby_opt_subcmd_detach:
|
|
return standby_detach(standby_params.cache_id);
|
|
case standby_opt_subcmd_activate:
|
|
return standby_activate(standby_params.cache_id,
|
|
standby_params.cache_device);
|
|
}
|
|
|
|
return FAILURE;
|
|
}
|
|
|
|
void standby_help(app *app_values, cli_command *cmd)
|
|
{
|
|
cmd_subcmd_help(app_values, cmd, standby_opt_flag_required);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Zero metadata command
|
|
******************************************************************************/
|
|
|
|
struct {
|
|
const char *device;
|
|
bool force;
|
|
} static zero_params = {
|
|
.device = "",
|
|
.force = false
|
|
};
|
|
|
|
static cli_option zero_options[] = {
|
|
{'d', "device", "Path to device on which metadata would be cleared", 1, "DEVICE", CLI_OPTION_REQUIRED},
|
|
{'f', "force", "Ignore potential dirty data on cache device"},
|
|
{0}
|
|
};
|
|
|
|
/* Parser of option for zeroing metadata command */
|
|
int zero_handle_option(char *opt, const char **arg)
|
|
{
|
|
if (!strcmp(opt, "device")) {
|
|
if(validate_device_name(arg[0]) == FAILURE)
|
|
return FAILURE;
|
|
zero_params.device = arg[0];
|
|
} else if (!strcmp(opt, "force")){
|
|
zero_params.force = 1;
|
|
} else {
|
|
return FAILURE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int handle_zero()
|
|
{
|
|
int cache_device = 0;
|
|
|
|
cache_device = open(zero_params.device, O_RDONLY);
|
|
|
|
if (cache_device < 0) {
|
|
cas_printf(LOG_ERR, "Couldn't open cache device %s.\n", zero_params.device);
|
|
return FAILURE;
|
|
}
|
|
|
|
if (close(cache_device) < 0) {
|
|
cas_printf(LOG_ERR, "Couldn't close the cache device.\n");
|
|
return FAILURE;
|
|
}
|
|
|
|
return zero_md(zero_params.device, zero_params.force);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Command properties
|
|
******************************************************************************/
|
|
|
|
static cli_command cas_commands[] = {
|
|
{
|
|
.name = "start-cache",
|
|
.short_name = 'S',
|
|
.desc = "Start new cache instance or load using metadata",
|
|
.long_desc = NULL,
|
|
.options = start_options,
|
|
.command_handle_opts = start_cache_command_handle_option,
|
|
.handle = handle_start,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "attach-cache",
|
|
.desc = "Attach cache device",
|
|
.long_desc = NULL,
|
|
.options = attach_cache_options,
|
|
.command_handle_opts = start_cache_command_handle_option,
|
|
.handle = handle_cache_attach,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "detach-cache",
|
|
.desc = "Detach cache device",
|
|
.long_desc = NULL,
|
|
.options = detach_options,
|
|
.command_handle_opts = command_handle_option,
|
|
.handle = handle_cache_detach,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "stop-cache",
|
|
.short_name = 'T',
|
|
.desc = "Stop cache instance",
|
|
.long_desc = NULL,
|
|
.options = stop_options,
|
|
.command_handle_opts = command_handle_option,
|
|
.handle = handle_stop,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "set-param",
|
|
.short_name = 'X',
|
|
.desc = "Set various runtime parameters",
|
|
.long_desc = "Set various runtime parameters",
|
|
.namespace = &set_param_namespace,
|
|
.namespace_handle_opts = set_param_namespace_handle_option,
|
|
.handle = handle_set_param,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "get-param",
|
|
.short_name = 'G',
|
|
.desc = "Get various runtime parameters",
|
|
.long_desc = "Get various runtime parameters",
|
|
.namespace = &get_param_namespace,
|
|
.namespace_handle_opts = get_param_namespace_handle_option,
|
|
.handle = handle_get_param,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "set-cache-mode",
|
|
.short_name = 'Q',
|
|
.desc = "Set cache mode",
|
|
.long_desc = "Set cache mode",
|
|
.options = set_state_cache_mode_options,
|
|
.command_handle_opts = set_cache_mode_command_handle_option,
|
|
.handle = handle_set_cache_mode,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "add-core",
|
|
.short_name = 'A',
|
|
.desc = "Add core device to cache instance",
|
|
.long_desc = NULL,
|
|
.options = add_options,
|
|
.command_handle_opts = command_handle_option,
|
|
.handle = handle_add,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "remove-core",
|
|
.short_name = 'R',
|
|
.desc = "Remove active core device from cache instance",
|
|
.long_desc = NULL,
|
|
.options = remove_options,
|
|
.command_handle_opts = remove_core_command_handle_option,
|
|
.handle = handle_remove,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "remove-inactive",
|
|
.desc = "Remove inactive core device from cache instance",
|
|
.long_desc = NULL,
|
|
.options = remove_inactive_options,
|
|
.command_handle_opts = remove_core_command_handle_option,
|
|
.handle = handle_remove_inactive,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "remove-detached",
|
|
.desc = "Remove core device from core pool",
|
|
.long_desc = NULL,
|
|
.options = core_pool_remove_options,
|
|
.command_handle_opts = core_pool_remove_command_handle_option,
|
|
.handle = handle_core_pool_remove,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "list-caches",
|
|
.short_name = 'L',
|
|
.desc = "List all cache instances and core devices",
|
|
.long_desc = NULL,
|
|
.options = list_options,
|
|
.command_handle_opts = command_handle_option,
|
|
.handle = handle_list,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "stats",
|
|
.short_name = 'P',
|
|
.desc = "Print statistics for cache instance",
|
|
.long_desc = NULL,
|
|
.options = stats_options,
|
|
.command_handle_opts = stats_command_handle_option,
|
|
.handle = handle_stats,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "reset-counters",
|
|
.short_name = 'Z',
|
|
.desc = "Reset cache statistics for core device within cache instance",
|
|
.long_desc = NULL,
|
|
.options = reset_counters_options,
|
|
.command_handle_opts = command_handle_option,
|
|
.handle = handle_reset_counters,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "flush-cache",
|
|
.short_name = 'F',
|
|
.desc = "Flush all dirty data from the caching device to core devices",
|
|
.long_desc = NULL,
|
|
.options = flush_cache_options,
|
|
.command_handle_opts = command_handle_option,
|
|
.handle = handle_flush_cache,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL,
|
|
},
|
|
{
|
|
.name = "io-class",
|
|
.short_name = 'C',
|
|
.desc = "Manage IO classes",
|
|
.long_desc = NULL,
|
|
.options = io_class_params_options,
|
|
.command_handle_opts = io_class_handle_option,
|
|
.handle = io_class_handle,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = io_class_help,
|
|
},
|
|
{
|
|
.name = "version",
|
|
.short_name = 'V',
|
|
.desc = "Print " OCF_LOGO " version",
|
|
.long_desc = NULL,
|
|
.options = version_options,
|
|
.command_handle_opts = version_handle_option,
|
|
.handle = handle_version,
|
|
.flags = 0,
|
|
.help = NULL
|
|
},
|
|
{
|
|
.name = "help",
|
|
.short_name = 'H',
|
|
.desc = "Print help",
|
|
.long_desc = NULL,
|
|
.options = NULL,
|
|
.command_handle_opts = NULL,
|
|
.flags = 0,
|
|
.handle = handle_help,
|
|
.help = NULL
|
|
},
|
|
{
|
|
.name = "standby",
|
|
.desc = "Manage failover standby",
|
|
.long_desc = NULL,
|
|
.options = standby_params_options,
|
|
.command_handle_opts = standby_handle_option,
|
|
.handle = standby_handle,
|
|
.flags = (CLI_COMMAND_BLOCKED | CLI_SU_REQUIRED),
|
|
.help = standby_help,
|
|
},
|
|
{
|
|
.name = "zero-metadata",
|
|
.desc = "Clear metadata from caching device",
|
|
.long_desc = NULL,
|
|
.options = zero_options,
|
|
.command_handle_opts = zero_handle_option,
|
|
.handle = handle_zero,
|
|
.flags = CLI_SU_REQUIRED,
|
|
.help = NULL
|
|
},
|
|
{
|
|
.name = "script",
|
|
.options = script_params_options,
|
|
.command_handle_opts = script_handle_option,
|
|
.flags = (CLI_COMMAND_HIDDEN | CLI_SU_REQUIRED),
|
|
.handle = script_handle,
|
|
},
|
|
{0},
|
|
};
|
|
|
|
#define MAN_PAGE "casadm"
|
|
#define HELP_FOOTER ""
|
|
|
|
static int handle_help()
|
|
{
|
|
app app_values;
|
|
app_values.name = MAN_PAGE;
|
|
app_values.info = "<command> [option...]";
|
|
app_values.title = HELP_HEADER;
|
|
app_values.doc = HELP_FOOTER;
|
|
app_values.man = MAN_PAGE;
|
|
app_values.block = 0;
|
|
|
|
print_help(&app_values, cas_commands);
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, const char *argv[])
|
|
{
|
|
int blocked = 0;
|
|
app app_values;
|
|
|
|
set_default_sig_handler();
|
|
set_safe_lib_constraint_handler();
|
|
|
|
app_values.name = argv[0];
|
|
app_values.info = "<command> [option...]";
|
|
app_values.title = HELP_HEADER;
|
|
app_values.doc = HELP_FOOTER;
|
|
app_values.man = MAN_PAGE;
|
|
app_values.block = blocked;
|
|
|
|
return args_parse(&app_values, cas_commands, argc, argv);
|
|
}
|