Merge pull request #690 from Ostrokrzew/removal

Introduce removing inactive core command
This commit is contained in:
Michał Mielewczyk 2021-03-10 15:56:53 +01:00 committed by GitHub
commit 713f5b3b0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 215 additions and 39 deletions

View File

@ -1904,12 +1904,24 @@ int remove_core(unsigned int cache_id, unsigned int core_id,
if (run_ioctl_interruptible(fd, KCAS_IOCTL_REMOVE_CORE, &cmd, if (run_ioctl_interruptible(fd, KCAS_IOCTL_REMOVE_CORE, &cmd,
"Removing core", cache_id, core_id) < 0) { "Removing core", cache_id, core_id) < 0) {
close(fd); close(fd);
if (OCF_ERR_FLUSHING_INTERRUPTED == cmd.ext_err_code) { if (cmd.ext_err_code == OCF_ERR_FLUSHING_INTERRUPTED) {
cas_printf(LOG_ERR, "You have interrupted removal of core. CAS continues to operate normally.\n"); cas_printf(LOG_ERR, "You have interrupted %s of core. "
"CAS continues to operate normally.\n",
detach ? "detaching" : "removal");
return INTERRUPTED; return INTERRUPTED;
} else if (cmd.ext_err_code == OCF_ERR_CORE_IN_INACTIVE_STATE) {
cas_printf(LOG_ERR, "Core is inactive. To manage the "
"inactive core use '--remove-inactive' "
"command.\n");
return FAILURE;
} else if (cmd.ext_err_code == KCAS_ERR_REMOVED_DIRTY) {
print_err(cmd.ext_err_code);
return SUCCESS;
} else { } else {
cas_printf(LOG_ERR, "Error while removing core device %d from cache instance %d\n", cas_printf(LOG_ERR, "Error while %s core device %d "
core_id, cache_id); "from cache instance %d\n",
detach ? "detaching" : "removing",
core_id, cache_id);
print_err(cmd.ext_err_code); print_err(cmd.ext_err_code);
return FAILURE; return FAILURE;
} }
@ -1919,6 +1931,43 @@ int remove_core(unsigned int cache_id, unsigned int core_id,
return SUCCESS; return SUCCESS;
} }
int remove_inactive_core(unsigned int cache_id, unsigned int core_id)
{
int fd = 0;
struct kcas_remove_inactive cmd;
/* don't even attempt ioctl if filesystem is mounted */
if (SUCCESS != check_if_mounted(cache_id, core_id)) {
return FAILURE;
}
fd = open_ctrl_device();
if (fd == -1)
return FAILURE;
memset(&cmd, 0, sizeof(cmd));
cmd.cache_id = cache_id;
cmd.core_id = core_id;
if (run_ioctl(fd, KCAS_IOCTL_REMOVE_INACTIVE, &cmd) < 0) {
close(fd);
if (cmd.ext_err_code == KCAS_ERR_CORE_IN_ACTIVE_STATE) {
cas_printf(LOG_ERR, "Core is active. "
"To manage the active core use "
"'--remove-core' command.\n");
} else {
cas_printf(LOG_ERR, "Error while removing inactive "
"core device %d from cache instance "
"%d\n", core_id, cache_id);
print_err(cmd.ext_err_code);
}
return FAILURE;
}
close(fd);
return SUCCESS;
}
int core_pool_remove(const char *core_device) int core_pool_remove(const char *core_device)
{ {
struct kcas_core_pool_remove cmd; struct kcas_core_pool_remove cmd;

View File

@ -215,6 +215,15 @@ int get_core_info(int fd, int cache_id, int core_id, struct kcas_core_info *info
int remove_core(unsigned int cache_id, unsigned int core_id, int remove_core(unsigned int cache_id, unsigned int core_id,
bool detach, bool force_no_flush); bool detach, bool force_no_flush);
/**
* @brief remove inactive core device from a cache
*
* @param cache_id cache from which inactive core is being removed
* @param cache_id inactive core which is being removed
* @return 0 upon successful core removal, 1 upon failure
*/
int remove_inactive_core(unsigned int cache_id, unsigned int core_id);
int core_pool_remove(const char *core_device); int core_pool_remove(const char *core_device);
int get_core_pool_count(int fd); int get_core_pool_count(int fd);

View File

@ -180,6 +180,23 @@ int remove_core_command_handle_option(char *opt, const char **arg)
return 0; return 0;
} }
int remove_inactive_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]);
}
return 0;
}
int core_pool_remove_command_handle_option(char *opt, const char **arg) int core_pool_remove_command_handle_option(char *opt, const char **arg)
{ {
if (!strcmp(opt, "device")) { if (!strcmp(opt, "device")) {
@ -1109,7 +1126,7 @@ int handle_add()
static cli_option remove_options[] = { static cli_option remove_options[] = {
{'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED}, {'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
{'j', "core-id", CORE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED}, {'j', "core-id", CORE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED},
{'f', "force", "Force remove inactive core"}, {'f', "force", "Force active core removal without data flush"},
{0} {0}
}; };
@ -1121,6 +1138,18 @@ int handle_remove()
command_args_values.force); 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},
{0}
};
int handle_remove_inactive()
{
return remove_inactive_core(command_args_values.cache_id,
command_args_values.core_id);
}
static cli_option core_pool_remove_options[] = { static cli_option core_pool_remove_options[] = {
{'d', "device", CORE_DEVICE_DESC, 1, "DEVICE", CLI_OPTION_REQUIRED}, {'d', "device", CORE_DEVICE_DESC, 1, "DEVICE", CLI_OPTION_REQUIRED},
{0} {0}
@ -1961,7 +1990,7 @@ static cli_command cas_commands[] = {
{ {
.name = "remove-core", .name = "remove-core",
.short_name = 'R', .short_name = 'R',
.desc = "Remove core device from cache instance", .desc = "Remove active core device from cache instance",
.long_desc = NULL, .long_desc = NULL,
.options = remove_options, .options = remove_options,
.command_handle_opts = remove_core_command_handle_option, .command_handle_opts = remove_core_command_handle_option,
@ -1969,6 +1998,16 @@ static cli_command cas_commands[] = {
.flags = CLI_SU_REQUIRED, .flags = CLI_SU_REQUIRED,
.help = NULL, .help = NULL,
}, },
{
.name = "remove-inactive",
.desc = "Remove inactive core device from cache instance",
.long_desc = NULL,
.options = remove_inactive_options,
.command_handle_opts = remove_inactive_core_command_handle_option,
.handle = handle_remove_inactive,
.flags = CLI_SU_REQUIRED,
.help = NULL,
},
{ {
.name = "remove-detached", .name = "remove-detached",
.desc = "Remove core device from core pool", .desc = "Remove core device from core pool",

View File

@ -222,8 +222,8 @@ struct {
}, },
{ {
KCAS_ERR_REMOVED_DIRTY, KCAS_ERR_REMOVED_DIRTY,
"Flush error occured. Core has been set to detached state.\n" "Warning: Core has been removed or detached without flush.\n"
"Warning: Core device may contain inconsistent data.\n" "Core device may contain inconsistent data.\n"
"To access your data please add core back to the cache." "To access your data please add core back to the cache."
}, },
{ {
@ -256,7 +256,11 @@ struct {
KCAS_ERR_CACHE_STOPPING, KCAS_ERR_CACHE_STOPPING,
"Cache being stopped" "Cache being stopped"
}, },
{
KCAS_ERR_CORE_IN_ACTIVE_STATE,
"Core device is in active state"
},
}; };

View File

@ -1363,27 +1363,19 @@ static int _cache_mngt_remove_core_flush(ocf_cache_t cache,
core_active = (ocf_core_get_state(core) == ocf_core_state_active); core_active = (ocf_core_get_state(core) == ocf_core_state_active);
if (cmd->detach && !core_active) { if (!core_active) {
printk(KERN_WARNING OCF_PREFIX_SHORT
"Cannot detach core which "
"is already inactive!\n");
return -OCF_ERR_CORE_IN_INACTIVE_STATE;
}
if (core_active) {
return _cache_mngt_core_flush_sync(core,
true, _cache_read_unlock_put_cmpl);
} else if (!ocf_mngt_core_is_dirty(core)) {
result = 0;
goto unlock;
} else {
printk(KERN_WARNING OCF_PREFIX_SHORT
"Cannot remove dirty inactive core "
"without force option\n");
result = -OCF_ERR_CORE_IN_INACTIVE_STATE; result = -OCF_ERR_CORE_IN_INACTIVE_STATE;
goto unlock; goto unlock;
} }
if (!ocf_mngt_core_is_dirty(core)) {
result = 0;
goto unlock;
}
return _cache_mngt_core_flush_sync(core, true,
_cache_read_unlock_put_cmpl);
unlock: unlock:
ocf_mngt_cache_read_unlock(cache); ocf_mngt_cache_read_unlock(cache);
put: put:
@ -1399,21 +1391,23 @@ static int _cache_mngt_remove_core_prepare(ocf_cache_t cache, ocf_core_t core,
core_active = ocf_core_get_state(core) == ocf_core_state_active; core_active = ocf_core_get_state(core) == ocf_core_state_active;
if (cmd->detach && !core_active) { if (!core_active) {
printk(KERN_WARNING OCF_PREFIX_SHORT if (cmd->detach) {
"Cannot detach core which " printk(KERN_WARNING OCF_PREFIX_SHORT
"is already inactive!\n"); "Cannot detach core which "
"is already inactive!\n");
}
return -OCF_ERR_CORE_IN_INACTIVE_STATE; return -OCF_ERR_CORE_IN_INACTIVE_STATE;
} } else {
if (core_active) {
result = block_dev_destroy_exported_object(core); result = block_dev_destroy_exported_object(core);
if (result) if (result)
return result; return result;
} }
if (!cmd->force_no_flush) if (cmd->force_no_flush)
result = _cache_mngt_core_flush_uninterruptible(core); return -KCAS_ERR_REMOVED_DIRTY;
result = _cache_mngt_core_flush_uninterruptible(core);
return result ? -KCAS_ERR_REMOVED_DIRTY : 0; return result ? -KCAS_ERR_REMOVED_DIRTY : 0;
} }
@ -1463,7 +1457,7 @@ int cache_mngt_remove_core_from_cache(struct kcas_remove_core *cmd)
init_completion(&context.cmpl); init_completion(&context.cmpl);
context.result = &result; context.result = &result;
if (cmd->detach || prepare_result == -KCAS_ERR_REMOVED_DIRTY) { if (cmd->detach) {
ocf_mngt_cache_detach_core(core, ocf_mngt_cache_detach_core(core,
_cache_mngt_remove_core_complete, &context); _cache_mngt_remove_core_complete, &context);
} else { } else {
@ -1490,6 +1484,60 @@ put:
return result; return result;
} }
int cache_mngt_remove_inactive_core(struct kcas_remove_inactive *cmd)
{
struct _cache_mngt_sync_context context;
int result = 0;
ocf_cache_t cache;
ocf_core_t core;
result = mngt_get_cache_by_id(cas_ctx, cmd->cache_id, &cache);
if (result)
return result;
result = _cache_mngt_lock_sync(cache);
if (result)
goto put;
result = get_core_by_id(cache, cmd->core_id, &core);
if (result < 0) {
goto unlock;
}
result = (ocf_core_get_state(core) == ocf_core_state_active);
if (result) {
result = -KCAS_ERR_CORE_IN_ACTIVE_STATE;
goto unlock;
}
/*
* Destroy exported object - in case of error during destruction of
* exported object, instead of trying rolling this back we rather
* inform user about error.
*/
result = block_dev_destroy_exported_object(core);
if (result)
goto unlock;
init_completion(&context.cmpl);
context.result = &result;
ocf_mngt_cache_remove_core(core, _cache_mngt_remove_core_complete,
&context);
wait_for_completion(&context.cmpl);
if (!result) {
mark_core_id_free(cache, cmd->core_id);
}
unlock:
ocf_mngt_cache_unlock(cache);
put:
ocf_mngt_cache_put(cache);
return result;
}
int cache_mngt_reset_stats(const char *cache_name, size_t cache_name_len, int cache_mngt_reset_stats(const char *cache_name, size_t cache_name_len,
const char *core_name, size_t core_name_len) const char *core_name, size_t core_name_len)
{ {

View File

@ -36,6 +36,8 @@ int cache_mngt_add_core_to_cache(const char *cache_name, size_t name_len,
int cache_mngt_remove_core_from_cache(struct kcas_remove_core *cmd); int cache_mngt_remove_core_from_cache(struct kcas_remove_core *cmd);
int cache_mngt_remove_inactive_core(struct kcas_remove_inactive *cmd);
int cache_mngt_reset_stats(const char *cache_name, size_t cache_name_len, int cache_mngt_reset_stats(const char *cache_name, size_t cache_name_len,
const char *core_name, size_t core_name_len); const char *core_name, size_t core_name_len);

View File

@ -132,6 +132,16 @@ long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd,
RETURN_CMD_RESULT(cmd_info, arg, retval); RETURN_CMD_RESULT(cmd_info, arg, retval);
} }
case KCAS_IOCTL_REMOVE_INACTIVE: {
struct kcas_remove_inactive *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mngt_remove_inactive_core(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_RESET_STATS: { case KCAS_IOCTL_RESET_STATS: {
struct kcas_reset_stats *cmd_info; struct kcas_reset_stats *cmd_info;
char cache_name[OCF_CACHE_NAME_SIZE]; char cache_name[OCF_CACHE_NAME_SIZE];

View File

@ -65,6 +65,7 @@ struct {
{ KCAS_ERR_A_PART, EINVAL }, { KCAS_ERR_A_PART, EINVAL },
{ KCAS_ERR_REMOVED_DIRTY, EIO }, { KCAS_ERR_REMOVED_DIRTY, EIO },
{ KCAS_ERR_STOPPED_DIRTY, EIO }, { KCAS_ERR_STOPPED_DIRTY, EIO },
{ KCAS_ERR_CORE_IN_ACTIVE_STATE, ENODEV },
}; };
/*******************************************/ /*******************************************/

View File

@ -117,12 +117,19 @@ struct kcas_insert_core {
struct kcas_remove_core { struct kcas_remove_core {
uint16_t cache_id; /**< id of an running cache */ uint16_t cache_id; /**< id of an running cache */
uint16_t core_id; /**< id core object to be removed */ uint16_t core_id; /**< id core object to be removed */
bool force_no_flush; /**< remove core without flushing */ bool force_no_flush; /**< remove active core without flushing */
bool detach; /**< detach core without removing it from cache metadata */ bool detach; /**< detach core without removing it from cache metadata */
int ext_err_code; int ext_err_code;
}; };
struct kcas_remove_inactive {
uint16_t cache_id; /**< id of an running cache */
uint16_t core_id; /**< id core object to be removed */
int ext_err_code;
};
struct kcas_reset_stats { struct kcas_reset_stats {
uint16_t cache_id; /**< id of an running cache */ uint16_t cache_id; /**< id of an running cache */
uint16_t core_id; /**< id core object to be removed */ uint16_t core_id; /**< id core object to be removed */
@ -419,6 +426,7 @@ struct kcas_get_cache_param {
* 34 * KCAS_IOCTL_GET_STATS * OK * * 34 * KCAS_IOCTL_GET_STATS * OK *
* 35 * KCAS_IOCTL_PURGE_CACHE * OK * * 35 * KCAS_IOCTL_PURGE_CACHE * OK *
* 36 * KCAS_IOCTL_PURGE_CORE * OK * * 36 * KCAS_IOCTL_PURGE_CORE * OK *
* 37 * KCAS_IOCTL_REMOVE_INACTIVE * OK *
******************************************************************************* *******************************************************************************
*/ */
@ -473,7 +481,7 @@ struct kcas_get_cache_param {
/** Add core object to an running cache instance */ /** Add core object to an running cache instance */
#define KCAS_IOCTL_INSERT_CORE _IOWR(KCAS_IOCTL_MAGIC, 22, struct kcas_insert_core) #define KCAS_IOCTL_INSERT_CORE _IOWR(KCAS_IOCTL_MAGIC, 22, struct kcas_insert_core)
/** Remove core object from an running cache instance */ /** Remove active core object from an running cache instance */
#define KCAS_IOCTL_REMOVE_CORE _IOR(KCAS_IOCTL_MAGIC, 23, struct kcas_remove_core) #define KCAS_IOCTL_REMOVE_CORE _IOR(KCAS_IOCTL_MAGIC, 23, struct kcas_remove_core)
/** Retrieve properties of a running cache instance (incl. mode etc.) */ /** Retrieve properties of a running cache instance (incl. mode etc.) */
@ -517,6 +525,9 @@ struct kcas_get_cache_param {
* and invalidate all valid cache lines associated with given core. */ * and invalidate all valid cache lines associated with given core. */
#define KCAS_IOCTL_PURGE_CORE _IOWR(KCAS_IOCTL_MAGIC, 36, struct kcas_flush_core) #define KCAS_IOCTL_PURGE_CORE _IOWR(KCAS_IOCTL_MAGIC, 36, struct kcas_flush_core)
/** Remove inactive core object from an running cache instance */
#define KCAS_IOCTL_REMOVE_INACTIVE _IOR(KCAS_IOCTL_MAGIC, 37, struct kcas_remove_inactive)
/** /**
* Extended kernel CAS error codes * Extended kernel CAS error codes
*/ */
@ -566,7 +577,7 @@ enum kcas_error {
/** Given device is a partition */ /** Given device is a partition */
KCAS_ERR_A_PART, KCAS_ERR_A_PART,
/** Core has been removed with flush error */ /** Core has been removed, but it may contain dirty data */
KCAS_ERR_REMOVED_DIRTY, KCAS_ERR_REMOVED_DIRTY,
/** Cache has been stopped, but it may contain dirty data */ /** Cache has been stopped, but it may contain dirty data */
@ -584,11 +595,14 @@ enum kcas_error {
/** Condition token does not identify any known condition */ /** Condition token does not identify any known condition */
KCAS_ERR_CLS_RULE_UNKNOWN_CONDITION, KCAS_ERR_CLS_RULE_UNKNOWN_CONDITION,
/** Waiting for async operation was interrupted*/ /** Waiting for async operation was interrupted */
KCAS_ERR_WAITING_INTERRUPTED, KCAS_ERR_WAITING_INTERRUPTED,
/** Cache already being stopped*/ /** Cache already being stopped*/
KCAS_ERR_CACHE_STOPPING, KCAS_ERR_CACHE_STOPPING,
/** Core device is in active state */
KCAS_ERR_CORE_IN_ACTIVE_STATE
}; };
#endif #endif