162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * drivers/hyperhold/hp_core.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci #define pr_fmt(fmt) "[HYPERHOLD]" fmt 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/blkdev.h> 1262306a36Sopenharmony_ci#include <linux/sysctl.h> 1362306a36Sopenharmony_ci#include <linux/version.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "hyperhold.h" 1662306a36Sopenharmony_ci#include "hp_device.h" 1762306a36Sopenharmony_ci#include "hp_space.h" 1862306a36Sopenharmony_ci#include "hp_iotab.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define HP_DFLT_DEVICE "/dev/by-name/hyperhold" 2162306a36Sopenharmony_ci#define HP_DFLT_EXT_SIZE (1 << 15) 2262306a36Sopenharmony_ci#define HP_DEV_NAME_LEN 256 2362306a36Sopenharmony_ci#define HP_STATE_LEN 10 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define CHECK(cond, ...) ((cond) || (pr_err(__VA_ARGS__), false)) 2662306a36Sopenharmony_ci#define CHECK_BOUND(var, min, max) \ 2762306a36Sopenharmony_ci CHECK((var) >= (min) && (var) <= (max), \ 2862306a36Sopenharmony_ci "%s %u out of bounds %u ~ %u!\n", #var, (var), (min), (max)) 2962306a36Sopenharmony_ci#define CHECK_INITED CHECK(hyperhold.inited, "hyperhold is not enable!\n") 3062306a36Sopenharmony_ci#define CHECK_ENABLE (CHECK_INITED && CHECK(hyperhold.enable, "hyperhold is readonly!\n")) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct hyperhold { 3362306a36Sopenharmony_ci bool enable; 3462306a36Sopenharmony_ci bool inited; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci char device_name[HP_DEV_NAME_LEN]; 3762306a36Sopenharmony_ci u32 extent_size; 3862306a36Sopenharmony_ci u32 enable_soft_crypt; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci struct hp_device dev; 4162306a36Sopenharmony_ci struct hp_space spc; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci struct workqueue_struct *read_wq; 4462306a36Sopenharmony_ci struct workqueue_struct *write_wq; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci struct mutex init_lock; 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct hyperhold hyperhold; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciatomic64_t mem_used = ATOMIC64_INIT(0); 5262306a36Sopenharmony_ci#ifdef CONFIG_HYPERHOLD_DEBUG 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * return the memory overhead of hyperhold module 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_ciu64 hyperhold_memory_used(void) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci return atomic64_read(&mem_used) + hpio_memory() + space_memory(); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci#endif 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_civoid hyperhold_disable(bool force) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci if (!CHECK_INITED) 6562306a36Sopenharmony_ci return; 6662306a36Sopenharmony_ci if (!force && !CHECK_ENABLE) 6762306a36Sopenharmony_ci return; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci mutex_lock(&hyperhold.init_lock); 7062306a36Sopenharmony_ci hyperhold.enable = false; 7162306a36Sopenharmony_ci if (!wait_for_space_empty(&hyperhold.spc, force)) 7262306a36Sopenharmony_ci goto out; 7362306a36Sopenharmony_ci hyperhold.inited = false; 7462306a36Sopenharmony_ci wait_for_iotab_empty(); 7562306a36Sopenharmony_ci destroy_workqueue(hyperhold.read_wq); 7662306a36Sopenharmony_ci destroy_workqueue(hyperhold.write_wq); 7762306a36Sopenharmony_ci deinit_space(&hyperhold.spc); 7862306a36Sopenharmony_ci crypto_deinit(&hyperhold.dev); 7962306a36Sopenharmony_ci unbind_bdev(&hyperhold.dev); 8062306a36Sopenharmony_ciout: 8162306a36Sopenharmony_ci if (hyperhold.inited) 8262306a36Sopenharmony_ci pr_info("hyperhold is disabled, read only.\n"); 8362306a36Sopenharmony_ci else 8462306a36Sopenharmony_ci pr_info("hyperhold is totally disabled!\n"); 8562306a36Sopenharmony_ci mutex_unlock(&hyperhold.init_lock); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_disable); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_civoid hyperhold_enable(void) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci bool enable = true; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (hyperhold.inited) 9462306a36Sopenharmony_ci goto out; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci mutex_lock(&hyperhold.init_lock); 9762306a36Sopenharmony_ci if (hyperhold.inited) 9862306a36Sopenharmony_ci goto unlock; 9962306a36Sopenharmony_ci if (!bind_bdev(&hyperhold.dev, hyperhold.device_name)) 10062306a36Sopenharmony_ci goto err1; 10162306a36Sopenharmony_ci if (!crypto_init(&hyperhold.dev, hyperhold.enable_soft_crypt)) 10262306a36Sopenharmony_ci goto err2; 10362306a36Sopenharmony_ci if (!init_space(&hyperhold.spc, hyperhold.dev.dev_size, hyperhold.extent_size)) 10462306a36Sopenharmony_ci goto err3; 10562306a36Sopenharmony_ci hyperhold.read_wq = alloc_workqueue("hyperhold_read", WQ_HIGHPRI | WQ_UNBOUND, 0); 10662306a36Sopenharmony_ci if (!hyperhold.read_wq) 10762306a36Sopenharmony_ci goto err4; 10862306a36Sopenharmony_ci hyperhold.write_wq = alloc_workqueue("hyperhold_write", 0, 0); 10962306a36Sopenharmony_ci if (!hyperhold.write_wq) 11062306a36Sopenharmony_ci goto err5; 11162306a36Sopenharmony_ci hyperhold.inited = true; 11262306a36Sopenharmony_ci goto unlock; 11362306a36Sopenharmony_cierr5: 11462306a36Sopenharmony_ci destroy_workqueue(hyperhold.read_wq); 11562306a36Sopenharmony_cierr4: 11662306a36Sopenharmony_ci deinit_space(&hyperhold.spc); 11762306a36Sopenharmony_cierr3: 11862306a36Sopenharmony_ci crypto_deinit(&hyperhold.dev); 11962306a36Sopenharmony_cierr2: 12062306a36Sopenharmony_ci unbind_bdev(&hyperhold.dev); 12162306a36Sopenharmony_cierr1: 12262306a36Sopenharmony_ci enable = false; 12362306a36Sopenharmony_ciunlock: 12462306a36Sopenharmony_ci mutex_unlock(&hyperhold.init_lock); 12562306a36Sopenharmony_ciout: 12662306a36Sopenharmony_ci if (enable) { 12762306a36Sopenharmony_ci hyperhold.enable = true; 12862306a36Sopenharmony_ci pr_info("hyperhold is enabled.\n"); 12962306a36Sopenharmony_ci } else { 13062306a36Sopenharmony_ci hyperhold.enable = false; 13162306a36Sopenharmony_ci pr_err("hyperhold enable failed!\n"); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_enable); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int enable_sysctl_handler(struct ctl_table *table, int write, 13762306a36Sopenharmony_ci void *buffer, size_t *lenp, loff_t *ppos) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci const struct cred *cred = current_cred(); 14062306a36Sopenharmony_ci char *filter_buf; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci filter_buf = strstrip((char *)buffer); 14362306a36Sopenharmony_ci if (write) { 14462306a36Sopenharmony_ci if (!uid_eq(cred->euid, GLOBAL_MEMMGR_UID) && 14562306a36Sopenharmony_ci !uid_eq(cred->euid, GLOBAL_ROOT_UID)) { 14662306a36Sopenharmony_ci pr_err("no permission to enable/disable eswap!\n"); 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci if (!strcmp(filter_buf, "enable")) 15062306a36Sopenharmony_ci hyperhold_enable(); 15162306a36Sopenharmony_ci else if (!strcmp(filter_buf, "disable")) 15262306a36Sopenharmony_ci hyperhold_disable(false); 15362306a36Sopenharmony_ci else if (!strcmp(filter_buf, "force_disable")) 15462306a36Sopenharmony_ci hyperhold_disable(true); 15562306a36Sopenharmony_ci } else { 15662306a36Sopenharmony_ci if (*lenp < HP_STATE_LEN || *ppos) { 15762306a36Sopenharmony_ci *lenp = 0; 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci if (hyperhold.enable) 16162306a36Sopenharmony_ci strcpy(buffer, "enable\n"); 16262306a36Sopenharmony_ci else if (hyperhold.inited) 16362306a36Sopenharmony_ci strcpy(buffer, "readonly\n"); 16462306a36Sopenharmony_ci else 16562306a36Sopenharmony_ci strcpy(buffer, "disable\n"); 16662306a36Sopenharmony_ci *lenp = strlen(buffer); 16762306a36Sopenharmony_ci *ppos += *lenp; 16862306a36Sopenharmony_ci#ifdef CONFIG_HYPERHOLD_DEBUG 16962306a36Sopenharmony_ci pr_info("hyperhold memory overhead = %llu.\n", hyperhold_memory_used()); 17062306a36Sopenharmony_ci#endif 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int device_sysctl_handler(struct ctl_table *table, int write, 17662306a36Sopenharmony_ci void *buffer, size_t *lenp, loff_t *ppos) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci int ret; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci mutex_lock(&hyperhold.init_lock); 18162306a36Sopenharmony_ci if (write && hyperhold.inited) { 18262306a36Sopenharmony_ci pr_err("hyperhold device is busy!\n"); 18362306a36Sopenharmony_ci ret = -EBUSY; 18462306a36Sopenharmony_ci goto unlock; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci ret = proc_dostring(table, write, buffer, lenp, ppos); 18762306a36Sopenharmony_ci if (write && !ret) { 18862306a36Sopenharmony_ci hyperhold.enable_soft_crypt = 1; 18962306a36Sopenharmony_ci pr_info("device changed, default enable soft crypt.\n"); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ciunlock: 19262306a36Sopenharmony_ci mutex_unlock(&hyperhold.init_lock); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return ret; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int extent_sysctl_handler(struct ctl_table *table, int write, 19862306a36Sopenharmony_ci void *buffer, size_t *lenp, loff_t *ppos) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci int ret; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci mutex_lock(&hyperhold.init_lock); 20362306a36Sopenharmony_ci if (write && hyperhold.inited) { 20462306a36Sopenharmony_ci pr_err("hyperhold device is busy!\n"); 20562306a36Sopenharmony_ci ret = -EBUSY; 20662306a36Sopenharmony_ci goto unlock; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci ret = proc_douintvec(table, write, buffer, lenp, ppos); 20962306a36Sopenharmony_ciunlock: 21062306a36Sopenharmony_ci mutex_unlock(&hyperhold.init_lock); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci return ret; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int crypto_sysctl_handler(struct ctl_table *table, int write, 21662306a36Sopenharmony_ci void *buffer, size_t *lenp, loff_t *ppos) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci int ret; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci mutex_lock(&hyperhold.init_lock); 22162306a36Sopenharmony_ci if (write && hyperhold.inited) { 22262306a36Sopenharmony_ci pr_err("hyperhold device is busy!\n"); 22362306a36Sopenharmony_ci ret = -EBUSY; 22462306a36Sopenharmony_ci goto unlock; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci ret = proc_douintvec_minmax(table, write, buffer, lenp, ppos); 22762306a36Sopenharmony_ciunlock: 22862306a36Sopenharmony_ci mutex_unlock(&hyperhold.init_lock); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic struct ctl_table_header *hp_sysctl_header; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) 23662306a36Sopenharmony_cistatic struct ctl_table hp_sys_table[] = { 23762306a36Sopenharmony_ci { 23862306a36Sopenharmony_ci .procname = "enable", 23962306a36Sopenharmony_ci .mode = 0666, 24062306a36Sopenharmony_ci .proc_handler = enable_sysctl_handler, 24162306a36Sopenharmony_ci }, 24262306a36Sopenharmony_ci { 24362306a36Sopenharmony_ci .procname = "device", 24462306a36Sopenharmony_ci .data = &hyperhold.device_name, 24562306a36Sopenharmony_ci .maxlen = sizeof(hyperhold.device_name), 24662306a36Sopenharmony_ci .mode = 0644, 24762306a36Sopenharmony_ci .proc_handler = device_sysctl_handler, 24862306a36Sopenharmony_ci }, 24962306a36Sopenharmony_ci { 25062306a36Sopenharmony_ci .procname = "extent_size", 25162306a36Sopenharmony_ci .data = &hyperhold.extent_size, 25262306a36Sopenharmony_ci .maxlen = sizeof(hyperhold.extent_size), 25362306a36Sopenharmony_ci .mode = 0644, 25462306a36Sopenharmony_ci .proc_handler = extent_sysctl_handler, 25562306a36Sopenharmony_ci }, 25662306a36Sopenharmony_ci { 25762306a36Sopenharmony_ci .procname = "soft_crypt", 25862306a36Sopenharmony_ci .data = &hyperhold.enable_soft_crypt, 25962306a36Sopenharmony_ci .maxlen = sizeof(hyperhold.enable_soft_crypt), 26062306a36Sopenharmony_ci .mode = 0644, 26162306a36Sopenharmony_ci .proc_handler = crypto_sysctl_handler, 26262306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 26362306a36Sopenharmony_ci .extra2 = SYSCTL_ONE, 26462306a36Sopenharmony_ci }, 26562306a36Sopenharmony_ci {} 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ci#else 26862306a36Sopenharmony_cistatic struct ctl_table hp_table[] = { 26962306a36Sopenharmony_ci { 27062306a36Sopenharmony_ci .procname = "enable", 27162306a36Sopenharmony_ci .mode = 0666, 27262306a36Sopenharmony_ci .proc_handler = enable_sysctl_handler, 27362306a36Sopenharmony_ci }, 27462306a36Sopenharmony_ci { 27562306a36Sopenharmony_ci .procname = "device", 27662306a36Sopenharmony_ci .data = &hyperhold.device_name, 27762306a36Sopenharmony_ci .maxlen = sizeof(hyperhold.device_name), 27862306a36Sopenharmony_ci .mode = 0644, 27962306a36Sopenharmony_ci .proc_handler = device_sysctl_handler, 28062306a36Sopenharmony_ci }, 28162306a36Sopenharmony_ci { 28262306a36Sopenharmony_ci .procname = "extent_size", 28362306a36Sopenharmony_ci .data = &hyperhold.extent_size, 28462306a36Sopenharmony_ci .maxlen = sizeof(hyperhold.extent_size), 28562306a36Sopenharmony_ci .mode = 0644, 28662306a36Sopenharmony_ci .proc_handler = extent_sysctl_handler, 28762306a36Sopenharmony_ci }, 28862306a36Sopenharmony_ci { 28962306a36Sopenharmony_ci .procname = "soft_crypt", 29062306a36Sopenharmony_ci .data = &hyperhold.enable_soft_crypt, 29162306a36Sopenharmony_ci .maxlen = sizeof(hyperhold.enable_soft_crypt), 29262306a36Sopenharmony_ci .mode = 0644, 29362306a36Sopenharmony_ci .proc_handler = crypto_sysctl_handler, 29462306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 29562306a36Sopenharmony_ci .extra2 = SYSCTL_ONE, 29662306a36Sopenharmony_ci }, 29762306a36Sopenharmony_ci {} 29862306a36Sopenharmony_ci}; 29962306a36Sopenharmony_cistatic struct ctl_table hp_kernel_table[] = { 30062306a36Sopenharmony_ci { 30162306a36Sopenharmony_ci .procname = "hyperhold", 30262306a36Sopenharmony_ci .mode = 0555, 30362306a36Sopenharmony_ci .child = hp_table, 30462306a36Sopenharmony_ci }, 30562306a36Sopenharmony_ci {} 30662306a36Sopenharmony_ci}; 30762306a36Sopenharmony_cistatic struct ctl_table hp_sys_table[] = { 30862306a36Sopenharmony_ci { 30962306a36Sopenharmony_ci .procname = "kernel", 31062306a36Sopenharmony_ci .mode = 0555, 31162306a36Sopenharmony_ci .child = hp_kernel_table, 31262306a36Sopenharmony_ci }, 31362306a36Sopenharmony_ci {} 31462306a36Sopenharmony_ci}; 31562306a36Sopenharmony_ci#endif 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cibool is_hyperhold_enable(void) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci return hyperhold.enable; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic int __init hyperhold_init(void) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci strcpy(hyperhold.device_name, HP_DFLT_DEVICE); 32562306a36Sopenharmony_ci hyperhold.extent_size = HP_DFLT_EXT_SIZE; 32662306a36Sopenharmony_ci hyperhold.enable_soft_crypt = 1; 32762306a36Sopenharmony_ci mutex_init(&hyperhold.init_lock); 32862306a36Sopenharmony_ci#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) 32962306a36Sopenharmony_ci hp_sysctl_header = register_sysctl("kernel/hyperhold", hp_sys_table); 33062306a36Sopenharmony_ci#else 33162306a36Sopenharmony_ci hp_sysctl_header = register_sysctl_table(hp_sys_table); 33262306a36Sopenharmony_ci#endif 33362306a36Sopenharmony_ci if (!hp_sysctl_header) { 33462306a36Sopenharmony_ci pr_err("register hyperhold sysctl table failed!\n"); 33562306a36Sopenharmony_ci return -EINVAL; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void __exit hyperhold_exit(void) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci unregister_sysctl_table(hp_sysctl_header); 34462306a36Sopenharmony_ci hyperhold_disable(true); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic struct hp_space *space_of(u32 eid) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci return &hyperhold.spc; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/* replace this func for multi devices */ 35362306a36Sopenharmony_cistatic struct hp_device *device_of(u32 eid) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci return &hyperhold.dev; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/* replace this func for multi devices */ 35962306a36Sopenharmony_ciu32 hyperhold_nr_extent(void) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci if (!CHECK_INITED) 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return hyperhold.spc.nr_ext; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_nr_extent); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ciu32 hyperhold_extent_size(u32 eid) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct hp_space *spc = NULL; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (!CHECK_INITED) 37362306a36Sopenharmony_ci return 0; 37462306a36Sopenharmony_ci spc = space_of(eid); 37562306a36Sopenharmony_ci if (!CHECK(spc, "invalid eid %u!\n", eid)) 37662306a36Sopenharmony_ci return 0; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return spc->ext_size; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_extent_size); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/* replace this func for multi devices */ 38362306a36Sopenharmony_cilong hyperhold_address(u32 eid, u32 offset) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct hp_space *spc = NULL; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (!CHECK_INITED) 38862306a36Sopenharmony_ci return -EINVAL; 38962306a36Sopenharmony_ci spc = space_of(eid); 39062306a36Sopenharmony_ci if (!CHECK(spc, "invalid eid %u!\n", eid)) 39162306a36Sopenharmony_ci return -EINVAL; 39262306a36Sopenharmony_ci if (!CHECK_BOUND(offset, 0, spc->ext_size - 1)) 39362306a36Sopenharmony_ci return -EINVAL; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci return (u64)eid * spc->ext_size + offset; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_address); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci/* replace this func for multi devices */ 40062306a36Sopenharmony_ciint hyperhold_addr_extent(u64 addr) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct hp_space *spc = NULL; 40362306a36Sopenharmony_ci u32 eid; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (!CHECK_INITED) 40662306a36Sopenharmony_ci return -EINVAL; 40762306a36Sopenharmony_ci eid = div_u64(addr, hyperhold.spc.ext_size); 40862306a36Sopenharmony_ci spc = space_of(eid); 40962306a36Sopenharmony_ci if (!CHECK(spc, "invalid eid %u!\n", eid)) 41062306a36Sopenharmony_ci return -EINVAL; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return eid; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_addr_extent); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci/* replace this func for multi devices */ 41762306a36Sopenharmony_ciint hyperhold_addr_offset(u64 addr) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci if (!CHECK_INITED) 42062306a36Sopenharmony_ci return -EINVAL; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return do_div(addr, hyperhold.spc.ext_size); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_addr_offset); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci/* replace this func for multi devices */ 42762306a36Sopenharmony_ciint hyperhold_alloc_extent(void) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci if (!CHECK_ENABLE) 43062306a36Sopenharmony_ci return -EINVAL; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return alloc_eid(&hyperhold.spc); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_alloc_extent); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_civoid hyperhold_free_extent(u32 eid) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct hp_space *spc = NULL; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (!CHECK_INITED) 44162306a36Sopenharmony_ci return; 44262306a36Sopenharmony_ci spc = space_of(eid); 44362306a36Sopenharmony_ci if (!CHECK(spc, "invalid eid %u!\n", eid)) 44462306a36Sopenharmony_ci return; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci free_eid(spc, eid); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_free_extent); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_civoid hyperhold_should_free_extent(u32 eid) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct hpio *hpio = NULL; 45362306a36Sopenharmony_ci struct hp_space *spc = NULL; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (!CHECK_INITED) 45662306a36Sopenharmony_ci return; 45762306a36Sopenharmony_ci spc = space_of(eid); 45862306a36Sopenharmony_ci if (!CHECK(spc, "invalid eid %u", eid)) 45962306a36Sopenharmony_ci return; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci hpio = hpio_get(eid); 46262306a36Sopenharmony_ci if (!hpio) { 46362306a36Sopenharmony_ci free_eid(spc, eid); 46462306a36Sopenharmony_ci return; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci hpio->free_extent = hyperhold_free_extent; 46762306a36Sopenharmony_ci hpio_put(hpio); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_should_free_extent); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* 47262306a36Sopenharmony_ci * alloc hpio struct for r/w extent at @eid, will fill hpio with new alloced 47362306a36Sopenharmony_ci * pages if @new_page. @return NULL on fail. 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_cistruct hpio *hyperhold_io_alloc(u32 eid, gfp_t gfp, unsigned int op, bool new_page) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct hpio *hpio = NULL; 47862306a36Sopenharmony_ci struct hp_space *spc; 47962306a36Sopenharmony_ci u32 nr_page; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (!CHECK_ENABLE) 48262306a36Sopenharmony_ci return NULL; 48362306a36Sopenharmony_ci spc = space_of(eid); 48462306a36Sopenharmony_ci if (!CHECK(spc, "invalid eid %u!\n", eid)) 48562306a36Sopenharmony_ci return NULL; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci nr_page = spc->ext_size / PAGE_SIZE; 48862306a36Sopenharmony_ci hpio = hpio_alloc(nr_page, gfp, op, new_page); 48962306a36Sopenharmony_ci if (!hpio) 49062306a36Sopenharmony_ci goto err; 49162306a36Sopenharmony_ci hpio->eid = eid; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return hpio; 49462306a36Sopenharmony_cierr: 49562306a36Sopenharmony_ci hpio_free(hpio); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return NULL; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_alloc); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_civoid hyperhold_io_free(struct hpio *hpio) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci if (!CHECK_INITED) 50462306a36Sopenharmony_ci return; 50562306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 50662306a36Sopenharmony_ci return; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci hpio_free(hpio); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_free); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci/* 51362306a36Sopenharmony_ci * find exist read hpio of the extent @eid in iotab and inc its refcnt, 51462306a36Sopenharmony_ci * alloc a new hpio and insert it into iotab if there is no hpio for @eid 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_cistruct hpio *hyperhold_io_get(u32 eid, gfp_t gfp, unsigned int op) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct hp_space *spc = NULL; 51962306a36Sopenharmony_ci u32 nr_page; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (!CHECK_INITED) 52262306a36Sopenharmony_ci return NULL; 52362306a36Sopenharmony_ci spc = space_of(eid); 52462306a36Sopenharmony_ci if (!CHECK(spc, "invalid eid %u", eid)) 52562306a36Sopenharmony_ci return NULL; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci nr_page = spc->ext_size / PAGE_SIZE; 52862306a36Sopenharmony_ci return hpio_get_alloc(eid, nr_page, gfp, op); 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_get); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cibool hyperhold_io_put(struct hpio *hpio) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci if (!CHECK_INITED) 53562306a36Sopenharmony_ci return false; 53662306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 53762306a36Sopenharmony_ci return false; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return hpio_put(hpio); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_put); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/* 54462306a36Sopenharmony_ci * notify all threads waiting for this hpio 54562306a36Sopenharmony_ci */ 54662306a36Sopenharmony_civoid hyperhold_io_complete(struct hpio *hpio) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci if (!CHECK_INITED) 54962306a36Sopenharmony_ci return; 55062306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 55162306a36Sopenharmony_ci return; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci hpio_complete(hpio); 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_complete); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_civoid hyperhold_io_wait(struct hpio *hpio) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci if (!CHECK_INITED) 56062306a36Sopenharmony_ci return; 56162306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 56262306a36Sopenharmony_ci return; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci hpio_wait(hpio); 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_wait); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cibool hyperhold_io_success(struct hpio *hpio) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci if (!CHECK_INITED) 57162306a36Sopenharmony_ci return false; 57262306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 57362306a36Sopenharmony_ci return false; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return hpio_get_state(hpio) == HPIO_DONE; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_success); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ciint hyperhold_io_extent(struct hpio *hpio) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci if (!CHECK_INITED) 58262306a36Sopenharmony_ci return -EINVAL; 58362306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 58462306a36Sopenharmony_ci return -EINVAL; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci return hpio->eid; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_extent); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ciint hyperhold_io_operate(struct hpio *hpio) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci if (!CHECK_INITED) 59362306a36Sopenharmony_ci return -EINVAL; 59462306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 59562306a36Sopenharmony_ci return -EINVAL; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return hpio->op; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_operate); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistruct page *hyperhold_io_page(struct hpio *hpio, u32 index) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci if (!CHECK_INITED) 60462306a36Sopenharmony_ci return NULL; 60562306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 60662306a36Sopenharmony_ci return NULL; 60762306a36Sopenharmony_ci if (!CHECK_BOUND(index, 0, hpio->nr_page - 1)) 60862306a36Sopenharmony_ci return NULL; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return hpio->pages[index]; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_page); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cibool hyperhold_io_add_page(struct hpio *hpio, u32 index, struct page *page) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci if (!CHECK_INITED) 61762306a36Sopenharmony_ci return false; 61862306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 61962306a36Sopenharmony_ci return false; 62062306a36Sopenharmony_ci if (!CHECK(page, "page is null!\n")) 62162306a36Sopenharmony_ci return false; 62262306a36Sopenharmony_ci if (!CHECK_BOUND(index, 0, hpio->nr_page - 1)) 62362306a36Sopenharmony_ci return false; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci get_page(page); 62662306a36Sopenharmony_ci atomic64_add(PAGE_SIZE, &mem_used); 62762306a36Sopenharmony_ci BUG_ON(hpio->pages[index]); 62862306a36Sopenharmony_ci hpio->pages[index] = page; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci return true; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_add_page); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ciu32 hyperhold_io_nr_page(struct hpio *hpio) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci if (!CHECK_INITED) 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return hpio->nr_page; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_nr_page); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_civoid *hyperhold_io_private(struct hpio *hpio) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci if (!CHECK_INITED) 64862306a36Sopenharmony_ci return NULL; 64962306a36Sopenharmony_ci if (!CHECK(hpio, "hpio is null!\n")) 65062306a36Sopenharmony_ci return NULL; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci return hpio->private; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_io_private); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic struct page *get_encrypted_page(struct hp_device *dev, struct page *page, unsigned int op) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct page *encrypted_page = NULL; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (!dev->ctfm) { 66162306a36Sopenharmony_ci encrypted_page = page; 66262306a36Sopenharmony_ci get_page(encrypted_page); 66362306a36Sopenharmony_ci goto out; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci encrypted_page = alloc_page(GFP_NOIO); 66762306a36Sopenharmony_ci if (!encrypted_page) { 66862306a36Sopenharmony_ci pr_err("alloc encrypted page failed!\n"); 66962306a36Sopenharmony_ci goto out; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci encrypted_page->index = page->index; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* just alloc a new page for read */ 67462306a36Sopenharmony_ci if (!op_is_write(op)) 67562306a36Sopenharmony_ci goto out; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* encrypt page for write */ 67862306a36Sopenharmony_ci if (soft_crypt_page(dev->ctfm, encrypted_page, page, HP_DEV_ENCRYPT)) { 67962306a36Sopenharmony_ci put_page(encrypted_page); 68062306a36Sopenharmony_ci encrypted_page = NULL; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ciout: 68362306a36Sopenharmony_ci return encrypted_page; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic void put_encrypted_pages(struct bio *bio) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci struct bio_vec *bv = NULL; 68962306a36Sopenharmony_ci struct bvec_iter_all iter; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci bio_for_each_segment_all(bv, bio, iter) 69262306a36Sopenharmony_ci put_page(bv->bv_page); 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic void hp_endio_work(struct work_struct *work) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct hpio *hpio = container_of(work, struct hpio, endio_work); 69862306a36Sopenharmony_ci struct hp_device *dev = NULL; 69962306a36Sopenharmony_ci struct bio_vec *bv = NULL; 70062306a36Sopenharmony_ci struct bvec_iter_all iter; 70162306a36Sopenharmony_ci struct page *page = NULL; 70262306a36Sopenharmony_ci u32 ext_size; 70362306a36Sopenharmony_ci sector_t sec; 70462306a36Sopenharmony_ci int i; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (op_is_write(hpio->op)) 70762306a36Sopenharmony_ci goto endio; 70862306a36Sopenharmony_ci ext_size = space_of(hpio->eid)->ext_size; 70962306a36Sopenharmony_ci dev = device_of(hpio->eid); 71062306a36Sopenharmony_ci sec = hpio->eid * ext_size / dev->sec_size; 71162306a36Sopenharmony_ci i = 0; 71262306a36Sopenharmony_ci bio_for_each_segment_all(bv, hpio->bio, iter) { 71362306a36Sopenharmony_ci page = bv->bv_page; 71462306a36Sopenharmony_ci BUG_ON(i >= hpio->nr_page); 71562306a36Sopenharmony_ci BUG_ON(!hpio->pages[i]); 71662306a36Sopenharmony_ci if (dev->ctfm) 71762306a36Sopenharmony_ci BUG_ON(soft_crypt_page(dev->ctfm, hpio->pages[i], page, HP_DEV_DECRYPT)); 71862306a36Sopenharmony_ci sec += PAGE_SIZE / dev->sec_size; 71962306a36Sopenharmony_ci i++; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ciendio: 72262306a36Sopenharmony_ci put_encrypted_pages(hpio->bio); 72362306a36Sopenharmony_ci bio_put(hpio->bio); 72462306a36Sopenharmony_ci if (hpio->endio) 72562306a36Sopenharmony_ci hpio->endio(hpio); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic void hpio_endio(struct bio *bio) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct hpio *hpio = bio->bi_private; 73162306a36Sopenharmony_ci struct workqueue_struct *wq = NULL; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci pr_info("hpio %p for eid %u returned %d.\n", 73462306a36Sopenharmony_ci hpio, hpio->eid, bio->bi_status); 73562306a36Sopenharmony_ci hpio_set_state(hpio, bio->bi_status ? HPIO_FAIL : HPIO_DONE); 73662306a36Sopenharmony_ci wq = op_is_write(hpio->op) ? hyperhold.write_wq : hyperhold.read_wq; 73762306a36Sopenharmony_ci queue_work(wq, &hpio->endio_work); 73862306a36Sopenharmony_ci atomic64_sub(sizeof(struct bio), &mem_used); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int hpio_submit(struct hpio *hpio) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct hp_device *dev = NULL; 74462306a36Sopenharmony_ci struct bio *bio = NULL; 74562306a36Sopenharmony_ci struct page *page = NULL; 74662306a36Sopenharmony_ci u32 ext_size; 74762306a36Sopenharmony_ci sector_t sec; 74862306a36Sopenharmony_ci int i; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) 75162306a36Sopenharmony_ci dev = device_of(hpio->eid); 75262306a36Sopenharmony_ci bio = bio_alloc(dev->bdev, BIO_MAX_VECS, 75362306a36Sopenharmony_ci hpio->op, GFP_NOIO); 75462306a36Sopenharmony_ci#else 75562306a36Sopenharmony_ci bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES); 75662306a36Sopenharmony_ci#endif 75762306a36Sopenharmony_ci if (!bio) { 75862306a36Sopenharmony_ci pr_err("bio alloc failed!\n"); 75962306a36Sopenharmony_ci return -ENOMEM; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci atomic64_add(sizeof(struct bio), &mem_used); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) 76462306a36Sopenharmony_ci bio->bi_opf = hpio->op; 76562306a36Sopenharmony_ci#else 76662306a36Sopenharmony_ci dev = device_of(hpio->eid); 76762306a36Sopenharmony_ci bio_set_op_attrs(bio, hpio->op, 0); 76862306a36Sopenharmony_ci#endif 76962306a36Sopenharmony_ci bio_set_dev(bio, dev->bdev); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci ext_size = space_of(hpio->eid)->ext_size; 77262306a36Sopenharmony_ci sec = div_u64((u64)hpio->eid * ext_size, dev->sec_size); 77362306a36Sopenharmony_ci bio->bi_iter.bi_sector = sec; 77462306a36Sopenharmony_ci for (i = 0; i < hpio->nr_page; i++) { 77562306a36Sopenharmony_ci if (!hpio->pages[i]) 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci hpio->pages[i]->index = sec; 77862306a36Sopenharmony_ci page = get_encrypted_page(dev, hpio->pages[i], hpio->op); 77962306a36Sopenharmony_ci if (!page) 78062306a36Sopenharmony_ci goto err; 78162306a36Sopenharmony_ci if (!bio_add_page(bio, page, PAGE_SIZE, 0)) { 78262306a36Sopenharmony_ci put_page(page); 78362306a36Sopenharmony_ci goto err; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci sec += PAGE_SIZE / dev->sec_size; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (dev->blk_key) 78962306a36Sopenharmony_ci inline_crypt_bio(dev->blk_key, bio); 79062306a36Sopenharmony_ci bio->bi_private = hpio; 79162306a36Sopenharmony_ci bio->bi_end_io = hpio_endio; 79262306a36Sopenharmony_ci hpio->bio = bio; 79362306a36Sopenharmony_ci submit_bio(bio); 79462306a36Sopenharmony_ci pr_info("submit hpio %p for eid %u.\n", hpio, hpio->eid); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci return 0; 79762306a36Sopenharmony_cierr: 79862306a36Sopenharmony_ci put_encrypted_pages(bio); 79962306a36Sopenharmony_ci bio_put(bio); 80062306a36Sopenharmony_ci atomic64_sub(sizeof(struct bio), &mem_used); 80162306a36Sopenharmony_ci return -EIO; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic int rw_extent_async(struct hpio *hpio, hp_endio endio, void *priv, unsigned int op) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci int ret = 0; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (!hpio_change_state(hpio, HPIO_INIT, HPIO_SUBMIT)) 80962306a36Sopenharmony_ci return -EAGAIN; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci hpio->private = priv; 81262306a36Sopenharmony_ci hpio->endio = endio; 81362306a36Sopenharmony_ci INIT_WORK(&hpio->endio_work, hp_endio_work); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci ret = hpio_submit(hpio); 81662306a36Sopenharmony_ci if (ret) { 81762306a36Sopenharmony_ci hpio_set_state(hpio, HPIO_FAIL); 81862306a36Sopenharmony_ci hpio_complete(hpio); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return ret; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciint hyperhold_write_async(struct hpio *hpio, hp_endio endio, void *priv) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci if (!CHECK_ENABLE) { 82762306a36Sopenharmony_ci hpio_set_state(hpio, HPIO_FAIL); 82862306a36Sopenharmony_ci hpio_complete(hpio); 82962306a36Sopenharmony_ci return -EINVAL; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci BUG_ON(!op_is_write(hpio->op)); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci return rw_extent_async(hpio, endio, priv, REQ_OP_WRITE); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_write_async); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ciint hyperhold_read_async(struct hpio *hpio, hp_endio endio, void *priv) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci if (!CHECK_INITED) { 84162306a36Sopenharmony_ci hpio_set_state(hpio, HPIO_FAIL); 84262306a36Sopenharmony_ci hpio_complete(hpio); 84362306a36Sopenharmony_ci return -EINVAL; 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (op_is_write(hpio->op)) 84762306a36Sopenharmony_ci return -EAGAIN; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci return rw_extent_async(hpio, endio, priv, REQ_OP_READ); 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ciEXPORT_SYMBOL(hyperhold_read_async); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cimodule_init(hyperhold_init) 85462306a36Sopenharmony_cimodule_exit(hyperhold_exit) 855