open-cas-linux/modules/cas_cache/service_ui_ioctl.c
Robert Baldyga 94e8ca09e0 Initial commit
Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
2019-03-29 08:45:50 +01:00

415 lines
9.6 KiB
C

/*
* Copyright(c) 2012-2019 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "cas_cache.h"
struct {
int cas_error;
int std_error;
} static cas_error_code_map[] = {
/* IOC error mappings*/
{ OCF_ERR_INVAL, EINVAL },
{ OCF_ERR_INVAL_VOLUME_TYPE, EINVAL },
{ OCF_ERR_INTR, EINTR },
{ OCF_ERR_UNKNOWN, EINVAL },
{ OCF_ERR_TOO_MANY_CACHES, ENOSPC },
{ OCF_ERR_NO_MEM, ENOMEM },
{ OCF_ERR_NO_FREE_RAM, ENOMEM },
{ OCF_ERR_START_CACHE_FAIL, EFAULT },
{ OCF_ERR_CACHE_IN_USE, EBUSY },
{ OCF_ERR_CACHE_NOT_EXIST, ENODEV },
{ OCF_ERR_CACHE_EXIST, EEXIST },
{ OCF_ERR_TOO_MANY_CORES, ENOSPC },
{ OCF_ERR_CORE_NOT_AVAIL, ENAVAIL },
{ OCF_ERR_NOT_OPEN_EXC, EBUSY },
{ OCF_ERR_CACHE_NOT_AVAIL, ENAVAIL },
{ OCF_ERR_IO_CLASS_NOT_EXIST, ENODEV },
{ OCF_ERR_WRITE_CACHE, EIO },
{ OCF_ERR_WRITE_CORE, EIO },
{ OCF_ERR_DIRTY_SHUTDOWN, EFAULT },
{ OCF_ERR_DIRTY_EXISTS, EFAULT },
{ OCF_ERR_FLUSHING_INTERRUPTED, EINTR },
/* CAS kernel error mappings*/
{ KCAS_ERR_ROOT, EPERM },
{ KCAS_ERR_SYSTEM, EINVAL },
{ KCAS_ERR_BAD_RANGE, ERANGE },
{ KCAS_ERR_DEV_SPACE, ENOSPC },
{ KCAS_ERR_INV_IOCTL, EINVAL },
{ KCAS_ERR_DEV_PENDING, EBUSY },
{ KCAS_ERR_DIRTY_EXISTS_NVME, EFAULT },
{ 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_NOT_NVME, ENODEV },
{ KCAS_ERR_FORMAT_FAILED, EFAULT },
{ KCAS_ERR_NVME_BAD_FORMAT, EINVAL },
{ KCAS_ERR_CONTAINS_PART, EINVAL },
{ KCAS_ERR_A_PART, EINVAL },
{ KCAS_ERR_REMOVED_DIRTY, EIO },
{ KCAS_ERR_STOPPED_DIRTY, EIO },
};
/*******************************************/
/* Helper which change cas-specific error */
/* codes to kernel generic error codes */
/*******************************************/
int map_cas_err_to_generic_code(int cas_error_code)
{
int i;
if (cas_error_code == 0)
return 0; /* No Error */
cas_error_code = abs(cas_error_code);
for (i = 0; i < ARRAY_SIZE(cas_error_code_map); i++) {
if (cas_error_code_map[i].cas_error == cas_error_code)
return -cas_error_code_map[i].std_error;
}
return -cas_error_code;
}
#define _GET_CMD_INFO(cmd_info, arg, size) ({ \
cmd_info = vmalloc(size); \
if (!cmd_info) \
return -ENOMEM; \
if (copy_from_user(cmd_info, (void __user *)arg, size)) { \
printk(KERN_ALERT "Cannot copy cmd info from user space\n"); \
vfree(cmd_info); \
return -EINVAL; \
} \
})
#define GET_CMD_INFO(cmd_info, arg) _GET_CMD_INFO(cmd_info, arg, \
sizeof(*cmd_info))
#define RETURN_CMD_RESULT(cmd_info, arg, result) ({ \
int ret = result; \
cmd_info->ext_err_code = abs(result); \
if (copy_to_user((void __user *)arg, cmd_info, sizeof(*cmd_info))) { \
printk(KERN_ALERT "Unable to copy response to user\n"); \
ret = -EFAULT; \
} \
vfree(cmd_info); \
return map_cas_err_to_generic_code(ret); \
})
/* this handles IOctl for /dev/cas */
/*********************************************/
long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int retval = 0;
if (_IOC_TYPE(cmd) != KCAS_IOCTL_MAGIC)
return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) {
/* Must be root to issue ioctls */
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_STATS &&
cmd != KCAS_IOCTL_GET_CAPABILITIES) {
return -EFAULT;
}
switch (cmd) {
case KCAS_IOCTL_START_CACHE: {
struct kcas_start_cache *cmd_info;
struct ocf_mngt_cache_config cfg;
struct ocf_mngt_cache_device_config device_cfg;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_prepare_cache_cfg(&cfg, &device_cfg, cmd_info);
if (retval)
RETURN_CMD_RESULT(cmd_info, arg, retval);
retval = cache_mng_init_instance(&cfg, &device_cfg, cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_STOP_CACHE: {
struct kcas_stop_cache *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_exit_instance(cmd_info->cache_id,
cmd_info->flush_data);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_SET_CACHE_STATE: {
struct kcas_set_cache_state *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_set_cache_mode(cmd_info->cache_id,
cmd_info->caching_mode, cmd_info->flush_data);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_INSERT_CORE: {
struct kcas_insert_core *cmd_info;
struct ocf_mngt_core_config cfg;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_prepare_core_cfg(&cfg, cmd_info);
if (retval)
RETURN_CMD_RESULT(cmd_info, arg, retval);
retval = cache_mng_add_core_to_cache(&cfg, cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_REMOVE_CORE: {
struct kcas_remove_core *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_remove_core_from_cache(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_RESET_STATS: {
struct kcas_reset_stats *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_reset_core_stats(cmd_info->cache_id,
cmd_info->core_id);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_FLUSH_CACHE: {
struct kcas_flush_cache *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_flush_device(cmd_info->cache_id);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_INTERRUPT_FLUSHING: {
struct kcas_interrupt_flushing *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_interrupt_flushing(cmd_info->cache_id);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_FLUSH_CORE: {
struct kcas_flush_core *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_flush_object(cmd_info->cache_id,
cmd_info->core_id);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_CACHE_INFO: {
struct kcas_cache_info *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_get_info(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_CORE_INFO: {
struct kcas_core_info *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_get_core_info(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_PARTITION_STATS: {
struct kcas_io_class *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_get_io_class_info(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_PARTITION_SET: {
struct kcas_io_classes *cmd_info;
/* copy entire memory from user, including array of
* ocf_io_class_info structs past the end of kcas_io_classes */
_GET_CMD_INFO(cmd_info, arg, KCAS_IO_CLASSES_SIZE);
retval = cache_mng_set_partitions(cmd_info);
/* return just sizeof(struct kcas_io_classes) bytes of data */
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_GET_CACHE_COUNT: {
struct kcas_cache_count *cmd_info;
GET_CMD_INFO(cmd_info, arg);
cmd_info->cache_count = ocf_mngt_cache_get_count(cas_ctx);
RETURN_CMD_RESULT(cmd_info, arg, 0);
}
case KCAS_IOCTL_LIST_CACHE: {
struct kcas_cache_list *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_list_caches(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval > 0 ? 0 : retval);
}
case KCAS_IOCTL_GET_CAPABILITIES: {
struct kcas_capabilites *cmd_info;
GET_CMD_INFO(cmd_info, arg);
memset(cmd_info, 0, sizeof(*cmd_info));
#ifdef CAS_NVME_FULL
cmd_info->nvme_format = 1;
#endif
RETURN_CMD_RESULT(cmd_info, arg, 0);
}
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);
}
#if defined(CAS_NVME_FULL)
case KCAS_IOCTL_NVME_FORMAT: {
struct kcas_nvme_format *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cas_nvme_format_optimal(
cmd_info->device_path_name,
cmd_info->metadata_mode,
cmd_info->force);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
#endif
case KCAS_IOCTL_GET_CORE_POOL_COUNT: {
struct kcas_core_pool_count *cmd_info;
GET_CMD_INFO(cmd_info, arg);
cmd_info->core_pool_count =
ocf_mngt_core_pool_get_count(cas_ctx);
RETURN_CMD_RESULT(cmd_info, arg, 0);
}
case KCAS_IOCTL_GET_CORE_POOL_PATHS: {
struct kcas_core_pool_path *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_core_pool_get_paths(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_CORE_POOL_REMOVE: {
struct kcas_core_pool_remove *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_core_pool_remove(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_CACHE_CHECK_DEVICE: {
struct kcas_cache_check_device *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_cache_check_device(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_SET_CORE_PARAM: {
struct kcas_set_core_param *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_set_core_params(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_GET_CORE_PARAM: {
struct kcas_get_core_param *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_get_core_params(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_SET_CACHE_PARAM: {
struct kcas_set_cache_param *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_set_cache_params(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
case KCAS_IOCTL_GET_CACHE_PARAM: {
struct kcas_get_cache_param *cmd_info;
GET_CMD_INFO(cmd_info, arg);
retval = cache_mng_get_cache_params(cmd_info);
RETURN_CMD_RESULT(cmd_info, arg, retval);
}
default:
return -EINVAL;
}
}