Merge pull request #919 from robertbaldyga/remove-upgrade
Remove upgrade-in-flight feature
This commit is contained in:
commit
d87b2c6be7
@ -56,7 +56,6 @@ OBJS += statistics_view.o
|
||||
OBJS += statistics_view_raw_csv.o
|
||||
OBJS += csvparse.o
|
||||
OBJS += extended_err_msg.o
|
||||
OBJS += upgrade.o
|
||||
OBJS += safeclib/memmove_s.o
|
||||
OBJS += safeclib/memcpy_s.o
|
||||
OBJS += safeclib/memset_s.o
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "cas_lib_utils.h"
|
||||
#include "safeclib/safe_str_lib.h"
|
||||
#include <cas_ioctl_codes.h>
|
||||
#include "upgrade.h"
|
||||
#include "statistics_view.h"
|
||||
|
||||
#define HELP_HEADER OCF_PREFIX_LONG
|
||||
@ -1447,8 +1446,7 @@ enum {
|
||||
|
||||
script_cmd_min_id = 0,
|
||||
|
||||
script_cmd_upgrade = script_cmd_min_id,
|
||||
script_cmd_check_cache_device,
|
||||
script_cmd_check_cache_device = script_cmd_min_id,
|
||||
|
||||
script_cmd_add_core,
|
||||
script_cmd_remove_core,
|
||||
@ -1478,14 +1476,6 @@ enum {
|
||||
* script_opt_* .priv fields contains id of commands, where they can be used
|
||||
*/
|
||||
static cli_option script_params_options[] = {
|
||||
[script_cmd_upgrade] = {
|
||||
.short_name = 0,
|
||||
.long_name = "upgrade-in-flight",
|
||||
.args_count = 0,
|
||||
.arg = NULL,
|
||||
.priv = 0,
|
||||
.flags = CLI_COMMAND_HIDDEN,
|
||||
},
|
||||
[script_cmd_check_cache_device] = {
|
||||
.short_name = 0,
|
||||
.long_name = "check-cache-device",
|
||||
@ -1696,8 +1686,6 @@ int script_handle() {
|
||||
switch (command_args_values.script_subcmd) {
|
||||
case script_cmd_check_cache_device:
|
||||
return check_cache_device(command_args_values.cache_device);
|
||||
case script_cmd_upgrade:
|
||||
return upgrade_start();
|
||||
case script_cmd_add_core:
|
||||
return add_core(
|
||||
command_args_values.cache_id,
|
||||
|
@ -197,10 +197,6 @@ struct {
|
||||
"Could not create exported object because file in /dev "
|
||||
"directory exists"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_IN_UPGRADE,
|
||||
"Operation not allowed. CAS is in upgrade state"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_UNALIGNED,
|
||||
"Cache device logical sector size is greater than core device "
|
||||
@ -208,9 +204,6 @@ struct {
|
||||
"on current cache device \nor try other device with the same "
|
||||
"logical sector size as core device."
|
||||
},
|
||||
{
|
||||
KCAS_ERR_NO_STORED_CONF,
|
||||
"Internal kernel module error" },
|
||||
{
|
||||
KCAS_ERR_ROLLBACK,
|
||||
"Cannot restore previous configuration"
|
||||
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2021 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "cas_lib.h"
|
||||
#include "cas_lib_utils.h"
|
||||
#include <cas_ioctl_codes.h>
|
||||
|
||||
extern cas_printf_t cas_printf;
|
||||
|
||||
int upgrade_start()
|
||||
{
|
||||
int fd;
|
||||
struct kcas_upgrade cmd_info;
|
||||
|
||||
if ((fd = open_ctrl_device()) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (run_ioctl_interruptible_retry(fd, KCAS_IOCTL_UPGRADE, &cmd_info,
|
||||
"Starting upgrade", 0, OCF_CORE_ID_INVALID) < 0) {
|
||||
close(fd);
|
||||
if (OCF_ERR_FLUSHING_INTERRUPTED == cmd_info.ext_err_code) {
|
||||
return INTERRUPTED;
|
||||
} else {
|
||||
cas_printf(LOG_ERR, "Error starting upgrade\n");
|
||||
print_err(cmd_info.ext_err_code);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return SUCCESS;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2021 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef _UPGRADE_H
|
||||
#define _UPGRADE_H
|
||||
|
||||
int upgrade_start();
|
||||
|
||||
#endif
|
@ -12,7 +12,6 @@
|
||||
#include <cas_ioctl_codes.h>
|
||||
|
||||
#include "linux_kernel_version.h"
|
||||
#include "layer_upgrade.h"
|
||||
#include "control.h"
|
||||
#include "layer_cache_management.h"
|
||||
#include "service_ui_ioctl.h"
|
||||
@ -21,6 +20,7 @@
|
||||
#include "classifier.h"
|
||||
#include "context.h"
|
||||
#include <linux/kallsyms.h>
|
||||
#include "../cas_disk/cas_disk.h"
|
||||
|
||||
#define CAS_KERN_EMERG KERN_EMERG OCF_PREFIX_SHORT
|
||||
#define CAS_KERN_ALERT KERN_ALERT OCF_PREFIX_SHORT
|
||||
@ -76,7 +76,6 @@ struct casdsk_functions_mapper {
|
||||
struct module *owner, struct casdsk_exp_obj_ops *ops);
|
||||
void(*casdsk_exp_obj_free)(struct casdsk_disk *dsk);
|
||||
struct request_queue *(*casdsk_disk_get_queue)(struct casdsk_disk *dsk);
|
||||
void (*casdsk_store_config)(size_t n_blobs, struct casdsk_props_conf *blobs);
|
||||
struct block_device *(*casdsk_disk_get_blkdev)(struct casdsk_disk *dsk);
|
||||
struct request_queue *(*casdsk_exp_obj_get_queue)(struct casdsk_disk *dsk);
|
||||
uint32_t (*casdsk_get_version)(void);
|
||||
@ -84,7 +83,6 @@ struct casdsk_functions_mapper {
|
||||
struct casdsk_disk *(*casdsk_disk_claim)(const char *path, void *private);
|
||||
int (*casdsk_exp_obj_unlock)(struct casdsk_disk *dsk);
|
||||
int (*casdsk_disk_set_pt)(struct casdsk_disk *dsk);
|
||||
size_t (*casdsk_get_stored_config)(struct casdsk_props_conf **blobs);
|
||||
struct gendisk *(*casdsk_disk_get_gendisk)(struct casdsk_disk *dsk);
|
||||
int (*casdsk_disk_attach) (struct casdsk_disk *dsk, struct module *owner,
|
||||
struct casdsk_exp_obj_ops *ops);
|
||||
@ -92,7 +90,6 @@ struct casdsk_functions_mapper {
|
||||
int (*casdsk_exp_obj_activate)(struct casdsk_disk *dsk);
|
||||
bool (*casdsk_exp_obj_activated)(struct casdsk_disk *ds);
|
||||
int (*casdsk_exp_obj_lock)(struct casdsk_disk *dsk);
|
||||
void (*casdsk_free_stored_config)(void);
|
||||
struct casdsk_disk *(*casdsk_disk_open)(const char *path, void *private);
|
||||
int (*casdsk_disk_clear_pt)(struct casdsk_disk *dsk);
|
||||
struct gendisk *(*casdsk_exp_obj_get_gendisk)(struct casdsk_disk *dsk);
|
||||
|
@ -1191,11 +1191,6 @@ int cache_mngt_prepare_core_cfg(struct ocf_mngt_core_config *cfg,
|
||||
cfg->uuid.size = strnlen(cmd_info->core_path_name, MAX_STR_LEN) + 1;
|
||||
cfg->try_add = cmd_info->try_add;
|
||||
|
||||
if (cas_upgrade_is_in_upgrade()) {
|
||||
cfg->volume_type = BLOCK_DEVICE_VOLUME;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cas_bdev_exist(cfg->uuid.data))
|
||||
return -OCF_ERR_INVAL_VOLUME_TYPE;
|
||||
|
||||
@ -2512,20 +2507,12 @@ int cache_mngt_exit_instance(const char *cache_name, size_t name_len, int flush)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!cas_upgrade_is_in_upgrade()) {
|
||||
/* If we are not in upgrade - destroy cache devices */
|
||||
status = block_dev_destroy_all_exported_objects(cache);
|
||||
if (status != 0) {
|
||||
printk(KERN_WARNING
|
||||
"Failed to remove all cached devices\n");
|
||||
goto stop_thread;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We are being switched to upgrade in flight mode -
|
||||
* wait for finishing pending core requests
|
||||
*/
|
||||
cache_mngt_wait_for_rq_finish(cache);
|
||||
/* Destroy cache devices */
|
||||
status = block_dev_destroy_all_exported_objects(cache);
|
||||
if (status != 0) {
|
||||
printk(KERN_WARNING
|
||||
"Failed to remove all cached devices\n");
|
||||
goto stop_thread;
|
||||
}
|
||||
|
||||
/* Flush cache again. This time we don't allow interruption. */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2021 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __LAYER_UPGRADE_H
|
||||
|
||||
#define __LAYER_UPGRADE_H
|
||||
|
||||
#include "cas_cache/cas_cache.h"
|
||||
|
||||
extern bool in_upgrade;
|
||||
|
||||
/**
|
||||
* @brief Check that CAS is in upgarde state
|
||||
* @return true if is or false if isn't
|
||||
*/
|
||||
bool cas_upgrade_is_in_upgrade(void);
|
||||
|
||||
/**
|
||||
* @brief Check that caches configuration is stored at casdsk
|
||||
* @return 0 if exist
|
||||
*/
|
||||
int cas_upgrade_get_configuration(void);
|
||||
|
||||
/**
|
||||
* @brief Start upgrade in flight procedure, dump configuration,
|
||||
* switch caches to PT and close caches
|
||||
* @return result
|
||||
*/
|
||||
int cas_upgrade(void);
|
||||
|
||||
/**
|
||||
* @brief Finish upgrade in new CAS module - restore all caches
|
||||
* @return result of restoring
|
||||
*/
|
||||
int cas_upgrade_finish(void);
|
||||
|
||||
/**
|
||||
* @brief Try to parse configuration stored in casdisk
|
||||
* @return result of verification
|
||||
*/
|
||||
int cas_upgrade_verify(void);
|
||||
|
||||
#endif /* __LAYER_UPGRADE_H */
|
||||
|
@ -21,10 +21,6 @@ MODULE_PARM_DESC(writeback_queue_unblock_size,
|
||||
"Cache writeback queue size (60000) at which queue "
|
||||
"is unblocked when blocked");
|
||||
|
||||
u32 dry_run;
|
||||
module_param(dry_run, uint, (S_IRUSR | S_IRGRP));
|
||||
MODULE_PARM_DESC(dry_run, "Perform dry run on module load");
|
||||
|
||||
u32 use_io_scheduler = 1;
|
||||
module_param(use_io_scheduler, uint, (S_IRUSR | S_IRGRP));
|
||||
MODULE_PARM_DESC(use_io_scheduler,
|
||||
@ -47,7 +43,6 @@ MODULE_PARM_DESC(seq_cut_off_mb,
|
||||
"Sequential cut off threshold in MiB. 0 - disable");
|
||||
|
||||
/* globals */
|
||||
bool in_upgrade;
|
||||
ocf_ctx_t cas_ctx;
|
||||
struct casdsk_functions_mapper casdisk_functions;
|
||||
|
||||
@ -94,7 +89,6 @@ int static cas_casdisk_lookup_funtions(void)
|
||||
cas_lookup_symbol(casdsk_exp_obj_create);
|
||||
cas_lookup_symbol(casdsk_exp_obj_free);
|
||||
cas_lookup_symbol(casdsk_disk_get_queue);
|
||||
cas_lookup_symbol(casdsk_store_config);
|
||||
cas_lookup_symbol(casdsk_disk_get_blkdev);
|
||||
cas_lookup_symbol(casdsk_exp_obj_get_queue);
|
||||
cas_lookup_symbol(casdsk_get_version);
|
||||
@ -102,14 +96,12 @@ int static cas_casdisk_lookup_funtions(void)
|
||||
cas_lookup_symbol(casdsk_disk_claim);
|
||||
cas_lookup_symbol(casdsk_exp_obj_unlock);
|
||||
cas_lookup_symbol(casdsk_disk_set_pt);
|
||||
cas_lookup_symbol(casdsk_get_stored_config);
|
||||
cas_lookup_symbol(casdsk_disk_get_gendisk);
|
||||
cas_lookup_symbol(casdsk_disk_attach);
|
||||
cas_lookup_symbol(casdsk_disk_set_attached);
|
||||
cas_lookup_symbol(casdsk_exp_obj_activate);
|
||||
cas_lookup_symbol(casdsk_exp_obj_activated);
|
||||
cas_lookup_symbol(casdsk_exp_obj_lock);
|
||||
cas_lookup_symbol(casdsk_free_stored_config);
|
||||
cas_lookup_symbol(casdsk_disk_open);
|
||||
cas_lookup_symbol(casdsk_disk_clear_pt);
|
||||
cas_lookup_symbol(casdsk_exp_obj_get_gendisk);
|
||||
@ -171,31 +163,6 @@ static int __init cas_init_module(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = cas_upgrade_get_configuration();
|
||||
if (-KCAS_ERR_NO_STORED_CONF == result) {
|
||||
printk(KERN_INFO OCF_PREFIX_SHORT
|
||||
"Not found configuration for upgrade. "
|
||||
"Standard module initialization.\n");
|
||||
} else {
|
||||
if (!dry_run) {
|
||||
result = cas_upgrade_finish();
|
||||
if (result) {
|
||||
printk(KERN_ERR OCF_PREFIX_SHORT
|
||||
"Error during finish upgrade, "
|
||||
"result: %d\n", result);
|
||||
goto error_cas_ctx_init;
|
||||
}
|
||||
} else {
|
||||
result = cas_upgrade_verify();
|
||||
if (result) {
|
||||
printk(KERN_ERR OCF_PREFIX_SHORT
|
||||
"Error during upgrade "
|
||||
"verification\n");
|
||||
goto error_cas_ctx_init;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = cas_ctrl_device_init();
|
||||
if (result) {
|
||||
printk(KERN_ERR OCF_PREFIX_SHORT
|
||||
|
@ -46,15 +46,6 @@ long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd,
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (cas_upgrade_is_in_upgrade() &&
|
||||
cmd != KCAS_IOCTL_CACHE_INFO &&
|
||||
cmd != KCAS_IOCTL_LIST_CACHE &&
|
||||
cmd != KCAS_IOCTL_GET_CACHE_COUNT &&
|
||||
cmd != KCAS_IOCTL_CORE_INFO &&
|
||||
cmd != KCAS_IOCTL_PARTITION_INFO) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case KCAS_IOCTL_START_CACHE: {
|
||||
struct kcas_start_cache *cmd_info;
|
||||
@ -315,16 +306,6 @@ long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd,
|
||||
RETURN_CMD_RESULT(cmd_info, arg, retval > 0 ? 0 : retval);
|
||||
}
|
||||
|
||||
case KCAS_IOCTL_UPGRADE: {
|
||||
struct kcas_upgrade *cmd_info;
|
||||
|
||||
GET_CMD_INFO(cmd_info, arg);
|
||||
|
||||
retval = cas_upgrade();
|
||||
|
||||
RETURN_CMD_RESULT(cmd_info, arg, retval);
|
||||
}
|
||||
|
||||
case KCAS_IOCTL_GET_CORE_POOL_COUNT: {
|
||||
struct kcas_core_pool_count *cmd_info;
|
||||
|
||||
|
@ -8,6 +8,5 @@
|
||||
#define __CAS_UTILS_H__
|
||||
|
||||
#include "utils_nvme.h"
|
||||
#include "utils_properties.h"
|
||||
|
||||
#endif /* __CAS_UTILS_H__ */
|
||||
|
@ -56,9 +56,7 @@ struct {
|
||||
{ KCAS_ERR_INV_IOCTL, EINVAL },
|
||||
{ KCAS_ERR_DEV_PENDING, EBUSY },
|
||||
{ KCAS_ERR_FILE_EXISTS, EEXIST },
|
||||
{ KCAS_ERR_IN_UPGRADE, EFAULT },
|
||||
{ KCAS_ERR_UNALIGNED, EINVAL },
|
||||
{ KCAS_ERR_NO_STORED_CONF, EINTR },
|
||||
{ KCAS_ERR_ROLLBACK, EFAULT },
|
||||
{ KCAS_ERR_NVME_BAD_FORMAT, EINVAL },
|
||||
{ KCAS_ERR_CONTAINS_PART, EINVAL },
|
||||
|
@ -1,769 +0,0 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2021 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include "cas_cache.h"
|
||||
|
||||
#define INTERNAL_CALL 0
|
||||
#define EXTERNAL_CALL 1
|
||||
|
||||
#define CAS_PROPERTIES_VERSION 101
|
||||
|
||||
#define VERSION_STR ".version"
|
||||
|
||||
/*
|
||||
* Difference between constant and non constant entry is store in LSB
|
||||
* e.g.:
|
||||
* cas_property_string in binary 0000 1010
|
||||
* cas_property_string_const in binary 0000 1011
|
||||
*/
|
||||
|
||||
#define CAS_PROP_UNCONST(type) (type & ~CAS_PROPERTIES_CONST)
|
||||
#define CAS_PROP_CHECK_CONST(type) (type & CAS_PROPERTIES_CONST)
|
||||
|
||||
enum cas_property_type {
|
||||
cas_property_string = 10,
|
||||
cas_property_string_const =
|
||||
(cas_property_string | CAS_PROPERTIES_CONST),
|
||||
cas_property_sint = 16,
|
||||
cas_property_sint_const = (cas_property_sint | CAS_PROPERTIES_CONST),
|
||||
cas_property_uint = 74,
|
||||
cas_property_uint_const = (cas_property_uint | CAS_PROPERTIES_CONST),
|
||||
};
|
||||
|
||||
struct cas_properties {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct _cas_property {
|
||||
uint8_t type;
|
||||
char *key;
|
||||
struct list_head item;
|
||||
union {
|
||||
void *value;
|
||||
uint64_t value_uint;
|
||||
int64_t value_sint;
|
||||
};
|
||||
};
|
||||
|
||||
struct cas_properties *cas_properties_create(void)
|
||||
{
|
||||
struct cas_properties *props;
|
||||
int result;
|
||||
|
||||
props = kzalloc(sizeof(*props), GFP_KERNEL);
|
||||
if (!props)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
INIT_LIST_HEAD(&props->list);
|
||||
|
||||
result = cas_properties_add_uint(props, VERSION_STR,
|
||||
CAS_PROPERTIES_VERSION, CAS_PROPERTIES_CONST);
|
||||
if (result) {
|
||||
kfree(props);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
result = cas_properties_add_uint(props, ".size", 0,
|
||||
CAS_PROPERTIES_NON_CONST);
|
||||
if (result) {
|
||||
kfree(props);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
void cas_properties_destroy(struct cas_properties *props)
|
||||
{
|
||||
struct list_head *curr, *tmp;
|
||||
struct _cas_property *entry;
|
||||
|
||||
list_for_each_safe(curr, tmp, &props->list) {
|
||||
entry = list_entry(curr, struct _cas_property, item);
|
||||
list_del(curr);
|
||||
if (cas_property_string == CAS_PROP_UNCONST(entry->type))
|
||||
kfree(entry->value);
|
||||
kfree(entry->key);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
kfree(props);
|
||||
}
|
||||
|
||||
static uint64_t _cas_prop_get_size(struct cas_properties *props)
|
||||
{
|
||||
struct list_head *curr;
|
||||
struct _cas_property *entry;
|
||||
uint64_t size_all = 0;
|
||||
|
||||
list_for_each(curr, &props->list) {
|
||||
entry = list_entry(curr, struct _cas_property, item);
|
||||
|
||||
size_all += cas_prop_strnlen(entry->key, MAX_STRING_SIZE) + 1;
|
||||
size_all += sizeof(entry->type);
|
||||
|
||||
switch (CAS_PROP_UNCONST(entry->type)) {
|
||||
case cas_property_string:
|
||||
size_all += cas_prop_strnlen(entry->value,
|
||||
MAX_STRING_SIZE) + 1;
|
||||
break;
|
||||
case cas_property_sint:
|
||||
size_all += sizeof(entry->value_sint);
|
||||
break;
|
||||
case cas_property_uint:
|
||||
size_all += sizeof(entry->value_uint);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return size_all;
|
||||
}
|
||||
|
||||
static int _cas_prop_serialize_string(char *buffer, const uint64_t size,
|
||||
uint64_t *offset, char *value)
|
||||
{
|
||||
uint64_t str_size = 0;
|
||||
|
||||
str_size = cas_prop_strnlen(value, MAX_STRING_SIZE) + 1;
|
||||
|
||||
if ((*offset + str_size) > size)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buffer + *offset, value, str_size);
|
||||
*offset += str_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cas_prop_parse_string(const char *buffer, const uint64_t size,
|
||||
uint64_t *offset, char **str)
|
||||
{
|
||||
char *tmp_str = NULL;
|
||||
uint64_t str_size = 0;
|
||||
|
||||
if (*offset >= size)
|
||||
return -ENOMEM;
|
||||
|
||||
str_size = cas_prop_strnlen(&buffer[*offset], size - *offset ) + 1;
|
||||
|
||||
if (str_size > size - *offset) {
|
||||
/* no null terminator at the end of buffer */
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tmp_str = kstrdup(&buffer[*offset], GFP_KERNEL);
|
||||
if (!tmp_str)
|
||||
return -ENOMEM;
|
||||
|
||||
*offset += str_size;
|
||||
*str = tmp_str;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cas_prop_serialize_int(char *buffer, const uint64_t size,
|
||||
uint64_t *offset, uint64_t number)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
/*
|
||||
* To prevent issue connected with byte order we
|
||||
* serialize integer byte by byte.
|
||||
*/
|
||||
for (i = 0; i < sizeof(number); i++) {
|
||||
char byte = number & 0xFF;
|
||||
|
||||
if (*offset < size)
|
||||
buffer[*offset] = byte;
|
||||
else
|
||||
return -ENOMEM;
|
||||
|
||||
(*offset)++;
|
||||
number = number >> 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cas_prop_serialize_uint(char *buffer, const uint64_t size,
|
||||
uint64_t *offset, uint64_t number)
|
||||
{
|
||||
return _cas_prop_serialize_int(buffer, size, offset, number);
|
||||
}
|
||||
|
||||
|
||||
static int _cas_prop_serialize_sint(char *buffer, const uint64_t size,
|
||||
uint64_t *offset, int64_t number)
|
||||
{
|
||||
return _cas_prop_serialize_int(buffer, size, offset, (uint64_t) number);
|
||||
|
||||
}
|
||||
|
||||
static int _cas_prop_parse_int(const char *buffer,
|
||||
const uint64_t size, uint64_t *offset, uint64_t *number)
|
||||
{
|
||||
int32_t i;
|
||||
uint64_t byte;
|
||||
|
||||
*number = 0;
|
||||
|
||||
/*
|
||||
* To prevent issue connected with byte order we
|
||||
* parse integer byte by byte.
|
||||
*/
|
||||
for (i = 0; i < sizeof(*number); i++) {
|
||||
if (*offset >= size)
|
||||
return -ENOMEM;
|
||||
|
||||
byte = buffer[*offset] & 0xFF;
|
||||
byte = byte << (i * 8);
|
||||
|
||||
*number |= byte;
|
||||
|
||||
(*offset)++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cas_prop_parse_uint(const char *buffer,
|
||||
const uint64_t size, uint64_t *offset, uint64_t *number)
|
||||
{
|
||||
return _cas_prop_parse_int(buffer, size, offset, number);
|
||||
}
|
||||
|
||||
static int _cas_prop_parse_sint(const char *buffer,
|
||||
const uint64_t size, uint64_t *offset, int64_t *number)
|
||||
{
|
||||
return _cas_prop_parse_int(buffer, size, offset, (uint64_t *) number);
|
||||
}
|
||||
|
||||
static int _cas_prop_serialize(struct _cas_property *entry, void *buffer,
|
||||
const uint64_t size, uint64_t *offset)
|
||||
{
|
||||
uint64_t item_size = 0;
|
||||
void *item;
|
||||
int result = 0;
|
||||
|
||||
if (*offset > size)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Each entry is represented in buffer in order as below
|
||||
* (e.g. in case we have entry with integer) :
|
||||
* <----- entry ----->
|
||||
* <- key -><-type-><- integer ->
|
||||
* <- X bytes -><1 byte><- 8 byte ->
|
||||
* | | | |
|
||||
*/
|
||||
|
||||
/*
|
||||
* First step - serialize key
|
||||
*/
|
||||
|
||||
item_size = cas_prop_strnlen(entry->key, MAX_STRING_SIZE) + 1;
|
||||
item = entry->key;
|
||||
|
||||
if ((*offset + item_size) > size)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buffer + *offset, item, item_size);
|
||||
*offset += item_size;
|
||||
|
||||
/*
|
||||
* Second step - serialize type
|
||||
*/
|
||||
|
||||
item_size = sizeof(entry->type);
|
||||
item = &entry->type;
|
||||
|
||||
if ((*offset + item_size) > size)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buffer + *offset, item, item_size);
|
||||
*offset += item_size;
|
||||
|
||||
/*
|
||||
* Third step - serialize value
|
||||
*/
|
||||
|
||||
switch (CAS_PROP_UNCONST(entry->type)) {
|
||||
case cas_property_string:
|
||||
/* Serialize string */
|
||||
result = _cas_prop_serialize_string(buffer, size, offset,
|
||||
entry->value);
|
||||
break;
|
||||
case cas_property_sint:
|
||||
/* Serialize signed integer */
|
||||
result = _cas_prop_serialize_sint(buffer, size, offset,
|
||||
entry->value_uint);
|
||||
break;
|
||||
case cas_property_uint:
|
||||
/* Serialize unsigned integer */
|
||||
result = _cas_prop_serialize_uint(buffer, size, offset,
|
||||
entry->value_uint);
|
||||
break;
|
||||
default:
|
||||
result = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int cas_properties_serialize(struct cas_properties *props,
|
||||
struct casdsk_props_conf *caches_serialized_conf)
|
||||
{
|
||||
int result = 0;
|
||||
uint64_t offset = 0, size;
|
||||
uint16_t crc = 0;
|
||||
void *buffer;
|
||||
struct list_head *curr;
|
||||
struct _cas_property *entry;
|
||||
|
||||
size = _cas_prop_get_size(props);
|
||||
if (size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
buffer = vzalloc(size);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Update first entry on list - size of buffer
|
||||
*/
|
||||
result = cas_properties_add_uint(props, ".size", size,
|
||||
CAS_PROPERTIES_CONST);
|
||||
if (result)
|
||||
goto error_after_buffer_allocation;
|
||||
|
||||
/*
|
||||
* Serialize each entry, one by one
|
||||
*/
|
||||
list_for_each(curr, &props->list) {
|
||||
entry = list_entry(curr, struct _cas_property, item);
|
||||
result = _cas_prop_serialize(entry, buffer, size, &offset);
|
||||
if (result)
|
||||
goto error_after_buffer_allocation;
|
||||
}
|
||||
|
||||
crc = crc16(0, buffer, size);
|
||||
|
||||
caches_serialized_conf->buffer = buffer;
|
||||
caches_serialized_conf->size = size;
|
||||
caches_serialized_conf->crc = crc;
|
||||
return result;
|
||||
|
||||
error_after_buffer_allocation:
|
||||
vfree(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
void cas_properties_print(struct cas_properties *props)
|
||||
{
|
||||
struct list_head *curr;
|
||||
struct _cas_property *entry;
|
||||
char *abc;
|
||||
|
||||
/*
|
||||
* Serialize each entry, one by one
|
||||
*/
|
||||
list_for_each(curr, &props->list) {
|
||||
entry = list_entry(curr, struct _cas_property, item);
|
||||
printk(KERN_DEBUG "[Upgrade] Key: %s", entry->key);
|
||||
switch (CAS_PROP_UNCONST(entry->type)) {
|
||||
case cas_property_string:
|
||||
printk(", string, ");
|
||||
abc = (char *)entry->value;
|
||||
printk("Value: %s ", abc);
|
||||
break;
|
||||
case cas_property_sint:
|
||||
break;
|
||||
case cas_property_uint:
|
||||
printk(", uint, ");
|
||||
printk("Value: %llu ", entry->value_uint);
|
||||
break;
|
||||
default:
|
||||
printk("Invalid type!");
|
||||
break;
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int _cas_prop_parse_version(const char *buffer, uint64_t *offset,
|
||||
uint64_t *version, int trigger)
|
||||
{
|
||||
int result = 0;
|
||||
char *key = NULL;
|
||||
uint8_t type;
|
||||
|
||||
result = _cas_prop_parse_string(buffer, strlen(VERSION_STR) + 1,
|
||||
offset, &key);
|
||||
if (result)
|
||||
goto error_during_parse_key;
|
||||
|
||||
if (strcmp(VERSION_STR, key)) {
|
||||
result = -EINVAL;
|
||||
goto error_after_parse_key;
|
||||
}
|
||||
|
||||
type = buffer[*offset];
|
||||
if (cas_property_uint_const != type) {
|
||||
result = -EINVAL;
|
||||
goto error_after_parse_key;
|
||||
}
|
||||
*offset += sizeof(type);
|
||||
|
||||
result = _cas_prop_parse_uint(buffer,
|
||||
strlen(VERSION_STR) + 1 + sizeof(type) +
|
||||
sizeof(*version), offset, version);
|
||||
if (result)
|
||||
goto error_after_parse_key;
|
||||
|
||||
/*
|
||||
* In case that is external call
|
||||
* we don't need check version.
|
||||
*/
|
||||
if (trigger == INTERNAL_CALL && *version != CAS_PROPERTIES_VERSION) {
|
||||
printk(KERN_ERR "Version of interface using to parse is "
|
||||
"different than version used to serialize\n");
|
||||
result = -EPERM;
|
||||
}
|
||||
|
||||
error_after_parse_key:
|
||||
kfree(key);
|
||||
error_during_parse_key:
|
||||
return result;
|
||||
}
|
||||
|
||||
int cas_properites_parse_version(struct casdsk_props_conf *caches_serialized_conf,
|
||||
uint64_t *version)
|
||||
{
|
||||
uint64_t offset = 0;
|
||||
char *buffer = NULL;
|
||||
|
||||
buffer = (char *) caches_serialized_conf->buffer;
|
||||
if (!buffer)
|
||||
return -EINVAL;
|
||||
|
||||
return _cas_prop_parse_version(buffer, &offset, version, EXTERNAL_CALL);
|
||||
}
|
||||
|
||||
struct cas_properties *
|
||||
cas_properites_parse(struct casdsk_props_conf *caches_serialized_conf)
|
||||
{
|
||||
struct cas_properties *props;
|
||||
char *key = NULL, *value = NULL, *buffer = NULL;
|
||||
int result;
|
||||
uint8_t type;
|
||||
uint64_t uint_value, size = 0, offset = 0, version = 0;
|
||||
uint16_t crc;
|
||||
int64_t sint_value;
|
||||
bool constant = false;
|
||||
|
||||
props = cas_properties_create();
|
||||
if (IS_ERR(props))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (!caches_serialized_conf) {
|
||||
result = -EINVAL;
|
||||
goto error_after_props_allocation;
|
||||
}
|
||||
|
||||
buffer = (char *) caches_serialized_conf->buffer;
|
||||
if (!buffer) {
|
||||
result = -EINVAL;
|
||||
goto error_after_props_allocation;
|
||||
}
|
||||
|
||||
size = caches_serialized_conf->size;
|
||||
crc = crc16(0, buffer, size);
|
||||
if (crc != caches_serialized_conf->crc) {
|
||||
printk(KERN_ERR "Cache configuration corrupted");
|
||||
result = -EINVAL;
|
||||
goto error_after_props_allocation;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse first entry on list - version of interface used to
|
||||
* serialization
|
||||
*/
|
||||
result = _cas_prop_parse_version(buffer, &offset, &version,
|
||||
INTERNAL_CALL);
|
||||
if (result)
|
||||
goto error_after_props_allocation;
|
||||
|
||||
while (offset < size) {
|
||||
/*
|
||||
* Parse key of entry
|
||||
*/
|
||||
result = _cas_prop_parse_string(buffer, size, &offset, &key);
|
||||
if (result)
|
||||
goto error_after_props_allocation;
|
||||
|
||||
/*
|
||||
* Parse type of entry
|
||||
*/
|
||||
if (offset + sizeof(type) > size) {
|
||||
kfree(key);
|
||||
goto error_after_props_allocation;
|
||||
}
|
||||
|
||||
memcpy(&type, buffer + offset, sizeof(type));
|
||||
offset += sizeof(type);
|
||||
|
||||
constant = CAS_PROP_CHECK_CONST(type);
|
||||
type = CAS_PROP_UNCONST(type);
|
||||
|
||||
switch (type) {
|
||||
case cas_property_string:
|
||||
/* Parse string */
|
||||
result = _cas_prop_parse_string(buffer, size, &offset,
|
||||
&value);
|
||||
if (result)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Add new entry with string to CAS properties instance
|
||||
*/
|
||||
result |= cas_properties_add_string(props, key, value,
|
||||
constant);
|
||||
kfree(value);
|
||||
break;
|
||||
case cas_property_sint:
|
||||
/* Parse signed integer */
|
||||
result = _cas_prop_parse_sint(buffer, size, &offset,
|
||||
&sint_value);
|
||||
/* Add new entry with signed integer to CAS properties
|
||||
* instance
|
||||
*/
|
||||
result |= cas_properties_add_sint(props, key,
|
||||
sint_value, constant);
|
||||
break;
|
||||
case cas_property_uint:
|
||||
/* Parse unsigned integer */
|
||||
result = _cas_prop_parse_uint(buffer, size, &offset,
|
||||
&uint_value);
|
||||
/* Add new entry with unsigned integer to CAS properties
|
||||
* instance
|
||||
*/
|
||||
result |= cas_properties_add_uint(props, key,
|
||||
uint_value, constant);
|
||||
break;
|
||||
default:
|
||||
result = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case when we added new entry,
|
||||
* we not need hold key value longer.
|
||||
*/
|
||||
kfree(key);
|
||||
|
||||
if (result)
|
||||
goto error_after_props_allocation;
|
||||
}
|
||||
|
||||
return props;
|
||||
|
||||
error_after_props_allocation:
|
||||
cas_properties_destroy(props);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
static struct _cas_property *_cas_prop_find(const struct cas_properties *props,
|
||||
const char *key)
|
||||
{
|
||||
struct list_head *curr;
|
||||
struct _cas_property *entry;
|
||||
|
||||
list_for_each(curr, &props->list) {
|
||||
entry = list_entry(curr, struct _cas_property, item);
|
||||
if (strncmp(key, entry->key, MAX_STRING_SIZE) == 0)
|
||||
return entry;
|
||||
}
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
static struct _cas_property *_cas_prop_alloc_entry_key(const char *key)
|
||||
{
|
||||
struct _cas_property *entry;
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
entry->key = kstrdup(key, GFP_KERNEL);
|
||||
if (!entry->key) {
|
||||
kfree(entry);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&entry->item);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* ADD
|
||||
*/
|
||||
|
||||
int cas_properties_add_uint(struct cas_properties *props, const char *key,
|
||||
uint64_t value, bool constant)
|
||||
{
|
||||
struct _cas_property *entry;
|
||||
|
||||
/*
|
||||
* Looks for entry with same key,
|
||||
* if it is exist - update, if not - create new
|
||||
*/
|
||||
entry = _cas_prop_find(props, key);
|
||||
if (IS_ERR(entry)) {
|
||||
entry = _cas_prop_alloc_entry_key(key);
|
||||
if (IS_ERR(entry))
|
||||
return PTR_ERR(entry);
|
||||
list_add_tail(&entry->item, &props->list);
|
||||
} else if (cas_property_uint != entry->type) {
|
||||
/*
|
||||
* We can update only non constant entry,
|
||||
* so we need compare type only with non constant type.
|
||||
*/
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entry->type = constant ? cas_property_uint_const : cas_property_uint;
|
||||
entry->value_uint = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cas_properties_add_sint(struct cas_properties *props, const char *key,
|
||||
int64_t value, bool constant)
|
||||
{
|
||||
struct _cas_property *entry;
|
||||
|
||||
/*
|
||||
* Looks for entry with same key,
|
||||
* if it is exist - update, if not - create new
|
||||
*/
|
||||
entry = _cas_prop_find(props, key);
|
||||
if (IS_ERR(entry)) {
|
||||
entry = _cas_prop_alloc_entry_key(key);
|
||||
if (IS_ERR(entry))
|
||||
return PTR_ERR(entry);
|
||||
list_add_tail(&entry->item, &props->list);
|
||||
} else if (cas_property_sint != entry->type) {
|
||||
/*
|
||||
* We can update only non constant entry,
|
||||
* so we need compare type only with non constant type.
|
||||
*/
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entry->type = constant ? cas_property_sint_const : cas_property_sint;
|
||||
entry->value_sint = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cas_properties_add_string(struct cas_properties *props, const char *key,
|
||||
const char *value, bool constant)
|
||||
{
|
||||
struct _cas_property *entry;
|
||||
char *tmp_value = NULL;
|
||||
|
||||
tmp_value = kstrdup(value, GFP_KERNEL);
|
||||
if (!tmp_value)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Looks for entry with same key,
|
||||
* if it is exist - update, if not - create new
|
||||
*/
|
||||
entry = _cas_prop_find(props, key);
|
||||
if (IS_ERR(entry)) {
|
||||
entry = _cas_prop_alloc_entry_key(key);
|
||||
if (IS_ERR(entry)) {
|
||||
kfree(tmp_value);
|
||||
return PTR_ERR(entry);
|
||||
}
|
||||
list_add_tail(&entry->item, &props->list);
|
||||
} else {
|
||||
if (cas_property_string != entry->type) {
|
||||
/*
|
||||
* We can update only non constant entry,
|
||||
* so we need compare type only with non constant type.
|
||||
*/
|
||||
kfree(tmp_value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kfree(entry->value);
|
||||
}
|
||||
|
||||
entry->type = constant ? cas_property_string_const :
|
||||
cas_property_string;
|
||||
entry->value = tmp_value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* GET
|
||||
*/
|
||||
|
||||
int cas_properties_get_uint(struct cas_properties *props, const char *key,
|
||||
uint64_t *value)
|
||||
{
|
||||
struct _cas_property *entry;
|
||||
|
||||
entry = _cas_prop_find(props, key);
|
||||
if ((IS_ERR(entry) == 0) && (cas_property_uint ==
|
||||
CAS_PROP_UNCONST(entry->type))) {
|
||||
*value = entry->value_uint;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return IS_ERR(entry) ? PTR_ERR(entry) : -EINVAL;
|
||||
}
|
||||
|
||||
int cas_properties_get_sint(struct cas_properties *props, const char *key,
|
||||
int64_t *value)
|
||||
{
|
||||
struct _cas_property *entry;
|
||||
|
||||
entry = _cas_prop_find(props, key);
|
||||
if ((IS_ERR(entry) == 0) && (cas_property_sint ==
|
||||
CAS_PROP_UNCONST(entry->type))) {
|
||||
*value = entry->value_sint;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return IS_ERR(entry) ? PTR_ERR(entry) : -EINVAL;
|
||||
}
|
||||
|
||||
int cas_properties_get_string(struct cas_properties *props, const char *key,
|
||||
char *value, uint32_t size)
|
||||
{
|
||||
struct _cas_property *entry;
|
||||
|
||||
entry = _cas_prop_find(props, key);
|
||||
if ((IS_ERR(entry) == 0) && (cas_property_string ==
|
||||
CAS_PROP_UNCONST(entry->type))) {
|
||||
/* Check if size of destination memory is enough */
|
||||
if (size < cas_prop_strnlen(entry->value, MAX_STRING_SIZE) + 1)
|
||||
return -ENOMEM;
|
||||
|
||||
cas_prop_strncpy(value, size, entry->value,
|
||||
cas_prop_strnlen(entry->value, MAX_STRING_SIZE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return IS_ERR(entry) ? PTR_ERR(entry) : -EINVAL;
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2021 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef UTILS_PROPERTIES_H_
|
||||
#define UTILS_PROPERTIES_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define cas_prop_strncpy(dest, dest_size, src, src_size) \
|
||||
strlcpy(dest, src, dest_size)
|
||||
#define cas_prop_strnlen(string, size) strnlen(string, size)
|
||||
#else
|
||||
#define cas_prop_strncpy(dest, dest_size, src, src_size) \
|
||||
strncpy(dest, src, src_size)
|
||||
#define cas_prop_strnlen(string, size) strlen(string)
|
||||
#endif
|
||||
|
||||
#include "../../cas_disk/cas_disk.h"
|
||||
|
||||
#define MAX_STRING_SIZE 4095
|
||||
|
||||
#define CAS_PROPERTIES_NON_CONST false
|
||||
#define CAS_PROPERTIES_CONST true
|
||||
|
||||
/**
|
||||
* @file utils_properties.h
|
||||
* @brief CAS cache interface for collect and serialization CAS properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Handler for instance of CAS properties
|
||||
*/
|
||||
struct cas_properties;
|
||||
|
||||
/**
|
||||
* @brief Initialize instance of CAS properties
|
||||
*
|
||||
* @return Handler to instance of interface
|
||||
*/
|
||||
struct cas_properties *cas_properties_create(void);
|
||||
|
||||
/**
|
||||
* @brief De-initialize instance of CAS properties
|
||||
*
|
||||
* @param props Handler to instance to de-initialize
|
||||
*/
|
||||
void cas_properties_destroy(struct cas_properties *props);
|
||||
|
||||
/**
|
||||
* @brief Serialize given CAS properties instance to continuous buffer
|
||||
*
|
||||
* @param props instance of CAS properties
|
||||
* @param idisk conf instance of CAS properties
|
||||
* @return result of serialize CAS properties
|
||||
*/
|
||||
int cas_properties_serialize(struct cas_properties *props,
|
||||
struct casdsk_props_conf *caches_serialized_conf);
|
||||
|
||||
/**
|
||||
* @brief Parse of first entry given continuous buffer to get version of
|
||||
* interface which been used to serialize
|
||||
*
|
||||
* @param buffer pointer to continuous buffer with serialized CAS properties
|
||||
* @param version pointer to memory where we will put version
|
||||
* @return result of getting version, 0 success
|
||||
*/
|
||||
int cas_properites_parse_version(struct casdsk_props_conf *caches_serialized_conf,
|
||||
uint64_t *version);
|
||||
|
||||
/**
|
||||
* @brief Parse of given continuous buffer to CAS properties instance
|
||||
*
|
||||
* @param buffer pointer to continuous buffer with serialized CAS properties
|
||||
* @return handler to CAS properties instance
|
||||
*/
|
||||
struct cas_properties *
|
||||
cas_properites_parse(struct casdsk_props_conf *caches_serialized_conf);
|
||||
|
||||
/**
|
||||
* @brief Add unsigned integer to CAS properties instance
|
||||
*
|
||||
* @param props CAS properties instance to add variable
|
||||
* @param key key paired with variable
|
||||
* @param value value of variable
|
||||
* @param private if true value cannot be updated
|
||||
* @return result of adding 0 success
|
||||
*/
|
||||
int cas_properties_add_uint(struct cas_properties *props, const char *key,
|
||||
uint64_t value, bool private);
|
||||
|
||||
/**
|
||||
* @brief Add signed integer to CAS properties instance
|
||||
*
|
||||
* @param props CAS properties instance to add variable
|
||||
* @param key key paired with variable
|
||||
* @param value value of variable
|
||||
* @param private if true value cannot be updated
|
||||
* @return result of adding 0 success
|
||||
*/
|
||||
int cas_properties_add_sint(struct cas_properties *props, const char *key,
|
||||
int64_t value, bool private);
|
||||
|
||||
/**
|
||||
* @brief Add string to CAS properties instance
|
||||
*
|
||||
* @param props CAS properties instance to add variable
|
||||
* @param key key paired with variable
|
||||
* @param value value of variable
|
||||
* @param private if true value cannot be updated
|
||||
* @return result of adding 0 success
|
||||
*/
|
||||
int cas_properties_add_string(struct cas_properties *props, const char *key,
|
||||
const char *value, bool private);
|
||||
|
||||
/**
|
||||
* @brief Get unsigned integer to CAS properties instance
|
||||
*
|
||||
* @param props CAS properties instance to add variable
|
||||
* @param key key paired with variable
|
||||
* @param value pointer to memory where we will put value
|
||||
* @return result of getting 0 success
|
||||
*/
|
||||
int cas_properties_get_uint(struct cas_properties *props, const char *key,
|
||||
uint64_t *value);
|
||||
|
||||
/**
|
||||
* @brief Get signed integer to CAS properties instance
|
||||
*
|
||||
* @param props CAS properties instance to add variable
|
||||
* @param key key paired with variable
|
||||
* @param value pointer to memory where we will put value
|
||||
* @return result of getting 0 success
|
||||
*/
|
||||
int cas_properties_get_sint(struct cas_properties *props, const char *key,
|
||||
int64_t *value);
|
||||
|
||||
/**
|
||||
* @brief Get string integer to CAS properties instance
|
||||
*
|
||||
* @param props CAS properties instance to add variable
|
||||
* @param key key paired with variable
|
||||
* @param value pointer to memory where we will put value
|
||||
* @param size size of destination memory
|
||||
* @return result of getting 0 success, 1 error, 2 not enough space
|
||||
* in destination
|
||||
*/
|
||||
int cas_properties_get_string(struct cas_properties *props, const char *key,
|
||||
char *value, uint32_t size);
|
||||
|
||||
|
||||
void cas_properties_print(struct cas_properties *props);
|
||||
#endif /* UTILS_PROPERTIES_H_ */
|
@ -33,13 +33,7 @@ int block_dev_open_object(ocf_volume_t vol, void *volume_params)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(true == cas_upgrade_is_in_upgrade())) {
|
||||
dsk = casdisk_functions.casdsk_disk_claim(uuid->data, NULL);
|
||||
casdisk_functions.casdsk_disk_set_attached(dsk);
|
||||
} else {
|
||||
dsk = casdisk_functions.casdsk_disk_open(uuid->data, NULL);
|
||||
}
|
||||
|
||||
dsk = casdisk_functions.casdsk_disk_open(uuid->data, NULL);
|
||||
if (IS_ERR_OR_NULL(dsk)) {
|
||||
int error = PTR_ERR(dsk) ?: -EINVAL;
|
||||
|
||||
@ -62,12 +56,7 @@ void block_dev_close_object(ocf_volume_t vol)
|
||||
if (bdobj->opened_by_bdev)
|
||||
return;
|
||||
|
||||
if (likely(!cas_upgrade_is_in_upgrade())) {
|
||||
casdisk_functions.casdsk_disk_close(bdobj->dsk);
|
||||
} else {
|
||||
casdisk_functions.casdsk_disk_set_pt(bdobj->dsk);
|
||||
casdisk_functions.casdsk_disk_detach(bdobj->dsk);
|
||||
}
|
||||
casdisk_functions.casdsk_disk_close(bdobj->dsk);
|
||||
}
|
||||
|
||||
unsigned int block_dev_get_max_io_size(ocf_volume_t vol)
|
||||
|
@ -458,16 +458,10 @@ int block_dev_activate_exported_object(ocf_core_t core)
|
||||
ocf_cache_t cache = ocf_core_get_cache(core);
|
||||
struct bd_object *bvol = bd_object(obj);
|
||||
|
||||
if (!cas_upgrade_is_in_upgrade()) {
|
||||
ret = casdisk_functions.casdsk_exp_obj_activate(bvol->dsk);
|
||||
ret = casdisk_functions.casdsk_exp_obj_activate(bvol->dsk);
|
||||
if (ret) {
|
||||
if (-EEXIST == ret)
|
||||
ret = KCAS_ERR_FILE_EXISTS;
|
||||
} else {
|
||||
ret = casdisk_functions.casdsk_disk_attach(bvol->dsk, THIS_MODULE,
|
||||
&_blockdev_exp_obj_ops);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
printk(KERN_ERR "Cannot activate exported object, %s.%s. "
|
||||
"Error code %d\n", ocf_cache_get_name(cache),
|
||||
ocf_core_get_name(core), ret);
|
||||
@ -506,11 +500,6 @@ int block_dev_create_exported_object(ocf_core_t core)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (cas_upgrade_is_in_upgrade()) {
|
||||
bvol->expobj_valid = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bvol->expobj_wq = alloc_workqueue("expobj_wq%s-%s",
|
||||
WQ_MEM_RECLAIM | WQ_HIGHPRI, 0,
|
||||
get_cache_id_string(cache),
|
||||
|
@ -31,40 +31,12 @@ struct casdsk_exp_obj_ops {
|
||||
struct bio *bio, void *private);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stored configuration buffer description
|
||||
*/
|
||||
struct casdsk_props_conf {
|
||||
void *buffer;
|
||||
size_t size;
|
||||
uint16_t crc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get version of cas_disk interface
|
||||
* @return cas_disk interface version
|
||||
*/
|
||||
uint32_t casdsk_get_version(void);
|
||||
|
||||
/**
|
||||
* @brief Store configuration buffers in cas_disk
|
||||
* @param n_blobs Number of configuration buffers
|
||||
* @param blobs Array of configuration buffers structures
|
||||
*/
|
||||
void casdsk_store_config(size_t n_blobs, struct casdsk_props_conf *blobs);
|
||||
|
||||
/**
|
||||
* @brief Get previously stored configuration buffers
|
||||
* @param blobs Where to store pointer to configuration buffers array
|
||||
* @return Number of stored configuration buffers
|
||||
*/
|
||||
size_t casdsk_get_stored_config(struct casdsk_props_conf **blobs);
|
||||
|
||||
/**
|
||||
* @brief Free resources related to stored configuration buffers
|
||||
*/
|
||||
void casdsk_free_stored_config(void);
|
||||
|
||||
/**
|
||||
* @brief Open block device
|
||||
* @param path Path to block device
|
||||
|
@ -12,11 +12,6 @@
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/blkdev.h>
|
||||
|
||||
struct casdsk_stored_config {
|
||||
size_t n_blobs;
|
||||
struct casdsk_props_conf *blobs;
|
||||
};
|
||||
|
||||
struct casdsk_module {
|
||||
struct mutex lock;
|
||||
|
||||
@ -31,8 +26,6 @@ struct casdsk_module {
|
||||
struct kmem_cache *pending_rqs_cache;
|
||||
|
||||
struct kobject kobj;
|
||||
|
||||
struct casdsk_stored_config config;
|
||||
};
|
||||
|
||||
extern struct casdsk_module *casdsk_module;
|
||||
|
@ -20,9 +20,6 @@ MODULE_VERSION(CAS_VERSION);
|
||||
static int iface_version = CASDSK_IFACE_VERSION;
|
||||
module_param(iface_version, int, (S_IRUSR | S_IRGRP));
|
||||
|
||||
static int upgrade_in_progress = 0;
|
||||
module_param(upgrade_in_progress, int, (S_IRUSR | S_IRGRP));
|
||||
|
||||
struct casdsk_module *casdsk_module;
|
||||
|
||||
uint32_t casdsk_get_version(void)
|
||||
@ -31,46 +28,6 @@ uint32_t casdsk_get_version(void)
|
||||
}
|
||||
EXPORT_SYMBOL(casdsk_get_version);
|
||||
|
||||
static void _casdsk_module_free_config(struct casdsk_module *mod)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (mod->config.blobs) {
|
||||
for (i = 0; i < mod->config.n_blobs; i++)
|
||||
vfree(mod->config.blobs[i].buffer);
|
||||
kfree(mod->config.blobs);
|
||||
|
||||
mod->config.blobs = NULL;
|
||||
mod->config.n_blobs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void casdsk_store_config(size_t n_blobs, struct casdsk_props_conf *blobs)
|
||||
{
|
||||
upgrade_in_progress = 1;
|
||||
_casdsk_module_free_config(casdsk_module);
|
||||
casdsk_module->config.blobs = blobs;
|
||||
casdsk_module->config.n_blobs = n_blobs;
|
||||
}
|
||||
EXPORT_SYMBOL(casdsk_store_config);
|
||||
|
||||
size_t casdsk_get_stored_config(struct casdsk_props_conf **blobs)
|
||||
{
|
||||
BUG_ON(!blobs);
|
||||
|
||||
*blobs = casdsk_module->config.blobs;
|
||||
return casdsk_module->config.n_blobs;
|
||||
}
|
||||
EXPORT_SYMBOL(casdsk_get_stored_config);
|
||||
|
||||
void casdsk_free_stored_config(void)
|
||||
{
|
||||
CASDSK_DEBUG_TRACE();
|
||||
_casdsk_module_free_config(casdsk_module);
|
||||
upgrade_in_progress = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(casdsk_free_stored_config);
|
||||
|
||||
static void _casdsk_module_release(struct kobject *kobj)
|
||||
{
|
||||
struct casdsk_module *mod;
|
||||
@ -82,8 +39,6 @@ static void _casdsk_module_release(struct kobject *kobj)
|
||||
mod = container_of(kobj, struct casdsk_module, kobj);
|
||||
BUG_ON(!mod);
|
||||
|
||||
_casdsk_module_free_config(mod);
|
||||
|
||||
kfree(mod);
|
||||
}
|
||||
|
||||
|
@ -290,10 +290,6 @@ struct kcas_capabilites {
|
||||
int ext_err_code;
|
||||
};
|
||||
|
||||
struct kcas_upgrade {
|
||||
int ext_err_code;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format NVMe namespace.
|
||||
*/
|
||||
@ -404,7 +400,7 @@ struct kcas_get_cache_param {
|
||||
* 16 * KCAS_IOCTL_GET_CACHE_COUNT * OK *
|
||||
* 17 * KCAS_IOCTL_LIST_CACHE * OK *
|
||||
* 18 * KCAS_IOCTL_GET_CAPABILITIES * DEPRECATED *
|
||||
* 19 * KCAS_IOCTL_UPGRADE * OK *
|
||||
* 19 * KCAS_IOCTL_UPGRADE * DEPRACATED *
|
||||
* 20 * KCAS_IOCTL_NVME_FORMAT * DEPRECATED *
|
||||
* 21 * KCAS_IOCTL_START_CACHE * OK *
|
||||
* 22 * KCAS_IOCTL_INSERT_CORE * OK *
|
||||
@ -465,9 +461,6 @@ struct kcas_get_cache_param {
|
||||
/** Provides capabilites of installed open cas module */
|
||||
#define KCAS_IOCTL_GET_CAPABILITIES _IOWR(KCAS_IOCTL_MAGIC, 18, struct kcas_capabilites)
|
||||
|
||||
/** Start upgrade in flight procedure */
|
||||
#define KCAS_IOCTL_UPGRADE _IOR(KCAS_IOCTL_MAGIC, 19, struct kcas_upgrade)
|
||||
|
||||
/** Format NVMe namespace to support selected metadata mode */
|
||||
#define KCAS_IOCTL_NVME_FORMAT _IOWR(KCAS_IOCTL_MAGIC, 20, struct kcas_nvme_format)
|
||||
|
||||
@ -551,16 +544,10 @@ enum kcas_error {
|
||||
*/
|
||||
KCAS_ERR_FILE_EXISTS,
|
||||
|
||||
/** CAS is under upgrade */
|
||||
KCAS_ERR_IN_UPGRADE,
|
||||
|
||||
/** Cache device sector size is greater than core device %s sector size
|
||||
*/
|
||||
KCAS_ERR_UNALIGNED,
|
||||
|
||||
/** No caches configuration for upgrade in flight */
|
||||
KCAS_ERR_NO_STORED_CONF,
|
||||
|
||||
/** Cannot roll-back previous configuration */
|
||||
KCAS_ERR_ROLLBACK,
|
||||
|
||||
|
@ -17,9 +17,6 @@ class CasVersion:
|
||||
self.type = release_type
|
||||
self.base = f"{self.main}.{self.major}.{self.minor}"
|
||||
|
||||
def can_be_upgraded(self):
|
||||
return self.main >= 20
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.main}.{self.major}.{self.minor}.{self.pr}" \
|
||||
f"{'.' + self.type if self.type is not None else ''}"
|
||||
@ -46,7 +43,3 @@ def get_available_cas_versions():
|
||||
versions = [CasVersion.from_git_tag(tag) for tag in release_tags]
|
||||
|
||||
return versions
|
||||
|
||||
|
||||
def get_upgradable_cas_versions():
|
||||
return [v for v in get_available_cas_versions() if v.can_be_upgraded()]
|
||||
|
@ -153,11 +153,6 @@ class casadm:
|
||||
'--file', ioclass_file]
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
@classmethod
|
||||
def start_upgrade(cls):
|
||||
cmd = [cls.casadm_path, '--script', '--upgrade-in-flight']
|
||||
|
||||
return cls.run_cmd(cmd)
|
||||
|
||||
# Configuration file parser
|
||||
|
||||
|
426
utils/upgrade
426
utils/upgrade
@ -1,426 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# Copyright(c) 2019-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
#
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import argparse
|
||||
import subprocess
|
||||
import os
|
||||
from pathlib import Path
|
||||
from shutil import copy
|
||||
|
||||
import opencas
|
||||
from upgrade_utils import (
|
||||
yn_prompt,
|
||||
Failure,
|
||||
Success,
|
||||
Warn,
|
||||
Abort,
|
||||
StateMachine,
|
||||
UpgradeState,
|
||||
insert_module,
|
||||
remove_module,
|
||||
get_device_sysfs_path,
|
||||
get_device_schedulers,
|
||||
set_device_scheduler,
|
||||
drop_os_caches,
|
||||
)
|
||||
|
||||
LOG_FILE = "/var/log/opencas-upgrade/upgrade.log"
|
||||
COMPILATION_LOG = "/var/log/opencas-upgrade/build.log"
|
||||
INIT_CONFIG_FILE_TMP_PATH = "/tmp/opencas_upgrade_backup.conf"
|
||||
|
||||
CAS_CACHE_KEY = "CAS Cache Kernel Module"
|
||||
CAS_DISK_KEY = "CAS Disk Kernel Module"
|
||||
CAS_CLI_KEY = "CAS CLI Utility"
|
||||
|
||||
CAS_DISK_MIN_VER = 20
|
||||
|
||||
OCL_BUILD_ROOT = f"{os.path.dirname(__file__)}/.."
|
||||
|
||||
|
||||
class InitUpgrade(UpgradeState):
|
||||
log = "Performing initial checks"
|
||||
will_prompt = True
|
||||
|
||||
class NotInstalled(Warn):
|
||||
pass
|
||||
|
||||
def do_work(self):
|
||||
if self.state_machine.params["force"]:
|
||||
self.will_prompt = False
|
||||
elif yn_prompt("Proceed with upgrade procedure?") == "n":
|
||||
return Abort("User aborted")
|
||||
|
||||
try:
|
||||
version = opencas.get_cas_version()
|
||||
except FileNotFoundError:
|
||||
return self.NotInstalled(f"Couldn't detect current CAS version")
|
||||
except Exception as e:
|
||||
return Failure(f"Failed to get current version of CAS {e}")
|
||||
|
||||
# Although there shouldn't be any problem with upgrade from CAS 19.9 to newer, this feature
|
||||
# is not full validated so it is disabled by default.
|
||||
if (int(version[CAS_DISK_KEY].split('.')[0]) < CAS_DISK_MIN_VER):
|
||||
return Failure(f"Minimal cas_disk version required to perform upgrade is 20.01!")
|
||||
|
||||
if version[CAS_CLI_KEY] != version[CAS_CACHE_KEY]:
|
||||
return Failure("Mismatch between CLI and cas_cache version")
|
||||
|
||||
active_devices = opencas.get_devices_state()
|
||||
|
||||
if any([device["status"] != "Running" for device in active_devices["caches"].values()]):
|
||||
return Failure("Incomplete configuration. Run casadm -L to review CAS state!")
|
||||
|
||||
if len(active_devices["core_pool"]) != 0:
|
||||
return Failure("Incomplete configuration. Run casadm -L to review CAS state!")
|
||||
|
||||
if os.path.isfile(opencas.cas_config.default_location):
|
||||
try:
|
||||
copy(opencas.cas_config.default_location, INIT_CONFIG_FILE_TMP_PATH)
|
||||
except IOError:
|
||||
return Failure("Could not save init config file backup")
|
||||
else:
|
||||
logging.info("Init config file not found")
|
||||
|
||||
return Success()
|
||||
|
||||
|
||||
class BuildCas(UpgradeState):
|
||||
log = "Compiling Open CAS"
|
||||
|
||||
def do_work(self):
|
||||
with open(COMPILATION_LOG, "w") as build_log:
|
||||
logging.info("Running ./configure for CAS")
|
||||
p = subprocess.run(
|
||||
["./configure"], cwd=OCL_BUILD_ROOT, stdout=build_log, stderr=build_log
|
||||
)
|
||||
if p.returncode:
|
||||
return Failure(f"Configuration of Open CAS failed. Build log: {COMPILATION_LOG}")
|
||||
|
||||
logging.info("Compiling CAS")
|
||||
p = subprocess.run(
|
||||
["make", "-j"], cwd=OCL_BUILD_ROOT, stdout=build_log, stderr=build_log
|
||||
)
|
||||
if p.returncode:
|
||||
return Failure(f"Compilation of Open CAS failed. Build log: {COMPILATION_LOG}")
|
||||
|
||||
return Success()
|
||||
|
||||
|
||||
class RestoreInitConfig(UpgradeState):
|
||||
log = "Restore original init config file"
|
||||
|
||||
def do_work(self):
|
||||
if not os.path.isfile(INIT_CONFIG_FILE_TMP_PATH):
|
||||
logging.warning("Init config backup file not found")
|
||||
return Success()
|
||||
|
||||
try:
|
||||
copy(INIT_CONFIG_FILE_TMP_PATH, opencas.cas_config.default_location)
|
||||
except IOError:
|
||||
logging.error(f"Failed to restore original init config file from "
|
||||
f"{INIT_CONFIG_FILE_TMP_PATH}. Configuration has to be restored manually.")
|
||||
return Failure()
|
||||
|
||||
os.remove(INIT_CONFIG_FILE_TMP_PATH)
|
||||
return Success()
|
||||
|
||||
|
||||
class InstallCas(UpgradeState):
|
||||
log = "Installing new Open CAS files"
|
||||
|
||||
def do_work(self):
|
||||
with open(COMPILATION_LOG, "a") as install_log:
|
||||
p = subprocess.run(
|
||||
["make", "install"], cwd=OCL_BUILD_ROOT, stdout=install_log, stderr=install_log
|
||||
)
|
||||
|
||||
if p.returncode:
|
||||
return Failure(
|
||||
f"Installation of Open CAS failed. Installation log: {COMPILATION_LOG}"
|
||||
)
|
||||
|
||||
return Success()
|
||||
|
||||
|
||||
class InsertModule(UpgradeState):
|
||||
module_path = f"{OCL_BUILD_ROOT}/modules/cas_cache/cas_cache.ko"
|
||||
options = {"installed": False}
|
||||
|
||||
def do_work(self):
|
||||
try:
|
||||
insert_module(self.module_path, **self.options)
|
||||
except Exception as e:
|
||||
return Failure(f"Couldn't load module {self.module_path}. Reason: {e}")
|
||||
|
||||
return Success()
|
||||
|
||||
|
||||
class InsertNewModule(InsertModule):
|
||||
log = "Try to insert new caching module"
|
||||
|
||||
|
||||
class DryRun(InsertModule):
|
||||
log = "Perform dry run to check upgrade data integrity"
|
||||
options = {"installed": False, "dry_run": 1}
|
||||
|
||||
def do_work(self):
|
||||
result = super().do_work()
|
||||
if not isinstance(result, Success):
|
||||
return Failure("Dry run failed")
|
||||
|
||||
try:
|
||||
logging.info(
|
||||
"Insert with dry_run set succeeded. Removing module to attempt final insertion."
|
||||
)
|
||||
remove_module("cas_cache")
|
||||
except Exception as e:
|
||||
return Failure(f"Could not unload module. Reason: {e}")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class InsertInstalledModule(InsertModule):
|
||||
log = "Restore old cas_cache module"
|
||||
module_path = "cas_cache"
|
||||
options = {"installed": True}
|
||||
|
||||
|
||||
class PrepareForUpgrade(UpgradeState):
|
||||
log = "Preparing Open CAS for upgrade"
|
||||
|
||||
def do_work(self):
|
||||
try:
|
||||
logging.info("Switching CAS to upgrade mode")
|
||||
opencas.casadm.start_upgrade()
|
||||
except opencas.casadm.CasadmError as e:
|
||||
return Failure(e)
|
||||
|
||||
return Success()
|
||||
|
||||
|
||||
class RemoveModule(UpgradeState):
|
||||
log = "Removing cas_cache module"
|
||||
|
||||
def do_work(self):
|
||||
try:
|
||||
logging.info("Removing cas_cache module")
|
||||
remove_module("cas_cache")
|
||||
except Exception as e:
|
||||
return Failure(f"Failed to remove cas_cache module. Reason: {e}")
|
||||
|
||||
return Success()
|
||||
|
||||
|
||||
class SetSchedulersToNoop(UpgradeState):
|
||||
log = "Setting core devices schedulers to noop"
|
||||
|
||||
def do_work(self):
|
||||
unique_core_sysfs_devices = {
|
||||
get_device_sysfs_path(core["device"])
|
||||
for core in opencas.get_devices_state()["cores"].values()
|
||||
}
|
||||
|
||||
self.state_machine.schedulers = {}
|
||||
for core_sysfs_path in unique_core_sysfs_devices:
|
||||
current, available = get_device_schedulers(core_sysfs_path)
|
||||
self.state_machine.schedulers[core_sysfs_path] = current
|
||||
|
||||
if current in ["noop", "none"]:
|
||||
logging.info(f"Core {core_sysfs_path} already uses {current} scheduler. Skipping.")
|
||||
elif "noop" in available:
|
||||
logging.info(f"Switching scheduler for {core_sysfs_path}: {current} => noop")
|
||||
set_device_scheduler(core_sysfs_path, "noop")
|
||||
elif "none" in available:
|
||||
logging.info(f"Switching scheduler for {core_sysfs_path}: {current} => none")
|
||||
set_device_scheduler(core_sysfs_path, "none")
|
||||
else:
|
||||
logging.info(f"No appropriate scheduler available for {core_sysfs_path}. Skipping.")
|
||||
|
||||
return Success()
|
||||
|
||||
|
||||
class RestoreCoreSchedulers(UpgradeState):
|
||||
log = "Restoring core devices schedulers"
|
||||
|
||||
def do_work(self):
|
||||
for core_sysfs_path, scheduler in self.state_machine.schedulers.items():
|
||||
current = get_device_schedulers(core_sysfs_path)[0]
|
||||
if scheduler in ["noop", "none"]:
|
||||
logging.info(
|
||||
f"Device {core_sysfs_path} already uses {scheduler} scheduler. Skipping."
|
||||
)
|
||||
else:
|
||||
logging.info(f"Switching scheduler for {core_sysfs_path}: {current} => {scheduler}")
|
||||
set_device_scheduler(core_sysfs_path, scheduler)
|
||||
|
||||
return Success()
|
||||
|
||||
|
||||
class DropCaches(UpgradeState):
|
||||
log = "Drop OS caches to ensure memory availability"
|
||||
|
||||
def do_work(self):
|
||||
logging.info("Dropping slab and page caches using procfs")
|
||||
drop_os_caches()
|
||||
|
||||
return Success()
|
||||
|
||||
|
||||
class InstallStateMachine(StateMachine):
|
||||
transition_map = {
|
||||
BuildCas: {Success: InstallCas},
|
||||
InstallCas: {"default": None},
|
||||
"default": None,
|
||||
}
|
||||
|
||||
|
||||
class RegularInstall(UpgradeState):
|
||||
log = "Installing Open CAS"
|
||||
will_prompt = True
|
||||
|
||||
def do_work(self):
|
||||
if (
|
||||
yn_prompt("Previous CAS installation not detected. Perform regular installation?")
|
||||
== "n"
|
||||
):
|
||||
return Abort("User aborted")
|
||||
|
||||
sm = InstallStateMachine(BuildCas)
|
||||
result = sm.run()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class UpgradeStateMachine(StateMachine):
|
||||
"""
|
||||
This class implements whole CAS in-flight upgrade procedure.
|
||||
|
||||
+-------------+ not +---------------+
|
||||
|InitUpgrade +----------->+RegularInstall |
|
||||
+------+------+ installed | |
|
||||
| | +---------+ |
|
||||
v | |BuildCas | |
|
||||
+------+------+ fail | +---+-----+ |
|
||||
|BuildCas +------+ | | |
|
||||
+------+------+ | | v |
|
||||
| | | +---+-----+ |
|
||||
v | | |Install | |
|
||||
+------+------+ fail | | +---------+ |
|
||||
|SetToNoop +------+ | |
|
||||
+------+------+ | +----------+----+
|
||||
| | |
|
||||
v +----------------+
|
||||
+------+------+ fail |
|
||||
|PrepareForUpg+-------------------+ |
|
||||
+------+------+ | |
|
||||
| | |
|
||||
v | |
|
||||
+------+------+ fail | |
|
||||
|RemoveModule +-------------------+ |
|
||||
+------+------+ | |
|
||||
| | |
|
||||
v | |
|
||||
+------+------+ fail | |
|
||||
|DropCaches +-------------------+ |
|
||||
+------+------+ | |
|
||||
| | |
|
||||
v | |
|
||||
+------+------+ fail | |
|
||||
|DryRun +--------+ | |
|
||||
+------+------+ | | |
|
||||
| | | |
|
||||
v | | |
|
||||
+------+------+ fail | | |
|
||||
|InsertNew +--------+ | |
|
||||
+------+------+ | | |
|
||||
| | | |
|
||||
v | | |
|
||||
+------+------+ fail | | |
|
||||
|InstallCas +--------+ | |
|
||||
+------+------+ v | |
|
||||
| +------+--------+ | |
|
||||
| |InsertInstalled| | |
|
||||
v +------+--------+ | |
|
||||
+------+------+ | | |
|
||||
|RestoreConfig+<-------+ | |
|
||||
+------+------+ | |
|
||||
| | |
|
||||
v | |
|
||||
+------+------+ | |
|
||||
|RestoreSched +<------------------+ |
|
||||
+------+------+ v
|
||||
| +------+---+
|
||||
+---------------------->+ END |
|
||||
+----------+
|
||||
|
||||
"""
|
||||
|
||||
transition_map = {
|
||||
InitUpgrade: {Success: BuildCas, InitUpgrade.NotInstalled: RegularInstall},
|
||||
RegularInstall: {"default": None},
|
||||
BuildCas: {Success: SetSchedulersToNoop},
|
||||
SetSchedulersToNoop: {Success: PrepareForUpgrade},
|
||||
PrepareForUpgrade: {Success: RemoveModule, Failure: RestoreCoreSchedulers},
|
||||
RemoveModule: {Success: DropCaches, Failure: RestoreCoreSchedulers},
|
||||
DropCaches: {Success: DryRun, Failure: RestoreCoreSchedulers},
|
||||
DryRun: {Success: InsertNewModule, Failure: InsertInstalledModule},
|
||||
InsertNewModule: {Success: InstallCas, Failure: InsertInstalledModule},
|
||||
InstallCas: {Success: RestoreInitConfig, Failure: InsertInstalledModule},
|
||||
InsertInstalledModule: {"default": RestoreInitConfig},
|
||||
RestoreInitConfig: {"default": RestoreCoreSchedulers},
|
||||
RestoreCoreSchedulers: {"default": None},
|
||||
"default": None,
|
||||
}
|
||||
|
||||
|
||||
def start(args):
|
||||
logging.info(">>> Starting OpenCAS upgrade procedure")
|
||||
s = UpgradeStateMachine(InitUpgrade, force=args.force)
|
||||
result = s.run()
|
||||
|
||||
if not isinstance(result, Success):
|
||||
print(f"Upgrade failed. Reason: {result}")
|
||||
exit_code = 1
|
||||
else:
|
||||
print("Upgrade completed successfully!")
|
||||
exit_code = 0
|
||||
|
||||
print(f"Full upgrade log: {LOG_FILE}")
|
||||
|
||||
return exit_code
|
||||
|
||||
|
||||
def main():
|
||||
Path(LOG_FILE).parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(logging.INFO)
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format="%(asctime)s [%(levelname)-5.5s] %(message)s",
|
||||
handlers=[logging.FileHandler(LOG_FILE)],
|
||||
)
|
||||
|
||||
parser = argparse.ArgumentParser(prog=__file__)
|
||||
subparsers = parser.add_subparsers(title="actions")
|
||||
|
||||
parser_start = subparsers.add_parser(
|
||||
"start", help="Upgrade Open CAS in flight to current version"
|
||||
)
|
||||
parser_start.add_argument("--force", action="store_true", help="Skip prompts")
|
||||
parser_start.set_defaults(func=start)
|
||||
|
||||
if len(sys.argv[1:]) == 0:
|
||||
parser.print_help()
|
||||
return 1
|
||||
else:
|
||||
args = parser.parse_args(sys.argv[1:])
|
||||
return args.func(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
Loading…
Reference in New Issue
Block a user