From ce6533c4bd66eb3b3bed782b61a340521cabcfaa Mon Sep 17 00:00:00 2001 From: YangXin <245051644@qq.com> Date: Thu, 30 Sep 2021 22:57:41 +0800 Subject: [PATCH] Update etmem. Signed-off-by: YangXin <245051644@qq.com> --- 0003-update-README.md.patch | 82 + 0004-add-cslide-for-etmem.patch | 6484 +++++++++++++++++ 0005-fix-code-check-problems.patch | 256 + 0006-remove-unused-share-vmas-merge.patch | 240 + ...ix-error-when-open-idle_pages-failed.patch | 52 + 0008-fix-memleak.patch | 134 + ...at-occur-when-execute-obj-add-or-del.patch | 56 + 0010-clean-code.patch | 334 + ...riod-when-error-occurs-in-this-perio.patch | 111 + ...dd-recursive-in-etmemd_get_task_pids.patch | 110 + ...mission-according-cmd-to-be-executed.patch | 130 + ...y-only-replace-cold-mem-in-hot-nodes.patch | 300 + ...t-mig_quota-hot_reserve-to-0-INT_MAX.patch | 41 + 0016-add-some-dfx-info.patch | 122 + ...rocess-when-failed-to-delete-any-obj.patch | 73 + 0018-fix-code-check-warnning.patch | 41 + 0019-accept-review-advise.patch | 78 + 0020-revert-socket-permission-check.patch | 133 + 0021-add-thirdpart-engine.patch | 549 ++ ...s-for-user-defined-thirdparty-engine.patch | 321 + 0023-accept-review-advise.patch | 95 + 0024-correct-etmemd-name.patch | 194 + ...rt-for-systemctl-mode-to-start-etmem.patch | 243 + 0026-add-scan-library.patch | 524 ++ ...t-to-ignore-host-access-when-scan-vm.patch | 72 + 0028-openlog-with-same-ident.patch | 41 + 0029-accept-advise.patch | 139 + 0030-notify-rpc-success-with-finish-tag.patch | 157 + 0031-remove-node_watermark.patch | 131 + 0032-print-all-log-to-stdout.patch | 80 + 0033-accept-review-advise.patch | 49 + 0034-fix-open-swap_pages-failure.patch | 48 + ...e-the-correct-example-of-config-file.patch | 85 + ...if-start_task-is-NULL-before-call-it.patch | 26 + ...ct-max_threads-when-max_threads-is-0.patch | 26 + 0038-fix-etmem-help-return-error.patch | 25 + ...f-eng_mgt_func-is-NULL-before-use-it.patch | 30 + 0040-make-code-clean-for-etmem.patch | 302 + ...ror-if-migrate-failed-and-clean-code.patch | 64 + 0042-etmemd-fix-memleak-and-clean-code.patch | 59 + 0043-update-README.md.patch | 575 ++ 0044-etmem-cleancode.patch | 55 + 0045-add-dram_percent-to-etmem.patch | 520 ++ 0046-Fix-memory-leak-in-slide-engine.patch | 52 + etmem.spec | 46 + 45 files changed, 13285 insertions(+) create mode 100644 0003-update-README.md.patch create mode 100644 0004-add-cslide-for-etmem.patch create mode 100644 0005-fix-code-check-problems.patch create mode 100644 0006-remove-unused-share-vmas-merge.patch create mode 100644 0007-fix-error-when-open-idle_pages-failed.patch create mode 100644 0008-fix-memleak.patch create mode 100644 0009-fix-some-bugs-that-occur-when-execute-obj-add-or-del.patch create mode 100644 0010-clean-code.patch create mode 100644 0011-wait-for-next-period-when-error-occurs-in-this-perio.patch create mode 100644 0012-add-recursive-in-etmemd_get_task_pids.patch create mode 100644 0013-check-permission-according-cmd-to-be-executed.patch create mode 100644 0014-stat-pages-info-early-only-replace-cold-mem-in-hot-nodes.patch create mode 100644 0015-limit-mig_quota-hot_reserve-to-0-INT_MAX.patch create mode 100644 0016-add-some-dfx-info.patch create mode 100644 0017-do-not-stop-the-process-when-failed-to-delete-any-obj.patch create mode 100644 0018-fix-code-check-warnning.patch create mode 100644 0019-accept-review-advise.patch create mode 100644 0020-revert-socket-permission-check.patch create mode 100644 0021-add-thirdpart-engine.patch create mode 100644 0022-export-symbols-for-user-defined-thirdparty-engine.patch create mode 100644 0023-accept-review-advise.patch create mode 100644 0024-correct-etmemd-name.patch create mode 100644 0025-add-support-for-systemctl-mode-to-start-etmem.patch create mode 100644 0026-add-scan-library.patch create mode 100644 0027-add-ign_host-to-ignore-host-access-when-scan-vm.patch create mode 100644 0028-openlog-with-same-ident.patch create mode 100644 0029-accept-advise.patch create mode 100644 0030-notify-rpc-success-with-finish-tag.patch create mode 100644 0031-remove-node_watermark.patch create mode 100644 0032-print-all-log-to-stdout.patch create mode 100644 0033-accept-review-advise.patch create mode 100644 0034-fix-open-swap_pages-failure.patch create mode 100644 0035-give-the-correct-example-of-config-file.patch create mode 100644 0036-check-if-start_task-is-NULL-before-call-it.patch create mode 100644 0037-correct-max_threads-when-max_threads-is-0.patch create mode 100644 0038-fix-etmem-help-return-error.patch create mode 100644 0039-check-if-eng_mgt_func-is-NULL-before-use-it.patch create mode 100644 0040-make-code-clean-for-etmem.patch create mode 100644 0041-return-error-if-migrate-failed-and-clean-code.patch create mode 100644 0042-etmemd-fix-memleak-and-clean-code.patch create mode 100644 0043-update-README.md.patch create mode 100644 0044-etmem-cleancode.patch create mode 100644 0045-add-dram_percent-to-etmem.patch create mode 100644 0046-Fix-memory-leak-in-slide-engine.patch diff --git a/0003-update-README.md.patch b/0003-update-README.md.patch new file mode 100644 index 0000000..0df3bd4 --- /dev/null +++ b/0003-update-README.md.patch @@ -0,0 +1,82 @@ +From a8620c7e4e5ddb1123e97ed10c2f1bc0a6684d0d Mon Sep 17 00:00:00 2001 +From: louhongxiang +Date: Fri, 2 Apr 2021 11:29:02 +0800 +Subject: [PATCH 03/50] update README.md. + +--- + README.md | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/README.md b/README.md +index 54e28f9..3e2a50a 100644 +--- a/README.md ++++ b/README.md +@@ -4,15 +4,19 @@ + + 随着CPU算力的发展,尤其是ARM核成本的降低,内存成本和内存容量成为约束业务成本和性能的核心痛点,因此如何节省内存成本,如何扩大内存容量成为存储迫切要解决的问题。 + +-etmem内存垂直扩展技术,通过DRAM+内存压缩/高性能存储新介质形成多级内存存储,对内存数据进行分级,将分级后的内存冷数据从内存介质迁移到高性能存储介质中,达到内存容量扩展的目的,从而实现内存成本下降。 ++etmem内存分级扩展技术,通过DRAM+内存压缩/高性能存储新介质形成多级内存存储,对内存数据进行分级,将分级后的内存冷数据从内存介质迁移到高性能存储介质中,达到内存容量扩展的目的,从而实现内存成本下降。 + +-## 安装教程 ++## 编译教程 + + 1. 下载etmem源码 + +- $ git clone https://gitee.com/src-openeuler/etmem.git ++ $ git clone https://gitee.com/openeuler/etmem.git + +-2. 编译安装 ++2. 编译和运行依赖 ++ ++ etmem的编译和运行依赖于libboundscheck组件 ++ ++3. 编译 + + $ cd etmem + +@@ -24,7 +28,6 @@ etmem内存垂直扩展技术,通过DRAM+内存压缩/高性能存储新介质 + + $ make + +- $ make install + + ## 使用说明 + +@@ -56,7 +59,7 @@ options: + + 在运行etmem进程之前,需要管理员预先规划哪些进程需要做内存扩展,将进程信息配置到etmem配置文件中,并配置内存扫描的周期、扫描次数、内存冷热阈值等信息。 + +-配置文件的示例文件在安装etmem软件包后,放置在/etc/etmem/example_conf.yaml,示例内容为: ++配置文件的示例文件在源码包中,放置在源码根目录的conf/example_conf.yaml,建议在使用时放置在/etc/etmem/目录下,示例内容为: + + ``` + options: +@@ -100,7 +103,7 @@ options: + + #### 使用方法 + +-通过etmem二进制执行工程创建/删除/查询操作,前提是服务端已经成功运行,并且配置文件/etc/etmem/example_conf.yaml内容正确。 ++通过etmem二进制执行工程创建/删除/查询操作,前提是服务端已经成功运行,并且配置文件(e.g. /etc/etmem/example_conf.yaml)内容正确。 + + 添加工程: + +@@ -173,7 +176,7 @@ show命令: + + #### 使用方法 + +-通过etmem二进制执行任务启动/停止操作,前提是服务端已经成功运行,配置文件/etc/etmem/example_conf.yaml内容正确,且etmem工程已经创建。 ++通过etmem二进制执行任务启动/停止操作,前提是服务端已经成功运行,配置文件(e.g. /etc/etmem/example_conf.yaml)内容正确,且etmem工程已经创建。 + + 启动工程 + +@@ -213,4 +216,4 @@ Usage: + 1. Fork本仓库 + 2. 新建个人分支 + 3. 提交代码 +-4. 新建Pull Request +\ No newline at end of file ++4. 新建Pull Request +-- +2.27.0 + diff --git a/0004-add-cslide-for-etmem.patch b/0004-add-cslide-for-etmem.patch new file mode 100644 index 0000000..c53718b --- /dev/null +++ b/0004-add-cslide-for-etmem.patch @@ -0,0 +1,6484 @@ +From bf17dfb2b372f630f6f8ca1cbf6e6472c30bba46 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Tue, 6 Apr 2021 21:46:25 +0800 +Subject: [PATCH 04/50] add cslide for etmem + +Signed-off-by: Kemeng Shi +--- + CMakeLists.txt | 12 +- + inc/etmem_inc/etmem.h | 3 +- + inc/etmem_inc/etmem_common.h | 5 + + inc/etmem_inc/etmem_engine.h | 20 + + inc/etmem_inc/{etmem_task.h => etmem_obj.h} | 8 +- + inc/etmemd_inc/etmemd.h | 4 + + inc/etmemd_inc/etmemd_common.h | 6 +- + inc/etmemd_inc/etmemd_cslide.h | 23 + + inc/etmemd_inc/etmemd_engine.h | 51 +- + inc/etmemd_inc/etmemd_file.h | 30 +- + inc/etmemd_inc/etmemd_pool_adapter.h | 7 +- + inc/etmemd_inc/etmemd_project.h | 40 +- + inc/etmemd_inc/etmemd_rpc.h | 9 +- + inc/etmemd_inc/etmemd_scan.h | 10 + + inc/etmemd_inc/etmemd_slide.h | 3 +- + inc/etmemd_inc/etmemd_task.h | 17 +- + src/etmem_src/etmem.c | 64 +- + src/etmem_src/etmem_common.c | 18 +- + src/etmem_src/etmem_engine.c | 156 ++ + src/etmem_src/etmem_obj.c | 197 ++ + src/etmem_src/etmem_project.c | 90 +- + src/etmem_src/etmem_rpc.c | 64 +- + src/etmem_src/etmem_task.c | 161 -- + src/etmemd_src/etmemd_common.c | 53 +- + src/etmemd_src/etmemd_cslide.c | 2272 +++++++++++++++++++ + src/etmemd_src/etmemd_engine.c | 86 +- + src/etmemd_src/etmemd_file.c | 438 +--- + src/etmemd_src/etmemd_migrate.c | 2 +- + src/etmemd_src/etmemd_pool_adapter.c | 34 +- + src/etmemd_src/etmemd_project.c | 707 ++++-- + src/etmemd_src/etmemd_rpc.c | 143 +- + src/etmemd_src/etmemd_scan.c | 150 +- + src/etmemd_src/etmemd_slide.c | 186 +- + src/etmemd_src/etmemd_task.c | 146 +- + 34 files changed, 4047 insertions(+), 1168 deletions(-) + create mode 100644 inc/etmem_inc/etmem_engine.h + rename inc/etmem_inc/{etmem_task.h => etmem_obj.h} (89%) + create mode 100644 inc/etmemd_inc/etmemd_cslide.h + create mode 100644 src/etmem_src/etmem_engine.c + create mode 100644 src/etmem_src/etmem_obj.c + delete mode 100644 src/etmem_src/etmem_task.c + create mode 100644 src/etmemd_src/etmemd_cslide.c + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index a4a83ca..fa64b89 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -32,6 +32,7 @@ set(ETMEMD_SRC + ${ETMEMD_SRC_DIR}/etmemd_project.c + ${ETMEMD_SRC_DIR}/etmemd_engine.c + ${ETMEMD_SRC_DIR}/etmemd_slide.c ++ ${ETMEMD_SRC_DIR}/etmemd_cslide.c + ${ETMEMD_SRC_DIR}/etmemd_task.c + ${ETMEMD_SRC_DIR}/etmemd_scan.c + ${ETMEMD_SRC_DIR}/etmemd_threadpool.c +@@ -42,7 +43,8 @@ set(ETMEMD_SRC + set(ETMEM_SRC + ${ETMEM_SRC_DIR}/etmem.c + ${ETMEM_SRC_DIR}/etmem_project.c +- ${ETMEM_SRC_DIR}/etmem_task.c ++ ${ETMEM_SRC_DIR}/etmem_obj.c ++ ${ETMEM_SRC_DIR}/etmem_engine.c + ${ETMEM_SRC_DIR}/etmem_rpc.c + ${ETMEM_SRC_DIR}/etmem_common.c) + +@@ -54,8 +56,12 @@ add_executable(etmem + + set(EXECUTABLE_OUTPUT_PATH ${BUILD_DIR}/bin) + ++include(FindPkgConfig) ++pkg_search_module(GLIB2 REQUIRED glib-2.0) ++ + target_include_directories(etmemd PRIVATE +- ${PROJECT_SOURCE_DIR}/inc/etmemd_inc) ++ ${PROJECT_SOURCE_DIR}/inc/etmemd_inc ++ ${GLIB2_INCLUDE_DIRS}) + + target_include_directories(etmem PRIVATE + ${PROJECT_SOURCE_DIR}/inc/etmem_inc) +@@ -68,7 +74,7 @@ if(CONFIG_DEBUG STREQUAL "y") + endif() + + set_target_properties(etmemd PROPERTIES LINK_FLAGS "-s -fPIE -pie -fPIC -Wl,-z,relro,-z,now,-z,noexecstack -Wtrampolines") +-target_link_libraries(etmemd PRIVATE pthread dl rt boundscheck) ++target_link_libraries(etmemd PRIVATE pthread dl rt boundscheck numa ${GLIB2_LIBRARIES}) + + if( ${ARCHITECTURE} STREQUAL "aarch64" ) + target_compile_options(etmemd PRIVATE -march=armv8-a) +diff --git a/inc/etmem_inc/etmem.h b/inc/etmem_inc/etmem.h +index 8d7b615..47979a2 100644 +--- a/inc/etmem_inc/etmem.h ++++ b/inc/etmem_inc/etmem.h +@@ -24,6 +24,7 @@ typedef enum etmem_cmd_e { + ETMEM_CMD_START, + ETMEM_CMD_STOP, + ETMEM_CMD_SHOW, ++ ETMEM_CMD_ENGINE, + ETMEM_CMD_HELP, + } etmem_cmd; + +@@ -37,7 +38,7 @@ struct etmem_conf { + struct etmem_obj { + char *name; + void (*help)(void); +- int (*do_cmd)(const struct etmem_conf *conf); ++ int (*do_cmd)(struct etmem_conf *conf); + + SLIST_ENTRY(etmem_obj) entry; + }; +diff --git a/inc/etmem_inc/etmem_common.h b/inc/etmem_inc/etmem_common.h +index 9725c87..294d216 100644 +--- a/inc/etmem_inc/etmem_common.h ++++ b/inc/etmem_inc/etmem_common.h +@@ -24,11 +24,16 @@ + #define FILE_NAME_MAX_LEN 256 + #define SOCKET_NAME_MAX_LEN 107 + ++#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) ++ + struct mem_proj { + etmem_cmd cmd; + char *proj_name; ++ char *eng_name; ++ char *task_name; + char *file_name; + char *sock_name; ++ char *eng_cmd; + }; + + int parse_name_string(const char *val, char **name_str, size_t max_len); +diff --git a/inc/etmem_inc/etmem_engine.h b/inc/etmem_inc/etmem_engine.h +new file mode 100644 +index 0000000..6d1ca14 +--- /dev/null ++++ b/inc/etmem_inc/etmem_engine.h +@@ -0,0 +1,20 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: louhongxiang ++ * Create: 2019-12-10 ++ * Description: This is a header file of the data structure definition for etmem engine function. ++ ******************************************************************************/ ++ ++#ifndef __ETMEM_ENGINE_H__ ++#define __ETMEM_ENGINE_H__ ++void engine_init(void); ++void engine_exit(void); ++#endif +diff --git a/inc/etmem_inc/etmem_task.h b/inc/etmem_inc/etmem_obj.h +similarity index 89% +rename from inc/etmem_inc/etmem_task.h +rename to inc/etmem_inc/etmem_obj.h +index aa8f218..635b6b3 100644 +--- a/inc/etmem_inc/etmem_task.h ++++ b/inc/etmem_inc/etmem_obj.h +@@ -13,10 +13,10 @@ + * Description: This is a header file of the function declaration for migration functions. + ******************************************************************************/ + +-#ifndef __ETMEM_TASK_H__ +-#define __ETMEM_TASK_H__ ++#ifndef __ETMEM_OBJ_H__ ++#define __ETMEM_OBJ_H__ + +-void migrate_init(void); +-void migrate_exit(void); ++void obj_init(void); ++void obj_exit(void); + + #endif +diff --git a/inc/etmemd_inc/etmemd.h b/inc/etmemd_inc/etmemd.h +index ed29d44..797049e 100644 +--- a/inc/etmemd_inc/etmemd.h ++++ b/inc/etmemd_inc/etmemd.h +@@ -19,6 +19,10 @@ + #include + #include + ++#define PTE_SIZE_SHIFT 12 ++#define PMD_SIZE_SHIFT 21 ++#define PUD_SIZE_SHIFT 30 ++ + /* + * page type specified by size + * */ +diff --git a/inc/etmemd_inc/etmemd_common.h b/inc/etmemd_inc/etmemd_common.h +index 2fe8a73..1b62bbd 100644 +--- a/inc/etmemd_inc/etmemd_common.h ++++ b/inc/etmemd_inc/etmemd_common.h +@@ -25,6 +25,8 @@ + #define DECIMAL_RADIX 10 + #define ETMEMD_MAX_PARAMETER_NUM 5 + ++#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) ++ + /* + * function: parse cmdline passed to etmemd server. + * +@@ -43,7 +45,7 @@ int get_int_value(const char *val, int *value); + int get_unsigned_int_value(const char *val, unsigned int *value); + void etmemd_safe_free(void **ptr); + +-FILE *etmemd_get_proc_file(const char *pid, const char *file, const char *mode); ++FILE *etmemd_get_proc_file(const char *pid, const char *file, int flags, const char *mode); + + int get_keyword_and_value(const char *str, char *key, char *val); + +@@ -56,4 +58,6 @@ int get_keyword_and_value(const char *str, char *key, char *val); + * */ + char *skip_blank_line(FILE *file); + ++int dprintf_all(int fd, const char *format, ...); ++ + #endif +diff --git a/inc/etmemd_inc/etmemd_cslide.h b/inc/etmemd_inc/etmemd_cslide.h +new file mode 100644 +index 0000000..2405f2d +--- /dev/null ++++ b/inc/etmemd_inc/etmemd_cslide.h +@@ -0,0 +1,23 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: louhongxiang ++ * Create: 2019-12-10 ++ * Description: This is a header file of the function declaration for cslide function. ++ ******************************************************************************/ ++ ++#ifndef ETMEMD_CSLIDE_H ++#define ETMEMD_CSLIDE_H ++ ++#include "etmemd_engine.h" ++ ++int fill_engine_type_cslide(struct engine *eng); ++ ++#endif +diff --git a/inc/etmemd_inc/etmemd_engine.h b/inc/etmemd_inc/etmemd_engine.h +index 13d676c..77916a5 100644 +--- a/inc/etmemd_inc/etmemd_engine.h ++++ b/inc/etmemd_inc/etmemd_engine.h +@@ -16,11 +16,13 @@ + #ifndef ETMEMD_ENGINE_H + #define ETMEMD_ENGINE_H + ++#include + #include "etmemd.h" + #include "etmemd_task.h" + + enum eng_type { + SLIDE_ENGINE = 0, ++ CSLIDE_ENGINE, + DYNAMIC_FB_ENGINE, + HISTORICAL_FB_ENGINE, + THIRDPARTY_ENGINE, +@@ -32,44 +34,29 @@ enum eng_type { + * */ + struct engine { + int engine_type; /* engine type used for elimination strategy */ ++ char *name; + void *params; /* point to engine parameter struct */ +- void *task; /* point to task this engine belongs to */ ++ struct project *proj; + struct page_refs *page_ref; /* scan result */ ++ struct engine_ops *ops; ++ struct task *tasks; + uint64_t page_cnt; /* number of pages */ +- struct adapter *adp; /* configured migration strategy */ +- +- /* parse parameter configuration */ +- int (*parse_param_conf)(struct engine *eng, FILE *file); +- +- /* migrate policy function */ +- struct memory_grade *(*mig_policy_func)(struct page_refs **page_refs, void *params); +- +- /* alloc tkpid params space based on different policies. */ +- int (*alloc_params)(struct task_pid **tk_pid); +-}; +- +-/* +- * adapter struct +- * */ +-struct adapter { +- /* scan function */ +- struct page_refs *(*do_scan)(const struct task_pid *tpid, const struct task *tk); +- +- /* migrate function */ +- int (*do_migrate)(unsigned int pid, const struct memory_grade *memory_grade); +-}; +- +-struct engine_item { +- enum eng_type eng_type; +- int (*fill_eng_func)(struct engine *eng); ++ struct engine *next; + }; + +-struct engine_private_item { +- char *priv_sec_name; +- int (*fill_eng_private_func)(const struct engine *eng, const char *val); ++struct engine_ops { ++ int (*fill_eng_params)(GKeyFile *config, struct engine *eng); ++ void (*clear_eng_params)(struct engine *eng); ++ int (*fill_task_params)(GKeyFile *config, struct task *task); ++ void (*clear_task_params)(struct task *tk); ++ int (*start_task)(struct engine *eng, struct task *tk); ++ void (*stop_task)(struct engine *eng, struct task *tk); ++ int (*alloc_pid_params)(struct engine *eng, struct task_pid **tk_pid); ++ void (*free_pid_params)(struct engine *eng, struct task_pid **tk_pid); ++ int (*eng_mgt_func)(struct engine *eng, struct task *tk, char *cmd, int fd); + }; + +-const char *etmemd_get_eng_name(enum eng_type type); ++struct engine *etmemd_engine_add(GKeyFile *config); ++void etmemd_engine_remove(struct engine *eng); + +-int fill_engine_type(struct engine *eng, const char *val); + #endif +diff --git a/inc/etmemd_inc/etmemd_file.h b/inc/etmemd_inc/etmemd_file.h +index a251d1b..34ccaf9 100644 +--- a/inc/etmemd_inc/etmemd_file.h ++++ b/inc/etmemd_inc/etmemd_file.h +@@ -17,23 +17,31 @@ + #define ETMEMD_FILE_H + + #include ++#include + #include "etmemd_project.h" + #include "etmemd_task.h" + +-struct project_item { +- char *proj_sec_name; +- int (*fill_proj_func)(struct project *proj, const char *val); +- bool optional; +- bool set; ++#define PROJ_GROUP "project" ++#define ENG_GROUP "engine" ++#define TASK_GROUP "task" ++ ++enum val_type { ++ INT_VAL, ++ STR_VAL, + }; + +-struct task_item { +- char *task_sec_name; +- int (*fill_task_func)(struct task *tk, const char *val); +- bool optional; +- bool set; ++struct config_item { ++ char *key; ++ enum val_type type; ++ int (*fill)(void *obj, void *val); ++ bool option; + }; + +-int etmemd_fill_proj_by_conf(struct project *proj, FILE *conf_file); ++int parse_file_config(GKeyFile *config, char *group_name, struct config_item *items, unsigned n, void *obj); ++ ++static inline int parse_to_int(void *val) ++{ ++ return (int)(long long)val; ++} + + #endif +diff --git a/inc/etmemd_inc/etmemd_pool_adapter.h b/inc/etmemd_inc/etmemd_pool_adapter.h +index 7448b50..3cb7b2a 100644 +--- a/inc/etmemd_inc/etmemd_pool_adapter.h ++++ b/inc/etmemd_inc/etmemd_pool_adapter.h +@@ -21,10 +21,15 @@ + #include "etmemd_project.h" + #include "etmemd_log.h" + ++struct task_executor { ++ struct task *tk; ++ void *(*func)(void *arg); ++}; ++ + /* + * Start process scanning and memory migration + * */ +-int start_threadpool_work(struct task *tk); ++int start_threadpool_work(struct task_executor *executor); + + /* + * Stop process and cleanup resource of scanning and memory migration +diff --git a/inc/etmemd_inc/etmemd_project.h b/inc/etmemd_inc/etmemd_project.h +index da929b4..d15c7fd 100644 +--- a/inc/etmemd_inc/etmemd_project.h ++++ b/inc/etmemd_inc/etmemd_project.h +@@ -18,6 +18,7 @@ + + #include + #include "etmemd_task.h" ++#include "etmemd_engine.h" + + /* set the length of project name to 32 */ + #define PROJECT_NAME_MAX_LEN 32 +@@ -25,12 +26,12 @@ + #define PROJECT_SHOW_COLM_MAX 128 + + struct project { +- bool start; ++ char *name; + int interval; + int loop; + int sleep; +- char *name; +- struct task *tasks; ++ bool start; ++ struct engine *engs; + + SLIST_ENTRY(project) entry; + }; +@@ -42,6 +43,10 @@ enum opt_result { + OPT_PRO_STARTED, + OPT_PRO_STOPPED, + OPT_PRO_NOEXIST, ++ OPT_ENG_EXISTED, ++ OPT_ENG_NOEXIST, ++ OPT_TASK_EXISTED, ++ OPT_TASK_NOEXIST, + OPT_INTER_ERR, + OPT_RET_END, + }; +@@ -49,32 +54,33 @@ enum opt_result { + /* + * function: Add project to etmem server. + * +- * in: const char *project_name - name of the project to be added +- * const char *file_name - name of the project configuration file ++ * in: GKeyFile *config - loaded config file + * +- * out: OPT_SUCCESS(0) - successed to add project +- * other value - failed to add project ++ * out: OPT_SUCCESS(0) - successed to add project ++ * other value - failed to add project + * */ +-enum opt_result etmemd_project_add(const char *project_name, const char *file_name); ++enum opt_result etmemd_project_add(GKeyFile *config); + + /* +- * function: Delete given project. ++ * function: Remove given project. + * +- * in: const char *project_name - name of the project to be deleted ++ * in: GKeyFile *config - loaded config file + * +- * out: OPT_SUCCESS(0) - successed to delete project +- * other value - failed to delete project ++ * out: OPT_SUCCESS(0) - successed to delete project ++ * other value - failed to delete project + * */ +-enum opt_result etmemd_project_delete(const char *project_name); ++enum opt_result etmemd_project_remove(GKeyFile *config); + + /* + * function: Show all the projects. + * ++ * in: const char *project_name - name of the project to start migrate ++ * int fd - client socket to show projects info + * + * out: OPT_SUCCESS(0) - successed to show all the projects + * other value - failed to show any project + * */ +-enum opt_result etmemd_project_show(void); ++enum opt_result etmemd_project_show(const char *project_name, int fd); + + /* + * function: Start migrate in given project. +@@ -96,6 +102,12 @@ enum opt_result etmemd_migrate_start(const char *project_name); + * */ + enum opt_result etmemd_migrate_stop(const char *project_name); + ++enum opt_result etmemd_project_mgt_engine(const char *project_name, const char *eng_name, char *cmd, char *task_name, int sock_fd); ++enum opt_result etmemd_project_add_engine(GKeyFile *config); ++enum opt_result etmemd_project_remove_engine(GKeyFile *config); ++enum opt_result etmemd_project_add_task(GKeyFile *config); ++enum opt_result etmemd_project_remove_task(GKeyFile *config); ++ + void etmemd_stop_all_projects(void); + + #endif +diff --git a/inc/etmemd_inc/etmemd_rpc.h b/inc/etmemd_inc/etmemd_rpc.h +index ff27494..146cec3 100644 +--- a/inc/etmemd_inc/etmemd_rpc.h ++++ b/inc/etmemd_inc/etmemd_rpc.h +@@ -19,11 +19,12 @@ + #include + + enum cmd_type { +- PROJ_ADD = 0, +- PROJ_DEL, ++ OBJ_ADD = 0, ++ OBJ_DEL, + MIG_START, + MIG_STOP, + PROJ_SHOW, ++ ENG_CMD, + }; + + enum rpc_decode_type { +@@ -36,6 +37,10 @@ struct server_rpc_params { + char *proj_name; + char *file_name; + int cmd; ++ int sock_fd; ++ char *eng_name; ++ char *eng_cmd; ++ char *task_name; + }; + + struct server_rpc_parser { +diff --git a/inc/etmemd_inc/etmemd_scan.h b/inc/etmemd_inc/etmemd_scan.h +index 9ae387e..ed72e1a 100644 +--- a/inc/etmemd_inc/etmemd_scan.h ++++ b/inc/etmemd_inc/etmemd_scan.h +@@ -16,6 +16,7 @@ + #ifndef ETMEMD_SCAN_H + #define ETMEMD_SCAN_H + ++#include + #include "etmemd.h" + #include "etmemd_task.h" + +@@ -31,6 +32,11 @@ + #define MAPS_FILE "/maps" + #define IDLE_SCAN_FILE "/idle_pages" + ++#define SMAPS_FILE "/smaps" ++#define VMFLAG_HEAD "VmFlags" ++ ++#define SCAN_AS_HUGE O_LARGEFILE ++ + enum { + VMA_STAT_READ = 0, + VMA_STAT_WRITE, +@@ -100,8 +106,11 @@ struct page_refs *etmemd_do_scan(const struct task_pid *tpid, const struct task + /* free vma list struct */ + void free_vmas(struct vmas *vmas); + ++struct page_refs **walk_vmas(int fd, struct walk_address *walk_address, struct page_refs **pf, unsigned long *use_rss); + int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **page_refs, unsigned long *use_rss); + ++int split_vmflags(char ***vmflags_array, char *vmflags); ++struct vmas *get_vmas_with_flags(const char *pid, char **vmflags_array, int vmflags_num, bool is_anon_only); + struct vmas *get_vmas(const char *pid); + + void clean_page_refs_unexpected(void *arg); +@@ -110,4 +119,5 @@ void clean_memory_grade_unexpected(void *arg); + + struct page_refs *add_page_refs_into_memory_grade(struct page_refs *page_refs, struct page_refs **list); + int init_g_page_size(void); ++int page_type_to_size(enum page_type type); + #endif +diff --git a/inc/etmemd_inc/etmemd_slide.h b/inc/etmemd_inc/etmemd_slide.h +index e95438d..e76e97a 100644 +--- a/inc/etmemd_inc/etmemd_slide.h ++++ b/inc/etmemd_inc/etmemd_slide.h +@@ -16,10 +16,11 @@ + #ifndef ETMEMD_SLIDE_H + #define ETMEMD_SLIDE_H + +- ++#include "etmemd_pool_adapter.h" + #include "etmemd_engine.h" + + struct slide_params { ++ struct task_executor *executor; + int t; /* watermark */ + }; + +diff --git a/inc/etmemd_inc/etmemd_task.h b/inc/etmemd_inc/etmemd_task.h +index b7fba2b..d6d89ea 100644 +--- a/inc/etmemd_inc/etmemd_task.h ++++ b/inc/etmemd_inc/etmemd_task.h +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include "etmemd_threadpool.h" + #include "etmemd_threadtimer.h" + +@@ -37,20 +38,16 @@ struct task_pid { + struct task { + char *type; + char *value; ++ char *name; + uint64_t max_threads; + +- struct project *proj; +- struct engine *eng; + struct task_pid *pids; ++ struct engine *eng; ++ void *params; + pthread_t task_pt; + timer_thread *timer_inst; + thread_pool *threadpool_inst; + +- int (*start_etmem)(struct task *tk); +- void (*stop_etmem)(struct task *tk); +- void (*delete_etmem)(struct task *tk); +- void *(*workflow_engine)(void *); +- + struct task *next; + }; + +@@ -64,5 +61,9 @@ void etmemd_free_task_struct(struct task **tk); + + void free_task_pid_mem(struct task_pid **tk_pid); + +-void etmemd_print_tasks(const struct task *tk); ++void etmemd_print_tasks(int fd, const struct task *tk, char *engine_name, bool started); ++ ++struct task *etmemd_add_task(GKeyFile *config); ++void etmemd_remove_task(struct task *tk); ++ + #endif +diff --git a/src/etmem_src/etmem.c b/src/etmem_src/etmem.c +index 8bd171c..863f91b 100644 +--- a/src/etmem_src/etmem.c ++++ b/src/etmem_src/etmem.c +@@ -19,8 +19,9 @@ + #include + #include "securec.h" + #include "etmem.h" +-#include "etmem_task.h" ++#include "etmem_obj.h" + #include "etmem_project.h" ++#include "etmem_engine.h" + + #define CMD_POSITION 1 + +@@ -65,53 +66,10 @@ static int check_param(int argc, char *argv[], struct etmem_conf *conf, + return -1; + } + +- return 0; +-} +- +-static void fill_cmd_type(struct etmem_conf *conf, const int val) +-{ +- conf->cmd = val; +-} +- +-struct cmd_item { +- char *cmd_name; +- enum etmem_cmd_e cmd; +- void (*fill_cmd_func)(struct etmem_conf *conf, const int val); +-}; +- +-struct cmd_item g_cmd_items[] = { +- {"add", ETMEM_CMD_ADD, fill_cmd_type}, +- {"del", ETMEM_CMD_DEL, fill_cmd_type}, +- {"start", ETMEM_CMD_START, fill_cmd_type}, +- {"stop", ETMEM_CMD_STOP, fill_cmd_type}, +- {"show", ETMEM_CMD_SHOW, fill_cmd_type}, +- {"help", ETMEM_CMD_HELP, fill_cmd_type}, +- {NULL, 0, NULL}, +-}; +- +-static int parse_command(int argc, char *argv[], struct etmem_conf *conf, +- const struct etmem_obj *obj) +-{ +- int ret = -1; +- int i = 0; +- +- while (g_cmd_items[i].cmd_name != NULL) { +- if (strcmp(argv[CMD_POSITION], g_cmd_items[i].cmd_name) == 0) { +- g_cmd_items[i].fill_cmd_func(conf, (int)g_cmd_items[i].cmd); +- ret = 0; +- break; +- } +- i++; +- } +- +- if (ret != 0) { +- printf("invalid command %s\n", argv[CMD_POSITION]); +- obj->help(); +- return -1; +- } +- +- conf->argc = argc - CMD_POSITION; +- conf->argv = argv + CMD_POSITION; ++ argc--; ++ argv++; ++ conf->argc = argc; ++ conf->argv = argv; + + return 0; + } +@@ -139,7 +97,7 @@ static int parse_args(int argc, char *argv[], struct etmem_conf *conf, + return -EINVAL; + } + +- return parse_command(argc, argv, conf, *obj); ++ return 0; + } + + void etmem_register_obj(struct etmem_obj *obj) +@@ -162,7 +120,8 @@ int main(int argc, char *argv[]) + + SLIST_INIT(&g_etmem_objs); + project_init(); +- migrate_init(); ++ obj_init(); ++ engine_init(); + + if (parse_args(argc, argv, &conf, &obj) != 0) { + if (conf.obj != NULL && strcmp(conf.obj, "help") == 0 && +@@ -173,7 +132,7 @@ int main(int argc, char *argv[]) + goto out; + } + +- if (conf.cmd == ETMEM_CMD_HELP) { ++ if (strcmp(conf.argv[0], "help") == 0) { + obj->help(); + err = 0; + goto out; +@@ -187,7 +146,8 @@ int main(int argc, char *argv[]) + } + + out: ++ engine_exit(); ++ obj_exit(); + project_exit(); +- migrate_exit(); + return err; + } +diff --git a/src/etmem_src/etmem_common.c b/src/etmem_src/etmem_common.c +index 9725db7..65d3690 100644 +--- a/src/etmem_src/etmem_common.c ++++ b/src/etmem_src/etmem_common.c +@@ -60,7 +60,7 @@ int parse_name_string(const char *val, char **name_str, size_t max_len) + int etmem_parse_check_result(int params_cnt, int argc) + { + if (params_cnt > 0 && argc - 1 > params_cnt * 2) { /* maximum number of args is limited to params_cnt * 2+1 */ +- printf("warn: useless parameters passed in\n"); ++ printf("warn: etmem useless parameters passed in\n"); + return -E2BIG; + } + +@@ -83,6 +83,22 @@ void free_proj_member(struct mem_proj *proj) + free(proj->sock_name); + proj->sock_name = NULL; + } ++ ++ if (proj->eng_name != NULL) { ++ free(proj->eng_name); ++ proj->eng_name = NULL; ++ } ++ ++ if (proj->task_name != NULL) { ++ free(proj->task_name); ++ proj->task_name = NULL; ++ } ++ ++ if (proj->eng_cmd != NULL) { ++ free(proj->eng_cmd); ++ proj->eng_cmd = NULL; ++ } ++ + } + + +diff --git a/src/etmem_src/etmem_engine.c b/src/etmem_src/etmem_engine.c +new file mode 100644 +index 0000000..7673205 +--- /dev/null ++++ b/src/etmem_src/etmem_engine.c +@@ -0,0 +1,156 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: louhongxiang ++ * Create: 2021-4-13 ++ * Description: engine operation for etmem client ++ ******************************************************************************/ ++ ++#include ++#include ++#include "etmem_engine.h" ++#include "securec.h" ++#include "etmem.h" ++#include "etmem_common.h" ++#include "etmem_rpc.h" ++ ++static void engine_help(void) ++{ ++ printf("etmem engine help information\n"); ++} ++ ++static int engine_parse_cmd(struct etmem_conf *conf, struct mem_proj *proj) ++{ ++ if (conf->argc == 0) { ++ printf("too few params for etmem client engine command\n"); ++ return -1; ++ } ++ proj->eng_cmd = conf->argv[0]; ++ proj->cmd = ETMEM_CMD_ENGINE; ++ return 0; ++} ++ ++static int engine_parse_args(struct etmem_conf *conf, struct mem_proj *proj) ++{ ++ int opt; ++ int params_cnt = 0; ++ int ret; ++ struct option opts[] = { ++ {"proj_name", required_argument, NULL,'n'}, ++ {"socket", required_argument, NULL,'s'}, ++ {"engine", required_argument, NULL,'e'}, ++ {"task_name", required_argument, NULL,'t'}, ++ {NULL, 0, NULL,0}, ++ }; ++ ++ while ((opt = getopt_long(conf->argc, conf->argv, "n:s:e:t:", opts, NULL)) != -1) { ++ switch (opt) { ++ case 'n': ++ proj->proj_name = optarg; ++ break; ++ ++ case 's': ++ proj->sock_name = optarg; ++ break; ++ ++ case 'e': ++ proj->eng_name = optarg; ++ break; ++ ++ case 't': ++ proj->task_name = optarg; ++ break; ++ ++ case '?': ++ /* fallthrough */ ++ default: ++ printf("invalid options: %s\n", conf->argv[optind]); ++ return -EINVAL; ++ } ++ params_cnt++; ++ ++ } ++ ret = etmem_parse_check_result(params_cnt, conf->argc); ++ return ret; ++} ++ ++static int engine_check_params(struct mem_proj *proj) ++{ ++ if (proj->sock_name == NULL || strlen(proj->sock_name) == 0) { ++ printf("socket name to connect must be given, please check.\n"); ++ return -1; ++ } ++ ++ if (proj->proj_name == NULL || strlen(proj->proj_name) == 0) { ++ printf("project name must be given, please check.\n"); ++ return -1; ++ } ++ ++ if (proj->eng_cmd == NULL || strlen(proj->eng_cmd) == 0) { ++ printf("engine command must be given, please check.\n"); ++ return -1; ++ } ++ ++ if (proj->eng_name == NULL || strlen(proj->eng_name) == 0) { ++ printf("engine name must be given, please check.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int engine_do_cmd(struct etmem_conf *conf) ++{ ++ struct mem_proj proj; ++ int ret; ++ ++ ret = memset_s(&proj, sizeof(struct mem_proj), 0, sizeof(struct mem_proj)); ++ if (ret != EOK) { ++ printf("memset_s for mem_proj fail\n"); ++ return ret; ++ } ++ ++ ret = engine_parse_cmd(conf, &proj); ++ if (ret != 0) { ++ printf("engine_parse_cmd fail\n"); ++ return -1; ++ } ++ ++ ret = engine_parse_args(conf, &proj); ++ if (ret != 0) { ++ printf("engine_parse_args fail\n"); ++ return -1; ++ } ++ ++ ret = engine_check_params(&proj); ++ if (ret != 0) { ++ printf("engine_check_params fail\n"); ++ return -1; ++ } ++ ++ ret = etmem_rpc_client(&proj); ++ return ret; ++} ++ ++static struct etmem_obj g_etmem_engine = { ++ .name = "engine", ++ .help = engine_help, ++ .do_cmd = engine_do_cmd, ++}; ++ ++void engine_init(void) ++{ ++ etmem_register_obj(&g_etmem_engine); ++} ++ ++void engine_exit(void) ++{ ++ etmem_unregister_obj(&g_etmem_engine); ++} +diff --git a/src/etmem_src/etmem_obj.c b/src/etmem_src/etmem_obj.c +new file mode 100644 +index 0000000..a3f66fe +--- /dev/null ++++ b/src/etmem_src/etmem_obj.c +@@ -0,0 +1,197 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: louhongxiang ++ * Create: 2021-4-14 ++ * Description: etmem obj command API. ++ ******************************************************************************/ ++ ++#include ++#include "securec.h" ++#include "etmem.h" ++#include "etmem_common.h" ++#include "etmem_rpc.h" ++#include "etmem_obj.h" ++ ++static void obj_help(void) ++{ ++ printf("\nUsage:\n" ++ " etmem obj add [options]\n" ++ " etmem obj del [options]\n" ++ " etmem obj help [options]\n" ++ "\nOptions:\n" ++ " -f|--file Add configuration file\n" ++ " -s|--socket Socket name to connect\n" ++ "\nNotes:\n" ++ " 1. Configuration file must be given.\n" ++ " 2. Socket name must be given.\n"); ++} ++ ++struct obj_cmd_item { ++ char *cmd_name; ++ enum etmem_cmd_e cmd; ++}; ++ ++static struct obj_cmd_item g_obj_cmd_items[] = { ++ {"add", ETMEM_CMD_ADD}, ++ {"del", ETMEM_CMD_DEL}, ++}; ++ ++static int obj_parse_cmd(struct etmem_conf *conf, struct mem_proj *proj) ++{ ++ unsigned i; ++ char *cmd = NULL; ++ ++ cmd = conf->argv[0]; ++ for (i = 0; i < ARRAY_SIZE(g_obj_cmd_items); i++) { ++ if (strcmp(cmd, g_obj_cmd_items[i].cmd_name) == 0) { ++ proj->cmd = g_obj_cmd_items[i].cmd; ++ return 0; ++ } ++ } ++ ++ printf("obj cmd %s is not supportted.\n", cmd); ++ return -1; ++} ++ ++static int parse_file_name(const char *val, char **file_name) ++{ ++ size_t len; ++ int ret; ++ ++ len = strlen(val) + 1; ++ if (len > FILE_NAME_MAX_LEN) { ++ printf("file name is too long, should not be larger than %u\n", FILE_NAME_MAX_LEN); ++ return -ENAMETOOLONG; ++ } ++ ++ *file_name = (char *)calloc(len, sizeof(char)); ++ if (*file_name == NULL) { ++ printf("malloc file name failed\n"); ++ return -ENOMEM; ++ } ++ ++ ret = strncpy_s(*file_name, len, val, len - 1); ++ if (ret != EOK) { ++ printf("strncpy_s file name fail\n"); ++ free(*file_name); ++ *file_name = NULL; ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int obj_parse_args(struct etmem_conf *conf, struct mem_proj *proj) ++{ ++ int opt, ret; ++ int params_cnt = 0; ++ struct option opts[] = { ++ {"file", required_argument, NULL, 'f'}, ++ {"socket", required_argument, NULL, 's'}, ++ {NULL, 0, NULL, 0}, ++ }; ++ ++ while ((opt = getopt_long(conf->argc, conf->argv, "f:s:", opts, NULL)) != -1) { ++ switch (opt) { ++ case 'f': ++ ret = parse_file_name(optarg, &proj->file_name); ++ if (ret != 0) { ++ printf("parse file name failed\n"); ++ return ret; ++ } ++ break; ++ case 's': ++ ret = parse_name_string(optarg, &proj->sock_name, SOCKET_NAME_MAX_LEN); ++ if (ret != 0) { ++ printf("parse socket name failed.\n"); ++ return ret; ++ } ++ break; ++ case '?': ++ /* fallthrough */ ++ default: ++ printf("invalid option: %s\n", conf->argv[optind]); ++ return -EINVAL; ++ } ++ params_cnt++; ++ } ++ ++ ret = etmem_parse_check_result(params_cnt, conf->argc); ++ ++ return ret; ++} ++ ++static int obj_check_params(const struct mem_proj *proj) ++{ ++ if (proj->sock_name == NULL || strlen(proj->sock_name) == 0) { ++ printf("socket name to connect must all be given, please check.\n"); ++ return -EINVAL; ++ } ++ ++ if (proj->file_name == NULL || strlen(proj->file_name) == 0) { ++ printf("file name must be given in add command.\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int obj_do_cmd(struct etmem_conf *conf) ++{ ++ struct mem_proj proj; ++ int ret; ++ ++ ret = memset_s(&proj, sizeof(struct mem_proj), 0, sizeof(struct mem_proj)); ++ if (ret != EOK) { ++ printf("memset_s for mem_proj failed\n"); ++ return ret; ++ } ++ ++ ret = obj_parse_cmd(conf, &proj); ++ if (ret != 0) { ++ printf("obj_parse_cmd fail\n"); ++ return ret; ++ } ++ ++ ret = obj_parse_args(conf, &proj); ++ if (ret != 0) { ++ printf("obj_parse_args fail\n"); ++ goto EXIT; ++ } ++ ++ ret = obj_check_params(&proj); ++ if (ret != 0) { ++ printf("obj_check_params fail\n"); ++ goto EXIT; ++ } ++ ++ ret = etmem_rpc_client(&proj); ++ ++EXIT: ++ free_proj_member(&proj); ++ return ret; ++} ++ ++static struct etmem_obj g_etmem_obj = { ++ .name = "obj", ++ .help = obj_help, ++ .do_cmd = obj_do_cmd, ++}; ++ ++void obj_init(void) ++{ ++ etmem_register_obj(&g_etmem_obj); ++} ++ ++void obj_exit(void) ++{ ++ etmem_unregister_obj(&g_etmem_obj); ++} +diff --git a/src/etmem_src/etmem_project.c b/src/etmem_src/etmem_project.c +index 85363b0..790979e 100644 +--- a/src/etmem_src/etmem_project.c ++++ b/src/etmem_src/etmem_project.c +@@ -27,65 +27,44 @@ static void project_help(void) + { + fprintf(stderr, + "\nUsage:\n" +- " etmem project add [options]\n" +- " etmem project del [options]\n" ++ " etmem project start [options]\n" ++ " etmem project stop [options]\n" + " etmem project show [options]\n" + " etmem project help\n" + "\nOptions:\n" +- " -f|--file Add configuration file\n" + " -n|--name Add project name\n" + " -s|--socket Socket name to connect\n" + "\nNotes:\n" + " 1. Project name and socket name must be given when execute add or del option.\n" +- " 2. Configuration file must be given when execute add option.\n" +- " 3. Socket name must be given when execute show option.\n"); ++ " 2. Socket name must be given when execute show option.\n"); + } + +-static int project_parse_cmd(const struct etmem_conf *conf, struct mem_proj *proj) +-{ +- switch (conf->cmd) { +- case ETMEM_CMD_ADD: +- /* fallthrough */ +- case ETMEM_CMD_DEL: +- /* fallthrough */ +- case ETMEM_CMD_SHOW: +- goto EXIT; +- default: +- printf("invalid command %u of project\n", conf->cmd); +- return -EINVAL; +- } ++struct project_cmd_item { ++ char *cmd_name; ++ enum etmem_cmd_e cmd; ++}; + +-EXIT: +- proj->cmd = conf->cmd; +- return 0; +-} ++static struct project_cmd_item g_project_cmd_items[] = { ++ {"show", ETMEM_CMD_SHOW}, ++ {"start", ETMEM_CMD_START}, ++ {"stop", ETMEM_CMD_STOP}, ++}; + +-static int parse_file_name(const char *val, char **file_name) ++static int project_parse_cmd(struct etmem_conf *conf, struct mem_proj *proj) + { +- size_t len; +- int ret; +- +- len = strlen(val) + 1; +- if (len > FILE_NAME_MAX_LEN) { +- printf("file name too long, should not be larger than %u\n", FILE_NAME_MAX_LEN); +- return -ENAMETOOLONG; +- } +- +- *file_name = (char *)calloc(len, sizeof(char)); +- if (*file_name == NULL) { +- printf("malloc file name failed.\n"); +- return -ENOMEM; +- } +- +- ret = strncpy_s(*file_name, len, val, len - 1); +- if (ret != EOK) { +- printf("strncpy_s file name failed.\n"); +- free(*file_name); +- *file_name = NULL; +- return ret; ++ unsigned i; ++ char *cmd = NULL; ++ ++ cmd = conf->argv[0]; ++ for (i = 0; i < ARRAY_SIZE(g_project_cmd_items); i++) { ++ if (strcmp(cmd, g_project_cmd_items[i].cmd_name) == 0) { ++ proj->cmd = g_project_cmd_items[i].cmd; ++ return 0; ++ } + } + +- return 0; ++ printf("project cmd %s is not supported\n", cmd); ++ return -1; + } + + static int project_parse_args(const struct etmem_conf *conf, struct mem_proj *proj) +@@ -94,7 +73,6 @@ static int project_parse_args(const struct etmem_conf *conf, struct mem_proj *pr + int ret; + int params_cnt = 0; + struct option opts[] = { +- {"file", required_argument, NULL, 'f'}, + {"name", required_argument, NULL, 'n'}, + {"socket", required_argument, NULL, 's'}, + {NULL, 0, NULL, 0}, +@@ -103,13 +81,6 @@ static int project_parse_args(const struct etmem_conf *conf, struct mem_proj *pr + while ((opt = getopt_long(conf->argc, conf->argv, "f:n:s:", + opts, NULL)) != -1) { + switch (opt) { +- case 'f': +- ret = parse_file_name(optarg, &proj->file_name); +- if (ret != 0) { +- printf("parse file name failed.\n"); +- return ret; +- } +- break; + case 'n': + ret = parse_name_string(optarg, &proj->proj_name, PROJECT_NAME_MAX_LEN); + if (ret != 0) { +@@ -149,14 +120,9 @@ static int project_check_params(const struct mem_proj *proj) + return 0; + } + +- if (proj->proj_name == NULL || strlen(proj->proj_name) == 0) { +- printf("project name must all be given, please check.\n"); +- return -EINVAL; +- } +- +- if (proj->cmd == ETMEM_CMD_ADD) { +- if (proj->file_name == NULL || strlen(proj->file_name) == 0) { +- printf("file name must be given in add command.\n"); ++ if (proj->cmd == ETMEM_CMD_START || proj->cmd == ETMEM_CMD_STOP) { ++ if (proj->proj_name == NULL || strlen(proj->proj_name) == 0) { ++ printf("project name must be given, please check\n"); + return -EINVAL; + } + } +@@ -164,7 +130,7 @@ static int project_check_params(const struct mem_proj *proj) + return 0; + } + +-static int project_do_cmd(const struct etmem_conf *conf) ++static int project_do_cmd(struct etmem_conf *conf) + { + struct mem_proj proj; + int ret; +diff --git a/src/etmem_src/etmem_rpc.c b/src/etmem_src/etmem_rpc.c +index 12a8f6d..8d03914 100644 +--- a/src/etmem_src/etmem_rpc.c ++++ b/src/etmem_src/etmem_rpc.c +@@ -24,7 +24,7 @@ + #include "securec.h" + #include "etmem_rpc.h" + +-#define ETMEM_CLIENT_REGISTER "proj_name %s file_name %s cmd %d" ++#define ETMEM_CLIENT_REGISTER "proj_name %s file_name %s cmd %d eng_name %s eng_cmd %s task_name %s" + + #define INT_MAX_LEN 9 + #define ETMEM_RPC_RECV_BUF_LEN 512 +@@ -86,6 +86,15 @@ static size_t etmem_client_get_str_len(const struct mem_proj *proj) + if (proj->file_name != NULL) { + total_len += strlen(proj->file_name); + } ++ if (proj->eng_name != NULL) { ++ total_len += strlen(proj->eng_name); ++ } ++ if (proj->eng_cmd != NULL) { ++ total_len += strlen(proj->eng_cmd); ++ } ++ if (proj->task_name != NULL) { ++ total_len += strlen(proj->task_name); ++ } + + return total_len; + } +@@ -108,7 +117,10 @@ static int etmem_client_send(const struct mem_proj *proj, int sockfd) + if (snprintf_s(reg_cmd, total_len, total_len - 1, ETMEM_CLIENT_REGISTER, + proj->proj_name == NULL ? "-" : proj->proj_name, + proj->file_name == NULL ? "-" : proj->file_name, +- proj->cmd) <= 0) { ++ proj->cmd, ++ proj->eng_name == NULL ? "-" : proj->eng_name, ++ proj->eng_cmd == NULL ? "-" : proj->eng_cmd, ++ proj->task_name == NULL ? "-" : proj->task_name) <= 0) { + printf("snprintf_s failed.\n"); + goto EXIT; + } +@@ -135,16 +147,15 @@ EXIT: + static bool etmem_recv_find_fail_keyword(const char *recv_msg) + { + if (strstr(recv_msg, "error") != NULL) { +- printf("get rpc error response. %s\n", recv_msg); + return true; + } +- + return false; + } + + static int etmem_client_recv(int sockfd) + { +- ssize_t ret; ++ ssize_t recv_size; ++ int ret = -1; + char *recv_msg = NULL; + uint8_t *recv_buf = NULL; + size_t recv_len = ETMEM_RPC_RECV_BUF_LEN; +@@ -155,22 +166,27 @@ static int etmem_client_recv(int sockfd) + return -1; + } + +- ret = recv(sockfd, recv_buf, recv_len, 0); +- if (ret < 0) { +- perror("recv failed:"); +- goto EXIT; +- } +- if ((unsigned long)ret >= recv_len) { +- printf("recv too long.\n"); +- ret = -1; +- goto EXIT; +- } +- +- recv_msg = (char *)recv_buf; +- recv_msg[recv_len - 1] = '\0'; +- if (etmem_recv_find_fail_keyword(recv_msg)) { +- ret = 0; +- goto EXIT; ++ while (true) { ++ recv_size = recv(sockfd, recv_buf, recv_len - 1, 0); ++ if (recv_size < 0) { ++ perror("recv failed:"); ++ goto EXIT; ++ } ++ if (recv_size == 0) { ++ if (errno == EAGAIN || errno == EWOULDBLOCK) { ++ printf("recv timeout:\n"); ++ } ++ ret = 0; ++ goto EXIT; ++ } ++ ++ recv_msg = (char *)recv_buf; ++ recv_msg[recv_size] = '\0'; ++ printf("%s", recv_msg); ++ if (etmem_recv_find_fail_keyword(recv_msg)) { ++ printf("error occurs when getting response from etmemd server\n"); ++ goto EXIT; ++ } + } + + EXIT: +@@ -207,12 +223,6 @@ int etmem_rpc_client(const struct mem_proj *proj) + ret = -ECOMM; + goto EXIT; + } +- if (ret == 0) { +- printf("error occurs when getting response from etmemd server.\n"); +- ret = -EPERM; +- goto EXIT; +- } +- ret = 0; + + EXIT: + close(sockfd); +diff --git a/src/etmem_src/etmem_task.c b/src/etmem_src/etmem_task.c +deleted file mode 100644 +index fc3206d..0000000 +--- a/src/etmem_src/etmem_task.c ++++ /dev/null +@@ -1,161 +0,0 @@ +-/****************************************************************************** +- * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. +- * etmem is licensed under the Mulan PSL v2. +- * You can use this software according to the terms and conditions of the Mulan PSL v2. +- * You may obtain a copy of Mulan PSL v2 at: +- * http://license.coscl.org.cn/MulanPSL2 +- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +- * PURPOSE. +- * See the Mulan PSL v2 for more details. +- * Author: louhongxiang +- * Create: 2019-12-10 +- * Description: Migration command API. +- ******************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include "securec.h" +-#include "etmem.h" +-#include "etmem_task.h" +-#include "etmem_common.h" +-#include "etmem_rpc.h" +- +-static void migrate_help(void) +-{ +- fprintf(stderr, +- "\nUsage:\n" +- " etmem migrate start [options]\n" +- " etmem migrate stop [options]\n" +- " etmem migrate help\n" +- "\nOptions:\n" +- " -n|--name Add project name\n" +- " -s|--socket Socket name to connect\n" +- "\nNotes:\n" +- " Project name and socket name must be given when execute start or stop option.\n"); +-} +- +-static int migrate_parse_cmd(const struct etmem_conf *conf, struct mem_proj *proj) +-{ +- switch (conf->cmd) { +- case ETMEM_CMD_START: +- /* fallthrough */ +- case ETMEM_CMD_STOP: +- goto EXIT; +- default: +- printf("invalid command %u of migrate\n", conf->cmd); +- return -EINVAL; +- } +- +-EXIT: +- proj->cmd = conf->cmd; +- return 0; +-} +- +-static int migrate_parse_args(const struct etmem_conf *conf, struct mem_proj *proj) +-{ +- int opt; +- int params_cnt = 0; +- int ret; +- struct option opts[] = { +- {"name", required_argument, NULL, 'n'}, +- {"socket", required_argument, NULL, 's'}, +- {NULL, 0, NULL, 0}, +- }; +- +- while ((opt = getopt_long(conf->argc, conf->argv, "n:s:", +- opts, NULL)) != -1) { +- switch (opt) { +- case 'n': +- ret = parse_name_string(optarg, &proj->proj_name, PROJECT_NAME_MAX_LEN); +- if (ret != 0) { +- printf("parse project name failed.\n"); +- return ret; +- } +- break; +- case 's': +- ret = parse_name_string(optarg, &proj->sock_name, SOCKET_NAME_MAX_LEN); +- if (ret != 0) { +- printf("parse socket name failed.\n"); +- return ret; +- } +- break; +- case '?': +- /* fallthrough */ +- default: +- ret = -EINVAL; +- printf("invalid option: %s\n", conf->argv[optind]); +- return ret; +- } +- params_cnt++; +- } +- +- ret = etmem_parse_check_result(params_cnt, conf->argc); +- if (ret != 0) { +- return ret; +- } +- +- return 0; +-} +- +-static int migrate_check_params(const struct mem_proj *proj) +-{ +- if (proj->proj_name == NULL || strlen(proj->proj_name) == 0 || +- proj->sock_name == NULL || strlen(proj->sock_name) == 0) { +- printf("project name and socket name must all be given, please check.\n"); +- return -EINVAL; +- } +- +- return 0; +-} +- +-static int migrate_do_cmd(const struct etmem_conf *conf) +-{ +- struct mem_proj proj; +- int ret; +- +- ret = memset_s(&proj, sizeof(struct mem_proj), 0, sizeof(struct mem_proj)); +- if (ret != EOK) { +- printf("memset_s for mem_proj failed.\n"); +- return ret; +- } +- +- ret = migrate_parse_cmd(conf, &proj); +- if (ret != 0) { +- goto EXIT; +- } +- +- ret = migrate_parse_args(conf, &proj); +- if (ret != 0) { +- goto EXIT; +- } +- +- ret = migrate_check_params(&proj); +- if (ret != 0) { +- goto EXIT; +- } +- +- etmem_rpc_client(&proj); +- +-EXIT: +- free_proj_member(&proj); +- return ret; +-} +- +-static struct etmem_obj g_etmem_migrate = { +- .name = "migrate", +- .help = migrate_help, +- .do_cmd = migrate_do_cmd, +-}; +- +-void migrate_init(void) +-{ +- etmem_register_obj(&g_etmem_migrate); +-} +- +-void migrate_exit(void) +-{ +- etmem_unregister_obj(&g_etmem_migrate); +-} +diff --git a/src/etmemd_src/etmemd_common.c b/src/etmemd_src/etmemd_common.c +index 0fe070c..43ed013 100644 +--- a/src/etmemd_src/etmemd_common.c ++++ b/src/etmemd_src/etmemd_common.c +@@ -21,6 +21,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "securec.h" + #include "etmemd_common.h" +@@ -214,9 +217,10 @@ static char *etmemd_get_proc_file_str(const char *pid, const char *file) + return file_name; + } + +-FILE *etmemd_get_proc_file(const char *pid, const char *file, const char *mode) ++FILE *etmemd_get_proc_file(const char *pid, const char *file, int flags, const char *mode) + { + char *file_name = NULL; ++ int fd = -1; + FILE *fp = NULL; + + file_name = etmemd_get_proc_file_str(pid, file); +@@ -224,7 +228,14 @@ FILE *etmemd_get_proc_file(const char *pid, const char *file, const char *mode) + return NULL; + } + +- fp = fopen(file_name, mode); ++ fd = open(file_name, flags); ++ if (fd < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "open file %s fail\n", file_name); ++ goto free_file_name; ++ } ++ fp = fdopen(fd, mode); ++ ++free_file_name: + free(file_name); + return fp; + } +@@ -366,3 +377,41 @@ char *skip_blank_line(FILE *file) + + return get_line; + } ++ ++static int write_all(int fd, const char *buf) ++{ ++ ssize_t rest = strlen(buf); ++ ssize_t send_size; ++ ++ while (rest > 0) { ++ send_size = write(fd, buf, rest); ++ if (send_size < 0) { ++ return -1; ++ } ++ rest -= send_size; ++ } ++ return 0; ++} ++ ++int dprintf_all(int fd, const char *format, ...) ++{ ++ char line[FILE_LINE_MAX_LEN]; ++ int ret; ++ va_list args_in; ++ ++ va_start(args_in, format); ++ ret = vsprintf_s(line, FILE_LINE_MAX_LEN, format, args_in); ++ if (ret > FILE_LINE_MAX_LEN) { ++ etmemd_log(ETMEMD_LOG_ERR, "fprintf_all fail as truncated.\n"); ++ return -1; ++ } ++ ++ ret = write_all(fd, line); ++ if (ret < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "write_all fail.\n"); ++ return -1; ++ } ++ ++ va_end(args_in); ++ return 0; ++} +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +new file mode 100644 +index 0000000..a3692ad +--- /dev/null ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -0,0 +1,2272 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: louhongxiang ++ * Create: 2021-4-19 ++ * Description: Memigd cslide API. ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "securec.h" ++#include "etmemd_log.h" ++#include "etmemd_common.h" ++#include "etmemd_engine.h" ++#include "etmemd_cslide.h" ++#include "etmemd_scan.h" ++#include "etmemd_migrate.h" ++#include "etmemd_file.h" ++ ++#define HUGE_1M_SIZE (1 << 20) ++#define HUGE_2M_SIZE (2 << 20) ++#define HUGE_1G_SIZE (1 << 30) ++#define BYTE_TO_KB(s) ((s) >> 10) ++#define KB_TO_BYTE(s) ((s) << 10) ++ ++#define TO_PCT 100 ++#define MAX_WM 100 ++#define MIN_WM 0 ++ ++#define BATCHSIZE (1 << 16) ++ ++#define factory_foreach_working_pid_params(iter, factory) \ ++ for ((iter) = (factory)->working_head, next_working_params(&(iter)); (iter) != NULL; (iter) = (iter)->next, next_working_params(&(iter))) ++ ++#define factory_foreach_pid_params(iter, factory) \ ++ for ((iter) = (factory)->working_head; (iter) != NULL; (iter) = (iter)->next) ++ ++struct node_mem { ++ long long huge_total; ++ long long huge_free; ++}; ++ ++struct sys_mem { ++ int node_num; ++ struct node_mem *node_mem; ++}; ++ ++struct node_page_refs { ++ struct page_refs *head; ++ struct page_refs *tail; ++ int64_t size; ++ uint32_t num; ++}; ++ ++struct count_page_refs { ++ struct node_page_refs *node_pfs; ++ int node_num; ++}; ++ ++struct node_pair { ++ int index; ++ int hot_node; ++ int cold_node; ++}; ++ ++struct node_map { ++ struct node_pair *pair; ++ int total_num; ++ int cur_num; ++}; ++ ++struct node_verifier { ++ int node_num; ++ int *nodes_map_count; ++}; ++ ++struct cslide_task_params { ++ bool anon_only; ++ struct { ++ char *vmflags_str; ++ char **vmflags_array; ++ int vmflags_num; ++ }; ++}; ++ ++struct vma_pf { ++ struct vma *vma; ++ struct page_refs *page_refs; ++ struct vma_pf *next; ++}; ++ ++struct node_pages_info { ++ uint32_t hot; ++ uint32_t cold; ++}; ++ ++enum pid_param_state { ++ STATE_NONE = 0, ++ STATE_WORKING, ++ STATE_REMOVE, ++ STATE_FREE, ++}; ++ ++struct cslide_pid_params { ++ enum pid_param_state state; ++ int count; ++ struct count_page_refs *count_page_refs; ++ struct memory_grade *memory_grade; ++ struct node_pages_info *node_pages_info; ++ struct vmas *vmas; ++ struct vma_pf *vma_pf; ++ unsigned int pid; ++ struct cslide_eng_params *eng_params; ++ struct cslide_task_params *task_params; ++ struct cslide_pid_params *next; ++}; ++ ++struct cslide_params_factory { ++ pthread_mutex_t mtx; ++ struct cslide_pid_params *to_add_head; ++ struct cslide_pid_params *to_add_tail; ++ struct cslide_pid_params *working_head; ++}; ++ ++struct cslide_eng_params { ++ struct sys_mem mem; ++ struct node_map node_map; ++ int node_watermark; ++ int hot_threshold; ++ int hot_reserve; // in MB ++ int mig_quota; // in MB ++ pthread_t worker; ++ pthread_mutex_t stat_mtx; ++ time_t stat_time; ++ struct { ++ int loop; ++ int interval; ++ int sleep; ++ }; ++ struct cslide_params_factory factory; ++ bool finish; ++}; ++ ++struct ctrl_cap { ++ long long cap; ++ long long used; ++}; ++ ++struct node_ctrl { ++ struct ctrl_cap hot_move_cap; ++ struct ctrl_cap hot_prefetch_cap; ++ struct ctrl_cap cold_move_cap; ++ long long cold_replaced; ++ long long cold_free; ++ long long free; ++ long long total; ++ long long quota; ++ long long reserve; ++}; ++ ++struct flow_ctrl { ++ struct node_ctrl *node_ctrl; ++ int pair_num; ++ int hot_enough; ++ int prefetch_enough; ++ int cold_enough; ++}; ++ ++struct page_filter { ++ void (*flow_cal_func)(struct flow_ctrl *ctrl); ++ long long (*flow_move_func)(struct flow_ctrl *ctrl, long long target, int node); ++ bool (*flow_enough)(struct flow_ctrl *ctrl); ++ void (*filter_policy)(struct page_filter *filter, struct node_pair *pair, struct count_page_refs *cpf, struct memory_grade *memory_grade); ++ struct flow_ctrl *ctrl; ++ int count_start; ++ int count_end; ++ int count_step; ++}; ++ ++struct page_offset { ++ struct page_refs *page_refs; ++ uint64_t to_offset; ++}; ++ ++struct cslide_cmd_item { ++ char *name; ++ int (*func)(void *params, int fd); ++}; ++ ++struct vma_pf *g_share_vma_head = NULL; ++ ++static inline int get_node_num(void) ++{ ++ return numa_num_configured_nodes(); ++} ++ ++static int init_sys_mem(struct sys_mem *mem) ++{ ++ int node_num = get_node_num(); ++ ++ if (node_num <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "node number %d is invalid \n", node_num); ++ return -1; ++ } ++ ++ mem->node_mem = malloc(sizeof(struct node_mem) * node_num); ++ if (mem->node_mem == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc node_mem fail\n"); ++ return -1; ++ } ++ mem->node_num = node_num; ++ return 0; ++} ++ ++static void destroy_sys_mem(struct sys_mem *mem) ++{ ++ mem->node_num = -1; ++ free(mem->node_mem); ++ mem->node_mem = NULL; ++} ++ ++static int read_hugepage_num(char *path) ++{ ++ FILE *f = NULL; ++ char *line = NULL; ++ size_t line_len = 0; ++ int nr = -1; ++ ++ f = fopen(path, "r"); ++ if (f == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "open file %s failed\n", path); ++ return -1; ++ } ++ if (getline(&line, &line_len, f) < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "read free hugepage from %s fail\n", path); ++ goto close_file; ++ } ++ ++ nr = strtoull(line, NULL, 0); ++ free(line); ++close_file: ++ fclose(f); ++ return nr; ++} ++ ++static long long get_single_huge_mem(int node, int huge_size, char *huge_state) ++{ ++ char path[PATH_MAX]; ++ int nr; ++ ++ if (sprintf_s(path, PATH_MAX, "/sys/devices/system/node/node%d/hugepages/hugepages-%dkB/%s_hugepages", ++ node, huge_size, huge_state) <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "snprintf path to get hugepage number fail\n"); ++ return -1; ++ } ++ ++ nr = read_hugepage_num(path); ++ if (nr < 0) { ++ return -1; ++ } ++ ++ return KB_TO_BYTE((long long)nr * (long long)huge_size); ++} ++ ++static long long get_node_huge_total(int node, char *huge_state) ++{ ++ long long size_2m; ++ ++ size_2m = get_single_huge_mem(node, BYTE_TO_KB(HUGE_2M_SIZE), huge_state); ++ if (size_2m < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get 2M %s page in node %d fail\n", huge_state, node); ++ return -1; ++ } ++ ++ return size_2m; ++} ++ ++static int get_node_huge_mem(int node, struct node_mem *mem) ++{ ++ mem->huge_total = get_node_huge_total(node, "nr"); ++ if (mem->huge_total <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get total hugepages of node %d fail\n", node); ++ return -1; ++ } ++ mem->huge_free = get_node_huge_total(node, "free"); ++ if (mem->huge_free < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get free hugepages of node %d fail\n", node); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int get_node_mem(int node, struct node_mem *mem) ++{ ++ if (get_node_huge_mem(node, mem) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get huge memory info of node %d fail\n", node); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int get_sys_mem(struct sys_mem *mem) ++{ ++ int i; ++ ++ for (i = 0; i < mem->node_num; i++) { ++ if (get_node_mem(i, &(mem->node_mem[i])) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get memory info of node %d fail\n", i); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void init_node_page_refs(struct node_page_refs *npf) ++{ ++ npf->head = NULL; ++ npf->tail = NULL; ++ npf->size = 0; ++ npf->num = 0; ++} ++ ++static void clean_node_page_refs(struct node_page_refs *npf) ++{ ++ clean_page_refs_unexpected(&npf->head); ++ npf->tail = NULL; ++ npf->size = 0; ++ npf->num = 0; ++} ++ ++static void npf_add_pf(struct node_page_refs *npf, struct page_refs *page_refs) ++{ ++ if (npf->head == NULL) { ++ npf->head = page_refs; ++ npf->tail = page_refs; ++ } else { ++ npf->tail->next = page_refs; ++ npf->tail = page_refs; ++ } ++ ++ npf->size += page_type_to_size(page_refs->type); ++ npf->num++; ++} ++ ++/* must called when all pf add to npf with npf_add_pf */ ++static void npf_setup_tail(struct node_page_refs *npf) ++{ ++ if (npf->tail != NULL) { ++ npf->tail->next = NULL; ++ } ++} ++ ++static long long move_npf_to_list(struct node_page_refs *npf, struct page_refs **list, long long size) ++{ ++ struct page_refs *t = NULL; ++ struct page_refs *iter = NULL; ++ struct page_refs *tmp = NULL; ++ long long moved_size = 0; ++ ++ if (npf->size <= size) { ++ t = npf->tail; ++ moved_size = npf->size; ++ } else { ++ for (iter = npf->head; iter != NULL && size >= moved_size + page_type_to_size(iter->type); iter = iter->next) { ++ moved_size += page_type_to_size(iter->type); ++ t = iter; ++ } ++ } ++ ++ if (t != NULL) { ++ tmp = t->next; ++ t->next = *list; ++ *list = npf->head; ++ npf->head = tmp; ++ if (tmp == NULL) { ++ npf->tail = NULL; ++ } ++ } ++ ++ npf->size -= moved_size; ++ return moved_size; ++} ++ ++static int init_count_page_refs(struct count_page_refs *cpf, int node_num) ++{ ++ int i; ++ ++ cpf->node_pfs = malloc(sizeof(struct node_page_refs) * node_num); ++ if (cpf->node_pfs == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc node_page_refs fail\n"); ++ return -1; ++ } ++ for (i = 0; i < node_num; i++) { ++ init_node_page_refs(&cpf->node_pfs[i]); ++ } ++ cpf->node_num = node_num; ++ return 0; ++} ++ ++static void clean_count_page_refs(struct count_page_refs *cpf) ++{ ++ int i; ++ ++ for (i = 0; i < cpf->node_num; i++) { ++ clean_node_page_refs(&cpf->node_pfs[i]); ++ } ++} ++ ++static void destroy_count_page_refs(struct count_page_refs *cpf) ++{ ++ clean_count_page_refs(cpf); ++ free(cpf->node_pfs); ++ cpf->node_pfs = NULL; ++ cpf->node_num = 0; ++} ++ ++static void insert_count_pfs(struct count_page_refs *cpf, struct page_refs *pf, int *nodes, int num) ++{ ++ struct node_page_refs *npf = NULL; ++ struct page_refs *next = NULL; ++ int node, count, i; ++ ++ for (i = 0; i < num; i++) { ++ next = pf->next; ++ node = nodes[i]; ++ if (node < 0 || node >= cpf->node_num) { ++ etmemd_log(ETMEMD_LOG_WARN, "addr %llx with invalid node %d\n", pf->addr, node); ++ pf->next = NULL; ++ etmemd_free_page_refs(pf); ++ pf = next; ++ continue; ++ } ++ count = pf->count; ++ npf = &cpf[count].node_pfs[node]; ++ npf_add_pf(npf, pf); ++ pf = next; ++ } ++} ++ ++/* must called after all page_refs insert by insert_count_pfs */ ++static void setup_count_pfs_tail(struct count_page_refs *cpf, int count) ++{ ++ int node, c; ++ struct node_page_refs *npf = NULL; ++ ++ for (c = 0; c <= count; c++) { ++ for (node = 0; node < cpf->node_num; node++) { ++ npf = &cpf[c].node_pfs[node]; ++ npf_setup_tail(npf); ++ } ++ } ++} ++ ++static int init_node_map(struct node_map *node_map, int node_num) ++{ ++ int pair_num; ++ ++ if (node_num % 2 != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "node_num is not even\n"); ++ return -1; ++ } ++ pair_num = node_num / 2; ++ node_map->pair = calloc(pair_num, sizeof(struct node_pair)); ++ if (node_map->pair == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc memory for node map fail\n"); ++ return -1; ++ } ++ node_map->total_num = pair_num; ++ node_map->cur_num = 0; ++ return 0; ++} ++ ++static void destroy_node_map(struct node_map *map) ++{ ++ free(map->pair); ++ map->pair = NULL; ++ map->total_num = 0; ++ map->cur_num = 0; ++} ++ ++static int add_node_pair(struct node_map *map, int cold_node, int hot_node) ++{ ++ if (map->cur_num == map->total_num) { ++ etmemd_log(ETMEMD_LOG_ERR, "too much pair, add pair hot %d cold %d fail\n", ++ hot_node, cold_node); ++ return -1; ++ } ++ map->pair[map->cur_num].hot_node = hot_node; ++ map->pair[map->cur_num].cold_node = cold_node; ++ map->pair[map->cur_num].index = map->cur_num; ++ map->cur_num++; ++ return 0; ++} ++ ++ ++static int init_node_verifier(struct node_verifier *nv, int node_num) ++{ ++ nv->nodes_map_count = calloc(node_num, sizeof(int)); ++ if (nv->nodes_map_count == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc memroy for nodes_map_count failed\n"); ++ return -1; ++ } ++ ++ nv->node_num = node_num; ++ return 0; ++} ++ ++static void destroy_node_verifier(struct node_verifier *nv) ++{ ++ free(nv->nodes_map_count); ++} ++ ++static bool is_node_valid(struct node_verifier *nv, int node) ++{ ++ if (node < 0 || node >= nv->node_num) { ++ etmemd_log(ETMEMD_LOG_ERR, "node %d out of range\n", node); ++ return false; ++ } ++ ++ if (nv->nodes_map_count[node] != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "node %d remap\n", node); ++ return false; ++ } ++ ++ nv->nodes_map_count[node]++; ++ return true; ++} ++ ++static bool has_node_unmap(struct node_verifier *nv) ++{ ++ int i; ++ bool ret = false; ++ ++ for (i = 0; i < nv->node_num; i++) { ++ if (nv->nodes_map_count[i] == 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "unmap node %d\n", i); ++ ret = true; ++ } ++ } ++ ++ return ret; ++} ++ ++static void clear_task_params(struct cslide_task_params *params) ++{ ++ if (params->vmflags_str != NULL) { ++ free(params->vmflags_str); ++ params->vmflags_str = NULL; ++ } ++ if (params->vmflags_array != NULL) { ++ free(params->vmflags_array); ++ params->vmflags_array = NULL; ++ } ++} ++ ++static struct cslide_pid_params *alloc_pid_params(struct cslide_eng_params *eng_params) ++{ ++ int i; ++ struct cslide_pid_params *params = calloc(1, sizeof(struct cslide_pid_params)); ++ int count = eng_params->loop; ++ int pair_num = eng_params->node_map.cur_num; ++ int node_num = eng_params->mem.node_num; ++ ++ if (params == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "malloc cslide pid params fail\n"); ++ return NULL; ++ } ++ params->count_page_refs = malloc(sizeof(struct count_page_refs) * (count + 1)); ++ if (params->count_page_refs == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "malloc counted page_refs fail\n"); ++ goto free_params; ++ } ++ ++ for (i = 0; i <= count; i++) { ++ if (init_count_page_refs(¶ms->count_page_refs[i], node_num) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "init counted page_refs fail\n"); ++ goto free_count_page_refs; ++ } ++ } ++ ++ params->count = count; ++ params->memory_grade = calloc(pair_num, sizeof(struct memory_grade)); ++ if (params->memory_grade == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc memory_grade fail\n"); ++ goto free_count_page_refs; ++ } ++ ++ params->node_pages_info = calloc(node_num, sizeof(struct node_pages_info)); ++ if (params->node_pages_info == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc pages info fail\n"); ++ goto free_memory_grade; ++ } ++ return params; ++ ++free_memory_grade: ++ free(params->memory_grade); ++ params->memory_grade = NULL; ++free_count_page_refs: ++ for (i--; i >= 0; i--) { ++ destroy_count_page_refs(¶ms->count_page_refs[i]); ++ } ++ free(params->count_page_refs); ++ params->count_page_refs = NULL; ++free_params: ++ free(params); ++ params = NULL; ++ return NULL; ++} ++ ++static void free_pid_params(struct cslide_pid_params *params) ++{ ++ int count = params->count; ++ int i; ++ ++ free(params->node_pages_info); ++ params->node_pages_info = NULL; ++ free(params->memory_grade); ++ params->memory_grade = NULL; ++ for (i = 0; i <= count; i++) { ++ destroy_count_page_refs(¶ms->count_page_refs[i]); ++ } ++ free(params->count_page_refs); ++ params->count_page_refs = NULL; ++ if (params->task_params != NULL) { ++ clear_task_params(params->task_params); ++ free(params->task_params); ++ params->task_params = NULL; ++ } ++ free(params); ++} ++ ++static void clean_pid_param(struct cslide_pid_params *pid_params) ++{ ++ struct cslide_eng_params *eng_params = pid_params->eng_params; ++ int pair_num = eng_params->node_map.cur_num; ++ int i; ++ ++ for (i = 0; i < pair_num; i++) { ++ clean_page_refs_unexpected(&pid_params->memory_grade[i].hot_pages); ++ clean_page_refs_unexpected(&pid_params->memory_grade[i].cold_pages); ++ } ++ for (i = 0; i <= pid_params->count; i++) { ++ clean_count_page_refs(&pid_params->count_page_refs[i]); ++ } ++} ++ ++static void destroy_factory(struct cslide_params_factory *factory) ++{ ++ pthread_mutex_destroy(&factory->mtx); ++} ++ ++static int init_factory(struct cslide_params_factory *factory) ++{ ++ return pthread_mutex_init(&factory->mtx, NULL); ++} ++ ++static void factory_add_pid_params(struct cslide_params_factory *factory, struct cslide_pid_params *params) ++{ ++ enum pid_param_state state = params->state; ++ params->state = STATE_WORKING; ++ ++ if (state == STATE_NONE) { ++ pthread_mutex_lock(&factory->mtx); ++ params->next = factory->to_add_head; ++ factory->to_add_head = params; ++ if (factory->to_add_tail == NULL) { ++ factory->to_add_tail = params; ++ } ++ pthread_mutex_unlock(&factory->mtx); ++ } ++} ++ ++static void factory_remove_pid_params(struct cslide_params_factory *factory, struct cslide_pid_params *params) ++{ ++ params->state = STATE_REMOVE; ++} ++ ++static void factory_free_pid_params(struct cslide_params_factory *factory, struct cslide_pid_params *params) ++{ ++ params->state = STATE_FREE; ++} ++ ++static void next_working_params(struct cslide_pid_params **params) ++{ ++ while (*params != NULL && (*params)->state != STATE_WORKING) { ++ *params = (*params)->next; ++ } ++} ++ ++/* add and free operations will take effect here */ ++static void factory_update_pid_params(struct cslide_params_factory *factory) ++{ ++ struct cslide_pid_params **prev = NULL; ++ struct cslide_pid_params *iter = NULL; ++ struct cslide_pid_params *to_add_head = NULL; ++ struct cslide_pid_params *to_add_tail = NULL; ++ ++ /* get new added params first */ ++ pthread_mutex_lock(&factory->mtx); ++ to_add_head = factory->to_add_head; ++ to_add_tail = factory->to_add_tail; ++ factory->to_add_head = NULL; ++ factory->to_add_tail = NULL; ++ pthread_mutex_unlock(&factory->mtx); ++ ++ if (to_add_head != NULL) { ++ to_add_tail->next = factory->working_head; ++ factory->working_head = to_add_head; ++ } ++ ++ /* clear the freed params */ ++ prev = &factory->working_head; ++ for (iter = *prev; iter != NULL; iter = *prev) { ++ if (iter->state != STATE_FREE) { ++ prev = &(iter->next); ++ continue; ++ } ++ *prev = iter->next; ++ iter->next = NULL; ++ free_pid_params(iter); ++ } ++} ++ ++static bool factory_working_empty(struct cslide_params_factory *factory) ++{ ++ struct cslide_pid_params *pid_params = NULL; ++ ++ factory_foreach_pid_params(pid_params, factory) { ++ if (pid_params->state == STATE_WORKING) { ++ return false; ++ } ++ } ++ return true; ++} ++ ++static struct page_refs *next_vma_pf(struct cslide_pid_params *params, int *cur) ++{ ++ int vma_pf_num = params->vmas->vma_cnt; ++ struct vma_pf *vma_pf = params->vma_pf; ++ struct page_refs *pf = NULL; ++ ++ while (*cur < vma_pf_num) { ++ pf = vma_pf[*cur].page_refs; ++ vma_pf[*cur].page_refs = NULL; ++ (*cur)++; ++ if (pf != NULL) { ++ break; ++ } ++ } ++ return pf; ++} ++ ++static int cslide_count_node_pfs(struct cslide_pid_params *params) ++{ ++ struct page_refs *page_refs = NULL; ++ struct page_refs *last = NULL; ++ unsigned int pid = params->pid; ++ int batch_size = BATCHSIZE; ++ void **pages = NULL; ++ int *status = NULL; ++ int actual_num = 0; ++ int ret = -1; ++ int vma_i = 0; ++ ++ if (params->vmas == NULL || params->vma_pf == NULL) { ++ return 0; ++ } ++ ++ status = malloc(sizeof(int) * batch_size); ++ if (status == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "malloc status fail\n"); ++ return -1; ++ } ++ ++ pages = malloc(sizeof(void *) * batch_size); ++ if (pages == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "malloc pages fail\n"); ++ goto free_status; ++ } ++ ++ page_refs = next_vma_pf(params, &vma_i); ++ last = page_refs; ++ while (page_refs != NULL) { ++ pages[actual_num++] = (void *)page_refs->addr; ++ if (page_refs->next == NULL) { ++ page_refs->next = next_vma_pf(params, &vma_i); ++ } ++ if (actual_num == batch_size || page_refs->next == NULL) { ++ if (move_pages(pid, actual_num, pages, NULL, status, MPOL_MF_MOVE_ALL) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get page refs numa node fail\n"); ++ goto free_pages; ++ } ++ insert_count_pfs(params->count_page_refs, last, status, actual_num); ++ last = page_refs->next; ++ actual_num = 0; ++ } ++ page_refs = page_refs->next; ++ } ++ setup_count_pfs_tail(params->count_page_refs, params->count); ++ ret = 0; ++ ++free_pages: ++ free(pages); ++ pages = NULL; ++free_status: ++ free(status); ++ status = NULL; ++ return ret; ++} ++ ++static inline bool cap_avail(struct ctrl_cap *cap) ++{ ++ return cap->used < cap->cap; ++} ++ ++/* return true if cap is still available */ ++static inline bool cap_cost(struct ctrl_cap *cap, long long *cost) ++{ ++ if (*cost < cap->cap - cap->used) { ++ cap->used += *cost; ++ return true; ++ } ++ ++ *cost = cap->cap - cap->used; ++ cap->used = cap->cap; ++ return false; ++} ++ ++/* return true if node can move hot pages */ ++static bool node_cal_hot_can_move(struct node_ctrl *node_ctrl) ++{ ++ long long can_move; ++ ++ if (node_ctrl->quota < node_ctrl->free) { ++ can_move = node_ctrl->quota; ++ } else { ++ can_move = node_ctrl->free + (node_ctrl->quota - node_ctrl->free) / 2; ++ if (can_move > node_ctrl->free + node_ctrl->cold_free) { ++ can_move = node_ctrl->free + node_ctrl->cold_free; ++ } ++ } ++ ++ if (can_move > node_ctrl->total) { ++ can_move = node_ctrl->total; ++ } ++ node_ctrl->hot_move_cap.cap = can_move; ++ return can_move > 0; ++} ++ ++static inline bool node_can_move_hot(struct node_ctrl *node_ctrl) ++{ ++ return cap_avail(&node_ctrl->hot_move_cap); ++} ++ ++static inline bool node_move_hot(struct node_ctrl *node_ctrl, long long *target) ++{ ++ return cap_cost(&node_ctrl->hot_move_cap, target); ++} ++ ++static void node_update_hot_move(struct node_ctrl *node_ctrl) ++{ ++ long long hot_move = node_ctrl->hot_move_cap.used; ++ ++ if (hot_move > node_ctrl->free) { ++ node_ctrl->cold_replaced += hot_move - node_ctrl->free; ++ node_ctrl->quota -= node_ctrl->free + (hot_move - node_ctrl->free) * 2; ++ node_ctrl->cold_free += node_ctrl->free; ++ node_ctrl->free = 0; ++ } else { ++ node_ctrl->free -= hot_move; ++ node_ctrl->quota -= hot_move; ++ node_ctrl->cold_free += hot_move; ++ } ++} ++ ++/* return true if node can prefetch hot pages */ ++static bool node_cal_hot_can_prefetch(struct node_ctrl *node_ctrl) ++{ ++ long long can_prefetch; ++ ++ if (node_ctrl->free <= node_ctrl->reserve) { ++ can_prefetch = 0; ++ goto exit; ++ } ++ ++ can_prefetch = node_ctrl->free - node_ctrl->reserve; ++ if (can_prefetch > node_ctrl->quota) { ++ can_prefetch = node_ctrl->quota; ++ } ++ ++exit: ++ node_ctrl->hot_prefetch_cap.cap = can_prefetch; ++ return can_prefetch > 0; ++} ++ ++static inline bool node_can_prefetch_hot(struct node_ctrl *node_ctrl) ++{ ++ return cap_avail(&node_ctrl->hot_prefetch_cap); ++} ++ ++static inline bool node_prefetch_hot(struct node_ctrl *node_ctrl, long long *target) ++{ ++ return cap_cost(&node_ctrl->hot_prefetch_cap, target); ++} ++ ++static void node_update_hot_prefetch(struct node_ctrl *node_ctrl) ++{ ++ long long hot_prefetch = node_ctrl->hot_prefetch_cap.used; ++ ++ node_ctrl->free -= hot_prefetch; ++ node_ctrl->quota -= hot_prefetch; ++ node_ctrl->cold_free += hot_prefetch; ++} ++ ++static bool node_cal_cold_can_move(struct node_ctrl *node_ctrl) ++{ ++ long long can_move; ++ ++ can_move = node_ctrl->quota < node_ctrl->reserve - node_ctrl->free ? node_ctrl->quota : node_ctrl->reserve - node_ctrl->free; ++ if (can_move > node_ctrl->cold_free) { ++ can_move = node_ctrl->cold_free; ++ } ++ if (can_move < 0) { ++ can_move = 0; ++ } ++ ++ node_ctrl->cold_move_cap.cap = can_move + node_ctrl->cold_replaced; ++ return node_ctrl->cold_move_cap.cap > 0; ++} ++ ++static inline bool node_can_move_cold(struct node_ctrl *node_ctrl) ++{ ++ return cap_avail(&node_ctrl->cold_move_cap); ++} ++ ++/* return true if still can move cold pages */ ++static inline bool node_move_cold(struct node_ctrl *node_ctrl, long long *target) ++{ ++ return cap_cost(&node_ctrl->cold_move_cap, target); ++} ++ ++static int init_flow_ctrl(struct flow_ctrl *ctrl, struct sys_mem *sys_mem, struct node_map *node_map, long long quota, long long reserve) ++{ ++ struct node_pair *pair = NULL; ++ struct node_ctrl *tmp = NULL; ++ int i; ++ ++ ctrl->node_ctrl = calloc(node_map->cur_num, sizeof(struct node_ctrl)); ++ if (ctrl->node_ctrl == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc memory for node_ctrl fail\n"); ++ return -1; ++ } ++ ++ ctrl->pair_num = node_map->cur_num; ++ ctrl->hot_enough = 0; ++ ctrl->cold_enough = 0; ++ ctrl->prefetch_enough = 0; ++ for (i = 0; i < ctrl->pair_num; i++) { ++ pair = &node_map->pair[i]; ++ tmp = &ctrl->node_ctrl[i]; ++ tmp->cold_free = sys_mem->node_mem[pair->cold_node].huge_free; ++ tmp->free = sys_mem->node_mem[pair->hot_node].huge_free; ++ tmp->total = sys_mem->node_mem[pair->hot_node].huge_total; ++ tmp->quota = quota; ++ tmp->reserve = reserve; ++ } ++ return 0; ++} ++ ++static void flow_cal_hot_can_move(struct flow_ctrl *ctrl) ++{ ++ int i; ++ ++ for (i = 0; i < ctrl->pair_num; i++) { ++ if (!node_cal_hot_can_move(&ctrl->node_ctrl[i])) { ++ ctrl->hot_enough++; ++ } ++ } ++} ++ ++static inline bool is_hot_enough(struct flow_ctrl *ctrl) ++{ ++ return ctrl->hot_enough == ctrl->pair_num; ++} ++ ++static long long ctrl_hot_move(struct flow_ctrl *ctrl, long long target, int node) ++{ ++ struct node_ctrl *node_ctrl = &ctrl->node_ctrl[node]; ++ ++ if (!node_can_move_hot(node_ctrl)) { ++ return 0; ++ } ++ ++ if (!node_move_hot(node_ctrl, &target)) { ++ ctrl->hot_enough++; ++ } ++ ++ return target; ++} ++ ++static void flow_cal_hot_can_prefetch(struct flow_ctrl *ctrl) ++{ ++ int i; ++ ++ for (i = 0; i < ctrl->pair_num; i++) { ++ node_update_hot_move(&ctrl->node_ctrl[i]); ++ if (!node_cal_hot_can_prefetch(&ctrl->node_ctrl[i])) { ++ ctrl->prefetch_enough++; ++ } ++ } ++} ++ ++static inline bool is_prefetch_enough(struct flow_ctrl *ctrl) ++{ ++ return ctrl->prefetch_enough == ctrl->pair_num; ++} ++ ++static long long ctrl_prefetch_hot(struct flow_ctrl *ctrl, long long target, int node) ++{ ++ struct node_ctrl *node_ctrl = &ctrl->node_ctrl[node]; ++ ++ if (!node_can_prefetch_hot(node_ctrl)) { ++ return 0; ++ } ++ ++ if (!node_prefetch_hot(node_ctrl, &target)) { ++ ctrl->prefetch_enough++; ++ } ++ ++ return target; ++} ++ ++static void flow_cal_cold_can_move(struct flow_ctrl *ctrl) ++{ ++ int i; ++ ++ for (i = 0; i < ctrl->pair_num; i++) { ++ node_update_hot_prefetch(&ctrl->node_ctrl[i]); ++ if (!node_cal_cold_can_move(&ctrl->node_ctrl[i])) { ++ ctrl->cold_enough++; ++ } ++ } ++} ++ ++static inline bool is_cold_enough(struct flow_ctrl *ctrl) ++{ ++ return ctrl->cold_enough == ctrl->pair_num; ++} ++ ++static long long ctrl_cold_move(struct flow_ctrl *ctrl, long long target, int node) ++{ ++ struct node_ctrl *node_ctrl = &ctrl->node_ctrl[node]; ++ ++ if (!node_can_move_cold(node_ctrl)) { ++ return 0; ++ } ++ ++ if (!node_move_cold(node_ctrl, &target)) { ++ ctrl->cold_enough++; ++ } ++ ++ return target; ++} ++ ++static void destroy_flow_ctrl(struct flow_ctrl *ctrl) ++{ ++ free(ctrl->node_ctrl); ++ ctrl->node_ctrl = NULL; ++} ++ ++static void do_filter(struct page_filter *filter, struct cslide_eng_params *eng_params) ++{ ++ struct cslide_pid_params *params = NULL; ++ struct count_page_refs *cpf = NULL; ++ struct memory_grade *memory_grade = NULL; ++ struct node_pair *pair = NULL; ++ int pair_num = eng_params->node_map.cur_num; ++ int i, j; ++ ++ filter->flow_cal_func(filter->ctrl); ++ if (filter->flow_enough(filter->ctrl)) { ++ return; ++ } ++ ++ for (i = filter->count_start; i != filter->count_end; i += filter->count_step) { ++ factory_foreach_working_pid_params(params, &eng_params->factory) { ++ cpf = ¶ms->count_page_refs[i]; ++ for (j = 0; j < pair_num; j++) { ++ pair = &eng_params->node_map.pair[j]; ++ memory_grade = ¶ms->memory_grade[j]; ++ filter->filter_policy(filter, pair, cpf, memory_grade); ++ if (filter->flow_enough(filter->ctrl)) { ++ return; ++ } ++ } ++ } ++ } ++} ++ ++static void to_hot_policy(struct page_filter *filter, struct node_pair *pair, struct count_page_refs *cpf, struct memory_grade *memory_grade) ++{ ++ long long can_move; ++ struct node_page_refs *npf = &cpf->node_pfs[pair->cold_node]; ++ ++ can_move = filter->flow_move_func(filter->ctrl, npf->size, pair->index); ++ move_npf_to_list(npf, &memory_grade->hot_pages, can_move); ++} ++ ++static void to_cold_policy(struct page_filter *filter, struct node_pair *pair, struct count_page_refs *cpf, struct memory_grade *memory_grade) ++{ ++ long long can_move; ++ struct node_page_refs *npf = &cpf->node_pfs[pair->hot_node]; ++ ++ can_move = filter->flow_move_func(filter->ctrl, npf->size, pair->index); ++ move_npf_to_list(npf, &memory_grade->cold_pages, can_move); ++} ++ ++static void move_hot_pages(struct cslide_eng_params *eng_params, struct flow_ctrl *ctrl) ++{ ++ struct page_filter filter; ++ filter.flow_cal_func = flow_cal_hot_can_move; ++ filter.flow_move_func = ctrl_hot_move; ++ filter.flow_enough = is_hot_enough; ++ filter.filter_policy = to_hot_policy; ++ filter.ctrl = ctrl; ++ filter.count_start = eng_params->loop; ++ filter.count_end = eng_params->hot_threshold - 1; ++ filter.count_step = -1; ++ do_filter(&filter, eng_params); ++} ++ ++static void prefetch_hot_pages(struct cslide_eng_params *eng_params, struct flow_ctrl *ctrl) ++{ ++ struct page_filter filter; ++ filter.flow_cal_func = flow_cal_hot_can_prefetch; ++ filter.flow_move_func = ctrl_prefetch_hot; ++ filter.flow_enough = is_prefetch_enough; ++ filter.filter_policy = to_hot_policy; ++ filter.ctrl = ctrl; ++ filter.count_start = eng_params->hot_threshold - 1; ++ filter.count_end = -1; ++ filter.count_step = -1; ++ do_filter(&filter, eng_params); ++} ++ ++static void move_cold_pages(struct cslide_eng_params *eng_params, struct flow_ctrl *ctrl) ++{ ++ struct page_filter filter; ++ filter.flow_cal_func = flow_cal_cold_can_move; ++ filter.flow_move_func = ctrl_cold_move; ++ filter.flow_enough = is_cold_enough; ++ filter.filter_policy = to_cold_policy; ++ filter.ctrl = ctrl; ++ filter.count_start = 0; ++ filter.count_end = eng_params->hot_threshold; ++ filter.count_step = 1; ++ do_filter(&filter, eng_params); ++} ++ ++static void cslide_filter_pfs(struct cslide_eng_params *eng_params) ++{ ++ struct flow_ctrl ctrl; ++ long long quota = (long long)eng_params->mig_quota * HUGE_1M_SIZE; ++ long long reserve = (long long)eng_params->hot_reserve * HUGE_1M_SIZE; ++ ++ if (init_flow_ctrl(&ctrl, &eng_params->mem, &eng_params->node_map, quota, reserve) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "init_flow_ctrl fail\n"); ++ return; ++ } ++ ++ move_hot_pages(eng_params, &ctrl); ++ prefetch_hot_pages(eng_params, &ctrl); ++ move_cold_pages(eng_params, &ctrl); ++ ++ destroy_flow_ctrl(&ctrl); ++} ++ ++static int cslide_policy(struct cslide_eng_params *eng_params) ++{ ++ struct cslide_pid_params *pid_params = NULL; ++ int ret; ++ ++ factory_foreach_working_pid_params(pid_params, &eng_params->factory) { ++ ret = cslide_count_node_pfs(pid_params); ++ if (ret != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "count node page refs fail\n"); ++ return ret; ++ } ++ } ++ ++ cslide_filter_pfs(eng_params); ++ return 0; ++} ++ ++static void sort_add_vma_pf(struct vma_pf *vma_pf) ++{ ++ struct vma_pf **iter = &g_share_vma_head; ++ ++ for (; *iter != NULL && (*iter)->vma->inode < vma_pf->vma->inode; iter = &((*iter)->next)) { ++ ; ++ } ++ ++ vma_pf->next = *iter; ++ *iter = vma_pf; ++} ++ ++static bool is_share(struct vma_pf *vma_pf) ++{ ++ struct vma *vma = vma_pf->vma; ++ ++ if (vma->inode != 0 && vma->stat[VMA_STAT_MAY_SHARE]) { ++ return true; ++ } ++ ++ return false; ++} ++ ++static inline uint64_t to_offset(struct page_offset *po) ++{ ++ return po->page_refs->addr + po->to_offset; ++} ++ ++static int page_offset_cmp(const void *a, const void *b) ++{ ++ struct page_offset *l = (struct page_offset *)a; ++ struct page_offset *r = (struct page_offset *)b; ++ ++ return to_offset(l) - to_offset(r); ++} ++ ++static inline void init_merge_po(struct page_offset *to_merge_po, int count) ++{ ++ qsort(to_merge_po, count, sizeof(struct page_offset), page_offset_cmp); ++} ++ ++static void next_po(struct page_offset *to_merge_po, int *count) ++{ ++ struct page_offset *po = to_merge_po; ++ struct page_offset tmp; ++ uint64_t offset; ++ int i; ++ ++ po->page_refs = po->page_refs->next; ++ if (po->page_refs == NULL) { ++ for (i = 1; i < *count; i++) { ++ to_merge_po[i - 1] = to_merge_po[i]; ++ } ++ (*count)--; ++ return; ++ } ++ ++ tmp = *po; ++ offset = to_offset(po); ++ for (i = 1; i < *count; i++) { ++ if (to_offset(&to_merge_po[i]) >= offset) { ++ break; ++ } ++ to_merge_po[i - 1] = to_merge_po[i]; ++ } ++ to_merge_po[i - 1] = tmp; ++} ++ ++static void merge_share_pfs(struct page_refs **share_pfs, int share_pfs_num) ++{ ++ int max_count = -1; ++ struct page_refs *max_pf = NULL; ++ int i; ++ ++ /* only keep one page_refs with max count */ ++ for (i = 0; i < share_pfs_num; i++) { ++ if (share_pfs[i]->count > max_count) { ++ max_pf = share_pfs[i]; ++ max_count = share_pfs[i]->count; ++ } ++ share_pfs[i]->count = -1; ++ } ++ max_pf->count = max_count; ++} ++ ++static int do_merge_vma_pf(struct vma_pf *vma_pf, int count) ++{ ++ struct page_refs **share_pfs = NULL; ++ struct page_offset *to_merge_po = NULL; ++ struct page_offset *iter = NULL; ++ int share_pfs_num; ++ uint64_t cur_offset = 0; ++ uint64_t next_offset; ++ int i; ++ ++ share_pfs = calloc(count, sizeof(struct page_refs *)); ++ if (share_pfs == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc share_pfs fail\n"); ++ return -1; ++ } ++ ++ to_merge_po = calloc(count, sizeof(struct page_offset)); ++ if (to_merge_po == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc iter_pfs fail\n"); ++ free(share_pfs); ++ return -1; ++ } ++ ++ for (i = 0; i < count; i++) { ++ to_merge_po[i].page_refs = vma_pf->page_refs; ++ to_merge_po[i].to_offset = vma_pf->vma->offset - vma_pf->vma->start; ++ vma_pf = vma_pf->next; ++ } ++ ++ init_merge_po(to_merge_po, count); ++ iter = to_merge_po; ++ share_pfs[0] = iter->page_refs; ++ share_pfs_num = 1; ++ cur_offset = to_offset(iter); ++ ++ for (next_po(to_merge_po, &count); count > 0; next_po(to_merge_po, &count)) { ++ iter = to_merge_po; ++ next_offset = to_offset(iter); ++ if (next_offset == cur_offset) { ++ share_pfs[share_pfs_num] = iter->page_refs; ++ share_pfs_num++; ++ } else { ++ if (share_pfs_num > 1) { ++ merge_share_pfs(share_pfs, share_pfs_num); ++ } ++ share_pfs[0] = iter->page_refs; ++ share_pfs_num = 1; ++ cur_offset = next_offset; ++ } ++ ++ } ++ if (share_pfs_num > 1) { ++ merge_share_pfs(share_pfs, share_pfs_num); ++ } ++ ++ free(to_merge_po); ++ free(share_pfs); ++ return 0; ++} ++ ++static int cslide_merge_share_vmas(struct cslide_eng_params *eng_params) ++{ ++ struct cslide_pid_params *pid_params = NULL; ++ struct vma_pf *vma_pf = NULL; ++ struct vma_pf *iter = NULL; ++ int count; ++ uint64_t i; ++ ++ factory_foreach_working_pid_params(pid_params, &eng_params->factory) { ++ vma_pf = pid_params->vma_pf; ++ if (vma_pf == NULL) { ++ continue; ++ } ++ for (i = 0; i < pid_params->vmas->vma_cnt; i++) { ++ if (is_share(&vma_pf[i])) { ++ sort_add_vma_pf(&vma_pf[i]); ++ } ++ } ++ } ++ ++ vma_pf = g_share_vma_head; ++ while (vma_pf != NULL) { ++ for (iter = vma_pf->next, count = 1; iter != NULL && iter->vma->inode == vma_pf->vma->inode; iter = iter->next, count++) { ++ ; ++ } ++ if (count > 1) { ++ if (do_merge_vma_pf(vma_pf, count) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "merge vma with inode %lld fail\n", vma_pf->vma->inode); ++ g_share_vma_head = NULL; ++ return -1; ++ } ++ } ++ vma_pf = iter; ++ } ++ g_share_vma_head = NULL; ++ return 0; ++} ++ ++static int cslide_get_vmas(struct cslide_pid_params *pid_params) ++{ ++ struct cslide_task_params *task_params = pid_params->task_params; ++ struct vma *vma = NULL; ++ char pid[PID_STR_MAX_LEN] = {0}; ++ uint64_t i; ++ ++ if (snprintf_s(pid, PID_STR_MAX_LEN, PID_STR_MAX_LEN - 1, "%u", pid_params->pid) <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "sprintf pid %u fail\n", pid_params->pid); ++ return -1; ++ } ++ pid_params->vmas = get_vmas_with_flags(pid, task_params->vmflags_array, task_params->vmflags_num, task_params->anon_only); ++ if (pid_params->vmas == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get vmas for %s fail\n", pid); ++ return -1; ++ } ++ ++ pid_params->vma_pf = calloc(pid_params->vmas->vma_cnt, sizeof(struct vma_pf)); ++ if (pid_params->vma_pf == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc memory for vma_pf fail\n"); ++ goto free_vmas; ++ } ++ ++ vma = pid_params->vmas->vma_list; ++ for (i = 0; i < pid_params->vmas->vma_cnt; i++) { ++ pid_params->vma_pf[i].vma = vma; ++ vma = vma->next; ++ } ++ return 0; ++ ++free_vmas: ++ free_vmas(pid_params->vmas); ++ pid_params->vmas = NULL; ++ return -1; ++} ++ ++static void cslide_free_vmas(struct cslide_pid_params *params) ++{ ++ uint64_t i; ++ ++ if (params->vmas == NULL) { ++ return; ++ } ++ ++ for (i = 0; i < params->vmas->vma_cnt; i++) { ++ clean_page_refs_unexpected(¶ms->vma_pf[i].page_refs); ++ } ++ free(params->vma_pf); ++ params->vma_pf = NULL; ++ free_vmas(params->vmas); ++ params->vmas = NULL; ++} ++ ++static int cslide_scan_vmas(struct cslide_pid_params *params) ++{ ++ char pid[PID_STR_MAX_LEN] = {0}; ++ struct vmas *vmas = params->vmas; ++ struct vma *vma = NULL; ++ struct vma_pf *vma_pf = NULL; ++ FILE *scan_fp = NULL; ++ struct walk_address walk_address; ++ uint64_t i; ++ int fd; ++ ++ if (snprintf_s(pid, PID_STR_MAX_LEN, PID_STR_MAX_LEN - 1, "%u", params->pid) <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "snpintf pid %u fail\n", params->pid); ++ return -1; ++ } ++ ++ scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, SCAN_AS_HUGE, "r"); ++ if (scan_fp == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "open %s file for pid %u fail\n", IDLE_SCAN_FILE, params->pid); ++ params->vma_pf = NULL; ++ return -1; ++ } ++ ++ fd = fileno(scan_fp); ++ if (fd == -1) { ++ fclose(scan_fp); ++ etmemd_log(ETMEMD_LOG_ERR, "fileno file fail for %s\n", IDLE_SCAN_FILE); ++ return -1; ++ } ++ for (i = 0; i < vmas->vma_cnt; i++) { ++ vma_pf = ¶ms->vma_pf[i]; ++ vma = vma_pf->vma; ++ walk_address.walk_start = vma->start; ++ walk_address.walk_end = vma->end; ++ if (walk_vmas(fd, &walk_address, &vma_pf->page_refs, NULL) == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "scan vma start %llu end %llu fail\n", vma->start, vma->end); ++ cslide_free_vmas(params); ++ fclose(scan_fp); ++ return -1; ++ } ++ } ++ ++ fclose(scan_fp); ++ return 0; ++} ++ ++static int cslide_do_scan(struct cslide_eng_params *eng_params) ++{ ++ struct cslide_pid_params *iter = NULL; ++ int i; ++ ++ factory_foreach_working_pid_params(iter, &eng_params->factory) { ++ if (cslide_get_vmas(iter) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide get vmas fail\n"); ++ continue; ++ } ++ } ++ ++ for (i = 0; i < eng_params->loop; i++) { ++ factory_foreach_working_pid_params(iter, &eng_params->factory) { ++ if (iter->vmas == NULL) { ++ continue; ++ } ++ if (cslide_scan_vmas(iter) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide scan vmas fail\n"); ++ continue; ++ } ++ } ++ sleep(eng_params->sleep); ++ } ++ ++ if (cslide_merge_share_vmas(eng_params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide merge share vams fail\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int do_migrate_pages(unsigned int pid, struct page_refs *page_refs, int node) ++{ ++ int batch_size = BATCHSIZE; ++ int ret = -1; ++ void **pages = NULL; ++ int *nodes = NULL; ++ int *status = NULL; ++ int actual_num = 0; ++ ++ if (page_refs == NULL) { ++ return 0; ++ } ++ ++ nodes = malloc(sizeof(int) * batch_size); ++ if (nodes == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "malloc nodes fail\n"); ++ return -1; ++ } ++ ++ status = malloc(sizeof(int) * batch_size); ++ if (status == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "malloc status fail\n"); ++ goto free_nodes; ++ } ++ ++ pages = malloc(sizeof(void *) * batch_size); ++ if (pages == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "malloc pages fail\n"); ++ goto free_status; ++ } ++ while (page_refs != NULL) { ++ pages[actual_num] = (void *)page_refs->addr; ++ nodes[actual_num] = node; ++ actual_num++; ++ page_refs = page_refs->next; ++ if (actual_num == batch_size || page_refs == NULL) { ++ ret = move_pages(pid, actual_num, pages, nodes, status, MPOL_MF_MOVE_ALL); ++ actual_num = 0; ++ if (ret != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "task %d move_pages fail with %d errno %d\n", pid, ret, errno); ++ continue; ++ } ++ } ++ } ++ ++ free(pages); ++ pages = NULL; ++free_status: ++ free(status); ++ status = NULL; ++free_nodes: ++ free(nodes); ++ nodes = NULL; ++ return ret; ++} ++ ++static int migrate_single_task(unsigned int pid, const struct memory_grade *memory_grade, int hot_node, int cold_node) ++{ ++ int ret = -1; ++ ++ if (do_migrate_pages(pid, memory_grade->cold_pages, cold_node) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "migrate cold pages fail\n"); ++ return ret; ++ } ++ ++ if (do_migrate_pages(pid, memory_grade->hot_pages, hot_node) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "migrate hot pages fail\n"); ++ return ret; ++ } ++ ++ ret = 0; ++ return ret; ++} ++ ++static int cslide_do_migrate(struct cslide_eng_params *eng_params) ++{ ++ struct cslide_pid_params *iter = NULL; ++ struct node_pair *pair = NULL; ++ int bind_node, i; ++ ++ factory_foreach_working_pid_params(iter, &eng_params->factory) { ++ for (i = 0; i < eng_params->node_map.cur_num; i++) { ++ pair = &eng_params->node_map.pair[i]; ++ bind_node = pair->hot_node < pair->cold_node ? pair->hot_node : pair->cold_node; ++ if (numa_run_on_node(bind_node) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "fail to run on node %d to migrate memory\n", bind_node); ++ } ++ migrate_single_task(iter->pid, &iter->memory_grade[i], pair->hot_node, pair->cold_node); ++ } ++ } ++ if (numa_run_on_node(-1) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "fail to run on all node after migrate memory\n"); ++ } ++ return 0; ++} ++ ++static bool is_node_empty(struct node_mem *mem) ++{ ++ return mem->huge_free == mem->huge_total; ++} ++ ++static bool is_all_cold_node_empty(struct cslide_eng_params *eng_params) ++{ ++ struct sys_mem *mem = &eng_params->mem; ++ struct node_pair *pair = NULL; ++ int i; ++ ++ for (i = 0; i < eng_params->node_map.cur_num; i++) { ++ pair = &eng_params->node_map.pair[i]; ++ if (!is_node_empty(&mem->node_mem[pair->cold_node])) { ++ return false; ++ } ++ } ++ return true; ++} ++ ++static inline bool is_busy(int node_watermark, long long total, long long free) ++{ ++ return free * TO_PCT / total < node_watermark; ++} ++ ++static bool is_node_busy(int node_watermark, struct node_mem *mem) ++{ ++ return is_busy(node_watermark, mem->huge_total, mem->huge_free); ++} ++ ++static bool is_any_hot_node_busy(struct cslide_eng_params *eng_params) ++{ ++ struct sys_mem *mem = &eng_params->mem; ++ struct node_pair *pair = NULL; ++ int node_watermark = eng_params->node_watermark; ++ int i; ++ ++ for (i = 0; i < eng_params->node_map.cur_num; i++) { ++ pair = &eng_params->node_map.pair[i]; ++ if (is_node_busy(node_watermark, &mem->node_mem[pair->hot_node])) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static bool need_migrate(struct cslide_eng_params *eng_params) ++{ ++ if (!is_all_cold_node_empty(eng_params)) { ++ return true; ++ } ++ if (is_any_hot_node_busy(eng_params)) { ++ return true; ++ } ++ ++ return false; ++} ++ ++static void get_node_pages_info(struct cslide_pid_params *pid_params) ++{ ++ struct cslide_eng_params *eng_params = pid_params->eng_params; ++ int n, c; ++ int t = eng_params->hot_threshold; ++ int count = pid_params->count; ++ int actual_t = t > count ? count + 1 : t; ++ int node_num = pid_params->count_page_refs->node_num; ++ struct node_pages_info *info = pid_params->node_pages_info; ++ ++ for (n = 0; n < node_num; n++) { ++ info[n].cold = 0; ++ info[n].hot = 0; ++ ++ for (c = 0; c < actual_t; c++) { ++ info[n].cold += pid_params->count_page_refs[c].node_pfs[n].num * 2 * 1024; ++ } ++ for (; c <= count; c++) { ++ info[n].hot += pid_params->count_page_refs[c].node_pfs[n].num * 2 * 1024; ++ } ++ } ++} ++ ++static void cslide_stat(struct cslide_eng_params *eng_params) ++{ ++ struct cslide_pid_params *iter = NULL; ++ ++ pthread_mutex_lock(&eng_params->stat_mtx); ++ factory_foreach_working_pid_params(iter, &eng_params->factory) { ++ get_node_pages_info(iter); ++ } ++ eng_params->stat_time = time(NULL); ++ pthread_mutex_unlock(&eng_params->stat_mtx); ++} ++ ++static void cslide_clean_params(struct cslide_eng_params *eng_params) ++{ ++ struct cslide_pid_params *iter = NULL; ++ ++ factory_foreach_pid_params(iter, &eng_params->factory) { ++ clean_pid_param(iter); ++ cslide_free_vmas(iter); ++ } ++} ++ ++static void destroy_cslide_eng_params(struct cslide_eng_params *params) ++{ ++ destroy_factory(¶ms->factory); ++ pthread_mutex_destroy(¶ms->stat_mtx); ++ destroy_node_map(¶ms->node_map); ++ destroy_sys_mem(¶ms->mem); ++} ++ ++static int init_cslide_eng_params(struct cslide_eng_params *params) ++{ ++ if (init_sys_mem(¶ms->mem) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "init system memory fail\n"); ++ return -1; ++ } ++ ++ if (init_node_map(¶ms->node_map, params->mem.node_num) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "init_node_map fail\n"); ++ goto destroy_sys_mem; ++ } ++ ++ if (pthread_mutex_init(¶ms->stat_mtx, NULL) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "init stat mutex fail\n"); ++ goto destroy_node_map; ++ } ++ ++ if (init_factory(¶ms->factory) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "init params factory fail\n"); ++ goto destroy_stat_mtx; ++ } ++ ++ return 0; ++ ++destroy_stat_mtx: ++ pthread_mutex_destroy(¶ms->stat_mtx); ++ ++destroy_node_map: ++ destroy_node_map(¶ms->node_map); ++ ++destroy_sys_mem: ++ destroy_sys_mem(¶ms->mem); ++ return -1; ++} ++ ++static void *cslide_main(void *arg) ++{ ++ struct cslide_eng_params *eng_params = (struct cslide_eng_params *)arg; ++ struct sys_mem *mem = NULL; ++ ++ while (true) { ++ factory_update_pid_params(&eng_params->factory); ++ if (eng_params->finish) { ++ etmemd_log(ETMEMD_LOG_DEBUG, "cslide task is stopping...\n"); ++ break; ++ } ++ if (factory_working_empty(&eng_params->factory)) { ++ goto next; ++ } ++ ++ mem = &eng_params->mem; ++ if (get_sys_mem(mem) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get system meminfo fail\n"); ++ goto next; ++ } ++ ++ if (cslide_do_scan(eng_params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide_do_scan fail\n"); ++ goto next; ++ } ++ ++ if (cslide_policy(eng_params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide_policy fail\n"); ++ goto next; ++ } ++ ++ if (!need_migrate(eng_params)) { ++ etmemd_log(ETMEMD_LOG_DEBUG, "no need to migrate\n"); ++ goto next; ++ } ++ ++ if (cslide_do_migrate(eng_params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide_do_migrate fail\n"); ++ goto next; ++ } ++ ++next: ++ cslide_stat(eng_params); ++ sleep(eng_params->interval); ++ cslide_clean_params(eng_params); ++ } ++ ++ factory_update_pid_params(&eng_params->factory); ++ destroy_cslide_eng_params(eng_params); ++ free(eng_params); ++ return NULL; ++} ++ ++static int cslide_alloc_pid_params(struct engine *eng, struct task_pid **tk_pid) ++{ ++ struct cslide_eng_params *eng_params = (struct cslide_eng_params *)eng->params; ++ unsigned pid = (*tk_pid)->pid; ++ struct cslide_pid_params *pid_params = NULL; ++ ++ pid_params = alloc_pid_params(eng_params); ++ if (pid_params == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc cslide pid params fail\n"); ++ return -1; ++ } ++ ++ pid_params->pid = pid; ++ pid_params->eng_params = eng_params; ++ pid_params->task_params = (*tk_pid)->tk->params; ++ (*tk_pid)->params = pid_params; ++ return 0; ++} ++ ++static void cslide_free_pid_params(struct engine *eng, struct task_pid **tk_pid) ++{ ++ struct cslide_eng_params *eng_params = (struct cslide_eng_params *)eng->params; ++ ++ if ((*tk_pid)->params != NULL) { ++ /* clear pid params in factory_update_pid_params in cslide_main */ ++ factory_free_pid_params(&eng_params->factory, (*tk_pid)->params); ++ (*tk_pid)->params = NULL; ++ } ++} ++ ++static int cslide_start_task(struct engine *eng, struct task *tk) ++{ ++ struct cslide_eng_params *eng_params = (struct cslide_eng_params *)eng->params; ++ struct task_pid *task_pid = NULL; ++ ++ for (task_pid = tk->pids; task_pid != NULL; task_pid = task_pid->next) { ++ factory_add_pid_params(&eng_params->factory, task_pid->params); ++ } ++ ++ return 0; ++} ++ ++static void cslide_stop_task(struct engine *eng, struct task *tk) ++{ ++ struct cslide_eng_params *eng_params = (struct cslide_eng_params *)eng->params; ++ struct task_pid *task_pid = NULL; ++ ++ for (task_pid = tk->pids; task_pid != NULL; task_pid = task_pid->next) { ++ factory_remove_pid_params(&eng_params->factory, task_pid->params); ++ } ++} ++ ++static char *get_time_stamp(time_t *t) ++{ ++ char *ts = asctime(localtime(t)); ++ size_t len = strlen(ts); ++ ++ if (ts[len - 1] == '\n') { ++ ts[len - 1] = '\0'; ++ } ++ return ts; ++} ++ ++static int show_task_pages(void *params, int fd) ++{ ++ struct cslide_pid_params *pid_params = (struct cslide_pid_params *)params; ++ struct cslide_eng_params *eng_params = pid_params->eng_params; ++ int node_num = pid_params->count_page_refs->node_num; ++ struct node_pages_info *info = pid_params->node_pages_info; ++ char *time_str = NULL; ++ int n; ++ ++ time_str = get_time_stamp(&eng_params->stat_time); ++ if (time_str != NULL) { ++ dprintf_all(fd, "[%s] ", time_str); ++ } ++ dprintf_all(fd, "task %d pages info (KB):\n", pid_params->pid); ++ dprintf_all(fd, "%5s %10s %10s %10s\n", "node", "used", "hot", "cold"); ++ for (n = 0; n < node_num; n++) { ++ dprintf_all(fd, "%5d %10d %10d %10d\n", n, ++ info[n].hot + info[n].cold, info[n].hot, info[n].cold); ++ } ++ return 0; ++} ++ ++static struct cslide_cmd_item g_task_cmd_items[] = { ++ {"showtaskpages", show_task_pages}, ++}; ++ ++static int show_host_pages(void *params, int fd) ++{ ++ struct cslide_eng_params *eng_params = (struct cslide_eng_params *)params; ++ struct cslide_pid_params *iter = NULL; ++ char *time_str = NULL; ++ int node_num = eng_params->mem.node_num; ++ int n; ++ uint32_t total; ++ struct node_pages_info *info = calloc(node_num, sizeof(struct node_pages_info)); ++ ++ if (info == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc memory for node_page_info fail\n"); ++ return -1; ++ } ++ ++ factory_foreach_working_pid_params(iter, &eng_params->factory) { ++ for (n = 0; n < node_num; n++) { ++ info[n].hot += iter->node_pages_info[n].hot; ++ info[n].cold += iter->node_pages_info[n].cold; ++ } ++ } ++ ++ time_str = get_time_stamp(&eng_params->stat_time); ++ if (time_str != NULL) { ++ dprintf_all(fd, "[%s] ", time_str); ++ } ++ dprintf_all(fd, "host pages info (KB):\n"); ++ dprintf_all(fd, "%5s %10s %10s %10s %10s\n", "node", "total", "used", "hot", "cold"); ++ for (n = 0; n < node_num; n++) { ++ total = eng_params->mem.node_mem[n].huge_total / 1024; ++ dprintf_all(fd, "%5d %10d %10d %10d %10d\n", ++ n, total, info[n].hot + info[n].cold, info[n].hot, info[n].cold); ++ } ++ ++ free(info); ++ return 0; ++} ++ ++struct cslide_cmd_item g_host_cmd_items[] = { ++ {"showhostpages", show_host_pages}, ++}; ++ ++static struct cslide_cmd_item *find_cmd_item(struct cslide_cmd_item *items, unsigned n, char *cmd) ++{ ++ unsigned i; ++ ++ for (i = 0; i < n; i++) { ++ if (strcmp(cmd, items[i].name) == 0) { ++ return &items[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int cslide_engine_do_cmd(struct engine *eng, struct task *tk, char *cmd, int fd) ++{ ++ struct cslide_eng_params *eng_params = (struct cslide_eng_params *)eng->params; ++ struct cslide_pid_params *pid_params = NULL; ++ struct cslide_cmd_item *item = NULL; ++ int ret; ++ ++ if (factory_working_empty(&eng_params->factory)) { ++ etmemd_log(ETMEMD_LOG_ERR, "no working pid under this cslide engine\n"); ++ return -1; ++ } ++ ++ item = find_cmd_item(g_host_cmd_items, ARRAY_SIZE(g_host_cmd_items), cmd); ++ if (item != NULL) { ++ pthread_mutex_lock(&eng_params->stat_mtx); ++ ret = item->func(eng_params, fd); ++ pthread_mutex_unlock(&eng_params->stat_mtx); ++ return ret; ++ } ++ ++ item = find_cmd_item(g_task_cmd_items, ARRAY_SIZE(g_task_cmd_items), cmd); ++ if (item == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide cmd %s is not supportted\n", cmd); ++ return -1; ++ } ++ if (tk == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "task for cslide cmd %s not found\n", cmd); ++ return -1; ++ } ++ ++ if (tk->pids == NULL || tk->pids->params == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "task %s for cslide cmd %s not started\n", tk->name, cmd); ++ return -1; ++ } ++ ++ pid_params = (struct cslide_pid_params *)tk->pids->params; ++ pthread_mutex_lock(&eng_params->stat_mtx); ++ ret = item->func(pid_params, fd); ++ pthread_mutex_unlock(&eng_params->stat_mtx); ++ return ret; ++} ++ ++static int fill_task_anon_only(void *obj, void *val) ++{ ++ int ret = 0; ++ struct cslide_task_params *params = (struct cslide_task_params *)obj; ++ char *anon_only = (char *)val; ++ ++ if (strcmp(anon_only, "yes") == 0) { ++ params->anon_only = true; ++ } else if (strcmp(anon_only, "no") == 0) { ++ params->anon_only = false; ++ } else { ++ etmemd_log(ETMEMD_LOG_ERR, "only_anon : not support %s\n", anon_only); ++ etmemd_log(ETMEMD_LOG_ERR, "only_anon : only support yes/no\n"); ++ ret = -1; ++ } ++ free(val); ++ return ret; ++} ++ ++static int fill_task_vm_flags(void *obj, void *val) ++{ ++ struct cslide_task_params *params = (struct cslide_task_params *)obj; ++ char *vm_flags = (char *)val; ++ ++ params->vmflags_num = split_vmflags(¶ms->vmflags_array, vm_flags); ++ if (params->vmflags_num <= 0) { ++ free(val); ++ etmemd_log(ETMEMD_LOG_ERR, "fill vm flags fail\n"); ++ return -1; ++ } ++ ++ params->vmflags_str = vm_flags; ++ if (params->vmflags_num != 1 || strcmp(params->vmflags_array[0], "ht") != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide only work with ht set\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static struct config_item g_cslide_task_config_items[] = { ++ {"vm_flags", STR_VAL, fill_task_vm_flags, false}, ++ {"anon_only", STR_VAL, fill_task_anon_only, false}, ++}; ++ ++static int cslide_fill_task(GKeyFile *config, struct task *tk) ++{ ++ struct cslide_task_params *params = calloc(1, sizeof(struct cslide_task_params)); ++ ++ if (params == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc cslide task params fail\n"); ++ return -1; ++ } ++ ++ if (parse_file_config(config, TASK_GROUP, g_cslide_task_config_items, ++ ARRAY_SIZE(g_cslide_task_config_items), (void *)params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide fill task params fail\n"); ++ goto exit; ++ } ++ ++ tk->params = params; ++ if (etmemd_get_task_pids(tk) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide fail to get task pids\n"); ++ tk->params = NULL; ++ goto exit; ++ } ++ return 0; ++ ++exit: ++ clear_task_params(params); ++ free(params); ++ return -1; ++} ++ ++static void cslide_clear_task(struct task *tk) ++{ ++ /* clear cslide task params when clear connected cslide pid params */ ++ etmemd_free_task_pids(tk); ++ tk->params = NULL; ++} ++ ++static int fill_node_pair(void *obj, void *val) ++{ ++ struct cslide_eng_params *params = (struct cslide_eng_params *)obj; ++ char *node_pair_str = (char *)val; ++ char *pair = NULL; ++ char *saveptr_pair = NULL; ++ char *hot_node_str = NULL; ++ char *cold_node_str = NULL; ++ char *saveptr_node = NULL; ++ int hot_node, cold_node; ++ struct node_map *map = ¶ms->node_map; ++ struct node_verifier nv; ++ char *pair_delim = " ;"; ++ char *node_delim = " ,"; ++ int ret = -1; ++ ++ if (init_node_verifier(&nv, params->mem.node_num) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "init_node_verifier fail\n"); ++ free(val); ++ return ret; ++ } ++ ++ for (pair = strtok_r(node_pair_str, pair_delim, &saveptr_pair); pair != NULL; pair = strtok_r(NULL, pair_delim, &saveptr_pair)) { ++ hot_node_str = strtok_r(pair, node_delim, &saveptr_node); ++ if (hot_node_str == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "parse hot node failed\n"); ++ goto err; ++ } ++ ++ cold_node_str = strtok_r(NULL, node_delim, &saveptr_node); ++ if (cold_node_str == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "parse cold node failed\n"); ++ goto err; ++ } ++ ++ if (get_int_value(hot_node_str, &hot_node) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "transfer hot node %s to integer fail\n", hot_node_str); ++ goto err; ++ } ++ ++ if (get_int_value(cold_node_str, &cold_node) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "transfer cold node %s to integer fail\n", cold_node_str); ++ goto err; ++ } ++ ++ if (!is_node_valid(&nv, hot_node) || !is_node_valid(&nv, cold_node)) { ++ etmemd_log(ETMEMD_LOG_ERR, "node %d(hot)->%d(cold) invalid\n", hot_node, cold_node); ++ goto err; ++ } ++ ++ if (add_node_pair(map, cold_node, hot_node) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "add %d(hot)->%d(cold) fail\n", hot_node, cold_node); ++ goto err; ++ } ++ } ++ ++ if (has_node_unmap(&nv)) { ++ etmemd_log(ETMEMD_LOG_ERR, "there is node unmap\n"); ++ goto err; ++ } ++ ret = 0; ++ ++err: ++ free(val); ++ destroy_node_verifier(&nv); ++ return ret; ++} ++ ++static int fill_migrate_watermark(void *obj, void *val) ++{ ++ struct cslide_eng_params *params = (struct cslide_eng_params *)obj; ++ int wm = parse_to_int(val); ++ ++ if (wm < MIN_WM || wm > MAX_WM) { ++ etmemd_log(ETMEMD_LOG_ERR, "migrate watermark %d invalid\n", wm); ++ return -1; ++ } ++ params->node_watermark = wm; ++ return 0; ++} ++ ++static int fill_hot_threshold(void *obj, void *val) ++{ ++ struct cslide_eng_params *params = (struct cslide_eng_params *)obj; ++ int t = parse_to_int(val); ++ ++ if (t < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "config hot threshold %d not valid\n", t); ++ return -1; ++ } ++ ++ params->hot_threshold = t; ++ return 0; ++} ++ ++static int fill_hot_reserve(void *obj, void *val) ++{ ++ struct cslide_eng_params *params = (struct cslide_eng_params *)obj; ++ int hot_reserve = parse_to_int(val); ++ ++ params->hot_reserve = hot_reserve; ++ return 0; ++} ++ ++static int fill_mig_quota(void *obj, void *val) ++{ ++ struct cslide_eng_params *params = (struct cslide_eng_params *)obj; ++ int mig_quota = parse_to_int(val); ++ ++ params->mig_quota = mig_quota; ++ return 0; ++} ++ ++static struct config_item cslide_eng_config_items[] = { ++ {"node_pair", STR_VAL, fill_node_pair, false}, ++ {"node_watermark", INT_VAL, fill_migrate_watermark, false}, ++ {"hot_threshold", INT_VAL, fill_hot_threshold, false}, ++ {"node_mig_quota", INT_VAL, fill_mig_quota, false}, ++ {"node_hot_reserve", INT_VAL, fill_hot_reserve, false}, ++}; ++ ++static int cslide_fill_eng(GKeyFile *config, struct engine *eng) ++{ ++ struct cslide_eng_params *params = calloc(1, sizeof(struct cslide_eng_params)); ++ ++ if (params == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc cslide engine params fail\n"); ++ return -1; ++ } ++ ++ if (init_cslide_eng_params(params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "init cslide engine params fail\n"); ++ return -1; ++ } ++ ++ params->loop = eng->proj->loop; ++ params->interval = eng->proj->interval; ++ params->sleep = eng->proj->sleep; ++ if (parse_file_config(config, ENG_GROUP, cslide_eng_config_items, ++ ARRAY_SIZE(cslide_eng_config_items), (void *)params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "cslide fill engine params fail\n"); ++ goto destroy_eng_params; ++ } ++ ++ eng->params = params; ++ if (pthread_create(¶ms->worker, NULL, cslide_main, params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "start cslide main worker fail\n"); ++ goto destroy_eng_params; ++ } ++ ++ return 0; ++ ++destroy_eng_params: ++ destroy_cslide_eng_params(params); ++ return -1; ++} ++ ++static void cslide_clear_eng(struct engine *eng) ++{ ++ struct cslide_eng_params *eng_params = eng->params; ++ /* clear cslide engine params in cslide_main */ ++ eng_params->finish = true; ++ eng->params = NULL; ++} ++ ++struct engine_ops g_cslide_eng_ops = { ++ .fill_eng_params = cslide_fill_eng, ++ .clear_eng_params = cslide_clear_eng, ++ .fill_task_params = cslide_fill_task, ++ .clear_task_params = cslide_clear_task, ++ .alloc_pid_params = cslide_alloc_pid_params, ++ .free_pid_params = cslide_free_pid_params, ++ .start_task = cslide_start_task, ++ .stop_task = cslide_stop_task, ++ .eng_mgt_func = cslide_engine_do_cmd, ++}; ++ ++int fill_engine_type_cslide(struct engine *eng) ++{ ++ eng->ops = &g_cslide_eng_ops; ++ eng->engine_type = CSLIDE_ENGINE; ++ eng->name = "cslide"; ++ return 0; ++} +diff --git a/src/etmemd_src/etmemd_engine.c b/src/etmemd_src/etmemd_engine.c +index 41d8fa5..98a7430 100644 +--- a/src/etmemd_src/etmemd_engine.c ++++ b/src/etmemd_src/etmemd_engine.c +@@ -17,38 +17,82 @@ + #include + #include "etmemd_engine.h" + #include "etmemd_slide.h" ++#include "etmemd_cslide.h" + #include "etmemd_log.h" ++#include "etmemd_common.h" ++#include "etmemd_file.h" + +-const char *etmemd_get_eng_name(enum eng_type type) ++struct engine_item { ++ char *name; ++ int (*fill_eng_func)(struct engine *eng); ++}; ++ ++static struct engine_item g_engine_items[] = { ++ {"slide", fill_engine_type_slide}, ++ {"cslide", fill_engine_type_cslide}, ++}; ++ ++static struct engine_item *find_engine_item(const char *name) + { +- if (type == SLIDE_ENGINE) { +- return "slide"; ++ unsigned i; ++ ++ for (i = 0; i < ARRAY_SIZE(g_engine_items); i++) { ++ if (strcmp(name, g_engine_items[i].name) == 0) { ++ return &g_engine_items[i]; ++ } + } + +- return ""; ++ return NULL; + } + +-struct engine_item g_eng_items[ENGINE_TYPE_CNT] = { +- {SLIDE_ENGINE, fill_engine_type_slide}, +-}; +- +-int fill_engine_type(struct engine *eng, const char *val) ++struct engine *etmemd_engine_add(GKeyFile *config) + { +- int ret = -1; +- int i; ++ struct engine *eng = NULL; ++ struct engine_item *item = NULL; ++ char *name = NULL; + +- for (i = 0; i < ENGINE_TYPE_CNT; i++) { +- if (strcmp(val, etmemd_get_eng_name(g_eng_items[i].eng_type)) == 0) { +- ret = g_eng_items[i].fill_eng_func(eng); +- break; +- } ++ if (g_key_file_has_key(config, ENG_GROUP, "name", NULL) == FALSE) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine name is not set\n"); ++ return NULL; + } + +- if (ret != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid engine type %s\n", val); +- return -1; ++ name = g_key_file_get_string(config, ENG_GROUP, "name", NULL); ++ if (name == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get name string of engine fail\n"); ++ return NULL; + } +- return 0; +-} + ++ item = find_engine_item(name); ++ if (item == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine %s not support\n", name); ++ goto free_name; ++ } + ++ eng = calloc(1, sizeof(struct engine)); ++ if (eng == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc memory for engine fail\n"); ++ goto free_name; ++ } ++ ++ if (item->fill_eng_func(eng) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "fill engine %s fail\n", name); ++ free(eng); ++ eng = NULL; ++ goto free_name; ++ } ++ ++ if (eng->ops == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine %s without operations\n", name); ++ free(eng); ++ eng = NULL; ++ } ++ ++free_name: ++ free(name); ++ return eng; ++} ++ ++void etmemd_engine_remove(struct engine *eng) ++{ ++ free(eng); ++} +diff --git a/src/etmemd_src/etmemd_file.c b/src/etmemd_src/etmemd_file.c +index 1115d7a..ac2654e 100644 +--- a/src/etmemd_src/etmemd_file.c ++++ b/src/etmemd_src/etmemd_file.c +@@ -13,444 +13,52 @@ + * Description: File operation API. + ******************************************************************************/ + +-#include +-#include +-#include +-#include +- +-#include "securec.h" + #include "etmemd_log.h" +-#include "etmemd_common.h" +-#include "etmemd_project.h" +-#include "etmemd_engine.h" + #include "etmemd_file.h" + +-#define MAX_INTERVAL_VALUE 1200 +-#define MAX_SLEEP_VALUE 1200 +-#define MAX_LOOP_VALUE 120 +- +-static int fill_project_interval(struct project *proj, const char *val) ++static int parse_item(GKeyFile *config, char *group_name, struct config_item *item, void *obj) + { +- int value; +- +- if (get_int_value(val, &value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid project interval value.\n"); +- return -1; +- } +- +- if (value < 1 || value > MAX_INTERVAL_VALUE) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid project interval value, must between 1 and 1200.\n"); +- return -1; +- } +- +- proj->interval = value; +- +- return 0; +-} ++ GError *error = NULL; ++ void *val; + +-static int fill_project_loop(struct project *proj, const char *val) +-{ +- int value; +- +- if (get_int_value(val, &value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid project loop value.\n"); +- return -1; +- } +- +- if (value < 1 || value > MAX_LOOP_VALUE) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid project loop value, must between 1 and 120.\n"); +- return -1; +- } +- +- proj->loop = value; +- +- return 0; +-} +- +-static int fill_project_sleep(struct project *proj, const char *val) +-{ +- int value; +- +- if (get_int_value(val, &value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid project sleep value.\n"); +- return -1; +- } +- +- if (value < 1 || value > MAX_SLEEP_VALUE) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid project sleep value, must between 1 and 1200.\n"); +- return -1; +- } +- +- proj->sleep = value; +- +- return 0; +-} +- +-static struct project_item g_project_items[] = { +- {"interval", fill_project_interval, false, false}, +- {"loop", fill_project_loop, false, false}, +- {"sleep", fill_project_sleep, false, false}, +- {NULL, NULL, false, false}, +-}; +- +-static int fill_project_params(struct project *proj, const char *key, +- const char *val) +-{ +- int ret = -1; +- int i = 0; +- +- while (g_project_items[i].proj_sec_name != NULL) { +- if (strcmp(key, g_project_items[i].proj_sec_name) == 0) { +- ret = g_project_items[i].fill_proj_func(proj, val); +- break; ++ if (!g_key_file_has_key(config, group_name, item->key, NULL)) { ++ if (item->option) { ++ return 0; + } +- +- i++; +- } +- +- if (ret != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "parse %s project config section fail\n", key); +- return -1; +- } +- +- g_project_items[i].set = true; +- return 0; +-} +- +-static int fill_task_type(struct task *new_task, const char *val) +-{ +- if (strcmp(val, "pid") != 0 && strcmp(val, "name") != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid task type, must be pid or name.\n"); +- return -1; +- } +- +- if (new_task->type != NULL) { +- etmemd_log(ETMEMD_LOG_WARN, "duplicate config for task type.\n"); +- return 0; +- } +- +- new_task->type = calloc(1, strlen(val) + 1); +- if (new_task->type == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "malloc task type fail.\n"); +- return -1; +- } +- +- if (strncpy_s(new_task->type, strlen(val) + 1, val, strlen(val)) != EOK) { +- etmemd_log(ETMEMD_LOG_ERR, "strncpy_s for task type fail.\n"); +- free(new_task->type); +- new_task->type = NULL; +- return -1; +- } +- +- return 0; +-} +- +-static int fill_task_value(struct task *new_task, const char *val) +-{ +- if (new_task->value != NULL) { +- etmemd_log(ETMEMD_LOG_WARN, "duplicate config for task value.\n"); +- return 0; +- } +- +- new_task->value = calloc(1, strlen(val) + 1); +- if (new_task->value == NULL) { +- etmemd_log(ETMEMD_LOG_WARN, "malloc task value fail.\n"); +- return -1; +- } +- +- if (strncpy_s(new_task->value, strlen(val) + 1, val, strlen(val)) != EOK) { +- etmemd_log(ETMEMD_LOG_ERR, "strncpy_s for task value fail.\n"); +- free(new_task->value); +- new_task->value = NULL; +- return -1; +- } +- +- return 0; +-} +- +-static int fill_task_engine(struct task *new_task, const char *val) +-{ +- if (new_task->eng != NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "engine is already configured\n"); +- return -1; +- } +- +- new_task->eng = (struct engine *)calloc(1, sizeof(struct engine)); +- if (new_task->eng == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "malloc engine fail\n"); +- return -1; +- } +- +- new_task->eng->task = (void *)new_task; +- +- if (fill_engine_type(new_task->eng, val) != 0) { +- free(new_task->eng); +- new_task->eng = NULL; +- return -1; +- } +- +- return 0; +-} +- +-static int fill_task_max_threads(struct task *new_task, const char *val) +-{ +- int value; +- int core; +- +- if (get_int_value(val, &value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid task max_threads value.\n"); ++ etmemd_log(ETMEMD_LOG_ERR, "key %s not set for group %s\n", item->key, group_name); + return -1; + } + +- if (value <= 0) { +- etmemd_log(ETMEMD_LOG_WARN, +- "Thread count is abnormal, set the default minimum of current thread count to 1\n"); +- value = 1; +- } +- +- core = get_nprocs(); +- /* +- * For IO intensive businesses, +- * max-threads is limited to 2N+1 of the maximum number of threads +- * */ +- if (value > 2 * core + 1) { +- etmemd_log(ETMEMD_LOG_WARN, +- "max-threads is limited to 2N+1 of the maximum number of threads\n"); +- value = 2 * core + 1; +- } +- +- new_task->max_threads = value; +- +- return 0; +-} +- +-static struct task_item g_task_items[] = { +- {"type", fill_task_type, false, false}, +- {"value", fill_task_value, false, false}, +- {"engine", fill_task_engine, false, false}, +- {"max_threads", fill_task_max_threads, true, false}, +- {NULL, NULL, false, false}, +-}; +- +-static int fill_task_params(struct task *new_task, const char *key, +- const char *val) +-{ +- int ret = -1; +- int i = 0; +- +- while (g_task_items[i].task_sec_name != NULL) { +- if (strcmp(key, g_task_items[i].task_sec_name) == 0) { +- ret = g_task_items[i].fill_task_func(new_task, val); ++ switch (item->type) { ++ case INT_VAL: ++ val = (void *)(long long)g_key_file_get_integer(config, group_name, item->key, &error); + break; +- } +- +- i++; +- } +- +- if (ret != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "parse %s task config section fail\n", key); +- return -1; +- } +- +- g_task_items[i].set = true; +- return 0; +-} +- +-static int process_engine_param_keyword(const char *get_line, struct engine *eng, +- FILE *conf_file, int *is_param) +-{ +- if (strcmp(get_line, "param") == 0) { +- if (eng == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "must configure engine type first\n"); +- return -1; +- } +- +- if (eng->parse_param_conf(eng, conf_file) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "parse engine parameters fail\n"); ++ case STR_VAL: ++ val = (void *)g_key_file_get_string(config, group_name, item->key, &error); ++ break; ++ default: ++ etmemd_log(ETMEMD_LOG_ERR, "config item type %d not support\n", item->type); + return -1; +- } +- +- *is_param = 1; +- } +- +- return 0; +-} +- +-static bool etmemd_check_task_params(void) +-{ +- int i = 0; +- +- while (g_task_items[i].task_sec_name != NULL) { +- /* do not check for the parameter which is optional */ +- if (g_task_items[i].optional) { +- i++; +- continue; +- } +- +- /* and the other parameters must be set */ +- if (!g_task_items[i].set) { +- etmemd_log(ETMEMD_LOG_ERR, "%s section must be set for task parameters\n", +- g_task_items[i].task_sec_name); +- return false; +- } +- +- /* reset the flag of set of the section, and no need to do this for the optional ones */ +- g_task_items[i].set = false; +- i++; + } + +- return true; +-} +- +-/* +- * new_task created in this function is needed during the whole +- * process life cycle of etmemd, and will be released when +- * etmemd exit in function etmemd_free_task_struct +- * */ +-static int get_task_params(FILE *conf_file, struct project *proj) +-{ +- struct task *new_task = NULL; +- char key[KEY_VALUE_MAX_LEN] = {}; +- char value[KEY_VALUE_MAX_LEN] = {}; +- char *get_line = NULL; +- int is_param = 0; +- +- new_task = (struct task *)calloc(1, sizeof(struct task)); +- if (new_task == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "malloc task fail\n"); ++ if (error != NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get value of key %s fail\n", item->key); + return -1; + } + +- new_task->proj = proj; +- new_task->next = proj->tasks; +- /* set default count of the thread pool to 1 */ +- new_task->max_threads = 1; +- +- while ((get_line = skip_blank_line(conf_file)) != NULL) { +- if (strcmp(get_line, "policies") != 0) { +- if (process_engine_param_keyword(get_line, new_task->eng, +- conf_file, &is_param) != 0) { +- goto out_err; +- } +- +- if (is_param == 1) { +- is_param = 0; +- continue; +- } +- +- if (get_keyword_and_value(get_line, key, value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "get task keyword and value fail\n"); +- goto out_err; +- } +- +- if (fill_task_params(new_task, key, value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "fill task parameter fail\n"); +- goto out_err; +- } +- +- continue; +- } +- +- goto next_task; +- } +- +-next_task: +- if (etmemd_check_task_params()) { +- proj->tasks = new_task; +- } else { +- goto out_err; +- } +- +- if (get_line == NULL) { +- return 0; +- } +- +- return get_task_params(conf_file, proj); +- +-out_err: +- etmemd_free_task_struct(&new_task); +- return -1; ++ return item->fill(obj, val); + } + +-static int get_project_params(FILE *conf_file, struct project *proj) ++int parse_file_config(GKeyFile *config, char *group_name, struct config_item *items, unsigned n, void *obj) + { +- char key[KEY_VALUE_MAX_LEN] = {}; +- char value[KEY_VALUE_MAX_LEN] = {}; +- char *get_line = NULL; +- +- while ((get_line = skip_blank_line(conf_file)) != NULL) { +- if (strcmp(get_line, "policies") != 0) { +- if (get_keyword_and_value(get_line, key, value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "get project keyword and value fail\n"); +- return -1; +- } +- +- if (fill_project_params(proj, key, value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "fill project parameter fail\n"); +- return -1; +- } +- +- continue; +- } ++ unsigned i; + +- if (get_task_params(conf_file, proj) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "get task parameters fail\n"); ++ for (i = 0; i < n; i++) { ++ if (parse_item(config, group_name, &items[i], obj) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "parse config key %s fail\n", items[i].key); + return -1; + } + } + + return 0; + } +- +-static bool etmemd_check_project_params(void) +-{ +- int i = 0; +- +- while (g_project_items[i].proj_sec_name != NULL) { +- /* do not check for the parameter which is optional */ +- if (g_project_items[i].optional) { +- i++; +- continue; +- } +- +- /* and the other parameters must be set */ +- if (!g_project_items[i].set) { +- etmemd_log(ETMEMD_LOG_ERR, "%s section must be set for project parameters\n", +- g_project_items[i].proj_sec_name); +- return false; +- } +- +- /* reset the flag of set of the section, and no need to do this for the optional ones */ +- g_project_items[i].set = false; +- i++; +- } +- +- return true; +-} +- +-int etmemd_fill_proj_by_conf(struct project *proj, FILE *conf_file) +-{ +- char *get_line = NULL; +- +- get_line = skip_blank_line(conf_file); +- if (get_line == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid config file, should not be empty\n"); +- return -1; +- } +- +- if (strcmp(get_line, "options") != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid config file, must begin with \"options\"\n"); +- return -1; +- } +- +- if (get_project_params(conf_file, proj) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "get project parameters fail\n"); +- return -1; +- } +- +- if (!etmemd_check_project_params()) { +- return -1; +- } +- +- return 0; +-} +diff --git a/src/etmemd_src/etmemd_migrate.c b/src/etmemd_src/etmemd_migrate.c +index 3e2f8e8..a7aa9b8 100644 +--- a/src/etmemd_src/etmemd_migrate.c ++++ b/src/etmemd_src/etmemd_migrate.c +@@ -69,7 +69,7 @@ static int etmemd_migrate_mem(const char *pid, const char *grade_path, struct pa + return 0; + } + +- fp = etmemd_get_proc_file(pid, grade_path, "r+"); ++ fp = etmemd_get_proc_file(pid, grade_path, 0, "r+"); + if (fp == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "cannot open %s for pid %s\n", grade_path, pid); + return -1; +diff --git a/src/etmemd_src/etmemd_pool_adapter.c b/src/etmemd_src/etmemd_pool_adapter.c +index 890aae8..417f864 100644 +--- a/src/etmemd_src/etmemd_pool_adapter.c ++++ b/src/etmemd_src/etmemd_pool_adapter.c +@@ -17,17 +17,18 @@ + #include + #include + #include "etmemd_pool_adapter.h" ++#include "etmemd_engine.h" + +-static void push_ctrl_workflow(struct task_pid **tk_pid) ++static void push_ctrl_workflow(struct task_pid **tk_pid, void *(*exector)(void *)) + { + struct task_pid *curr_pid = NULL; + struct task *tk = (*tk_pid)->tk; + while (*tk_pid != NULL) { + if (threadpool_add_worker(tk->threadpool_inst, +- tk->workflow_engine, ++ exector, + (*tk_pid)) != 0) { + etmemd_log(ETMEMD_LOG_DEBUG, "Failed to push < pid %u, Task_value %s, project_name %s >\n", +- (*tk_pid)->pid, tk->value, tk->proj->name); ++ (*tk_pid)->pid, tk->value, tk->eng->proj->name); + curr_pid = *tk_pid; + *tk_pid = (*tk_pid)->next; + free_task_pid_mem(&curr_pid); +@@ -40,18 +41,19 @@ static void push_ctrl_workflow(struct task_pid **tk_pid) + + static void *launch_threadtimer_executor(void *arg) + { +- struct task *tk = (struct task *)arg; ++ struct task_executor *executor = (struct task_executor*)arg; ++ struct task *tk = executor->tk; + thread_pool *pool_inst = NULL; + bool done = false; + int execution_size; + int scheduing_count; + +- if (tk->proj->start) { ++ if (tk->eng->proj->start) { + if (etmemd_get_task_pids(tk) != 0) { + return NULL; + } + +- push_ctrl_workflow(&tk->pids); ++ push_ctrl_workflow(&tk->pids, executor->func); + + threadpool_notify(tk->threadpool_inst); + +@@ -72,32 +74,34 @@ static void *launch_threadtimer_executor(void *arg) + return NULL; + } + +-int start_threadpool_work(struct task *tk) ++int start_threadpool_work(struct task_executor *executor) + { ++ struct task *tk = executor->tk; ++ + etmemd_log(ETMEMD_LOG_DEBUG, "start etmem for Task_value %s, project_name %s\n", +- tk->value, tk->proj->name); ++ tk->value, tk->eng->proj->name); + + /* create the threadpool first and it will start auto */ + tk->threadpool_inst = threadpool_create(tk->max_threads); + if (tk->threadpool_inst == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "Thread pool creation failed for project <%s> task <%s>.\n", +- tk->proj->name, tk->value); ++ tk->eng->proj->name, tk->value); + return -1; + } + +- tk->timer_inst = thread_timer_create(tk->proj->interval); ++ tk->timer_inst = thread_timer_create(tk->eng->proj->interval); + if (tk->timer_inst == NULL) { + threadpool_stop_and_destroy(&tk->threadpool_inst); + etmemd_log(ETMEMD_LOG_ERR, "Timer task creation failed for project <%s> task <%s>.\n", +- tk->proj->name, tk->value); ++ tk->eng->proj->name, tk->value); + return -1; + } + +- if (thread_timer_start(tk->timer_inst, launch_threadtimer_executor, tk) != 0) { ++ if (thread_timer_start(tk->timer_inst, launch_threadtimer_executor, executor) != 0) { + threadpool_stop_and_destroy(&tk->threadpool_inst); + thread_timer_destroy(&tk->timer_inst); + etmemd_log(ETMEMD_LOG_ERR, "Timer task start failed for project <%s> task <%s>.\n", +- tk->proj->name, tk->value); ++ tk->eng->proj->name, tk->value); + return -1; + } + +@@ -107,11 +111,11 @@ int start_threadpool_work(struct task *tk) + void stop_and_delete_threadpool_work(struct task *tk) + { + etmemd_log(ETMEMD_LOG_DEBUG, "stop and delete task <%s> of project <%s>\n", +- tk->value, tk->proj->name); ++ tk->value, tk->eng->proj->name); + + if (tk->timer_inst == NULL) { + etmemd_log(ETMEMD_LOG_DEBUG, "task <%s> of project <%s> has not been started, return\n", +- tk->value, tk->proj->name); ++ tk->value, tk->eng->proj->name); + return; + } + +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index 7ddc63f..9ead14c 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -29,280 +29,612 @@ + #include "etmemd_file.h" + #include "etmemd_log.h" + ++#define MAX_INTERVAL_VALUE 1200 ++#define MAX_SLEEP_VALUE 1200 ++#define MAX_LOOP_VALUE 120 ++ + static SLIST_HEAD(project_list, project) g_projects = SLIST_HEAD_INITIALIZER(g_projects); + +-static void free_before_delete_project(struct project *proj) ++static struct project *get_proj_by_name(const char *name) + { +- struct task *tmp_tk = NULL; ++ struct project *proj = NULL; ++ ++ SLIST_FOREACH(proj, &g_projects, entry) { ++ if (strcmp(proj->name, name) == 0) { ++ return proj; ++ } ++ } + +- etmemd_safe_free((void **)&proj->name); ++ return NULL; ++} + +- while (proj->tasks != NULL) { +- tmp_tk = proj->tasks; +- proj->tasks = proj->tasks->next; ++static struct engine *get_eng_by_name(struct project *proj, const char *name) ++{ ++ struct engine *eng = proj->engs; + +- etmemd_free_task_pids(tmp_tk); +- etmemd_free_task_struct(&tmp_tk); ++ while (eng != NULL) { ++ if (strcmp(eng->name, name) == 0) { ++ return eng; ++ } ++ eng = eng->next; + } ++ ++ return NULL; + } + +-static FILE *memid_project_open_conf(const char *file_name) ++static struct task *get_task_by_name(struct project *proj, struct engine *eng, const char *name) + { +- FILE *file = NULL; +- char path[PATH_MAX] = {0}; +- struct stat info; +- int r; +- int fd; ++ struct task *tk = eng->tasks; + +- if (realpath(file_name, path) == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "%s should be real path.\n", file_name); +- return NULL; ++ while (tk != NULL) { ++ if (strcmp(tk->name, name) == 0) { ++ return tk; ++ } ++ tk = tk->next; + } + +- fd = open(path, O_RDONLY); +- if (fd == -1) { +- return NULL; ++ return NULL; ++} ++ ++static char *get_obj_key(char *obj_name, const char *group_name) ++{ ++ if (strcmp(obj_name, group_name) == 0) { ++ return "name"; ++ } else { ++ return obj_name; + } ++} ++ ++static enum opt_result project_of_group(GKeyFile *config, const char *group_name, struct project **proj) ++{ ++ *proj = NULL; ++ char *proj_name = NULL; ++ char *key = NULL; + +- r = fstat(fd, &info); +- if (r == -1) { +- close(fd); +- return NULL; ++ key = get_obj_key(PROJ_GROUP, group_name); ++ if (g_key_file_has_key(config, group_name, key, NULL) == FALSE) { ++ etmemd_log(ETMEMD_LOG_ERR, "project name is not set for %s\n", group_name); ++ return OPT_INVAL; + } + +- if (S_ISDIR(info.st_mode)) { +- etmemd_log(ETMEMD_LOG_ERR, "%s should be a file , not a folder.\n", path); +- close(fd); +- return NULL; ++ proj_name = g_key_file_get_string(config, group_name, key, NULL); ++ if (proj_name == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get project name from %s fail\n", group_name); ++ return OPT_INTER_ERR; + } + +- file = fdopen(fd, "r"); ++ *proj = get_proj_by_name(proj_name); + +- return file; ++ free(proj_name); ++ return OPT_SUCCESS; + } + +-static struct project *etmemd_project_init_struct(const char *project_name) ++static enum opt_result engine_of_group(GKeyFile *config, char *group_name, struct project *proj, struct engine **eng) + { +- struct project *proj = NULL; ++ char *key = NULL; ++ char *eng_name = NULL; ++ *eng = NULL; + +- proj = (struct project *)calloc(1, sizeof(struct project)); +- if (proj == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "malloc for project fail.\n"); +- return NULL; ++ key = get_obj_key(ENG_GROUP, group_name); ++ if (g_key_file_has_key(config, group_name, key, NULL) == FALSE) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine is not set for %s\n", group_name); ++ return OPT_INVAL; + } + +- proj->name = calloc(1, strlen(project_name) + 1); +- if (proj->name == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "malloc project name fail.\n"); +- free(proj); +- return NULL; ++ eng_name = g_key_file_get_string(config, group_name, key, NULL); ++ if (eng_name == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get engine name from %s fail\n", group_name); ++ return OPT_INTER_ERR; + } + +- if (strncpy_s(proj->name, strlen(project_name) + 1, project_name, +- strlen(project_name)) != EOK) { +- etmemd_log(ETMEMD_LOG_ERR, "strncpy_s for project name fail\n"); +- free(proj->name); +- proj->name = NULL; +- free(proj); +- return NULL; ++ *eng = get_eng_by_name(proj, eng_name); ++ free(eng_name); ++ return OPT_SUCCESS; ++} ++ ++static enum opt_result task_of_group(GKeyFile *config, char *group_name, struct project *proj, struct engine *eng, struct task **tk) ++{ ++ char *task_name = NULL; ++ char *key = NULL; ++ *tk = NULL; ++ ++ key = get_obj_key(TASK_GROUP, group_name); ++ if (g_key_file_has_key(config, group_name, key, NULL) == FALSE) { ++ etmemd_log(ETMEMD_LOG_ERR, "task name is not set for %s\n", group_name); ++ return OPT_INVAL; ++ } ++ ++ task_name = g_key_file_get_string(config, group_name, key, NULL); ++ if (task_name == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get task name from %s fail\n", group_name); ++ return OPT_INTER_ERR; + } + +- return proj; ++ *tk = get_task_by_name(proj, eng, task_name); ++ free(task_name); ++ return OPT_SUCCESS; + } + +-static struct project *get_proj_by_name(const char *name) ++static enum opt_result get_group_objs(GKeyFile *config, char *group_name, struct project **proj, struct engine **eng, struct task **tk) + { +- struct project *proj = NULL; ++ enum opt_result ret; + +- if (name == NULL || strlen(name) == 0) { +- etmemd_log(ETMEMD_LOG_ERR, "project name must be given and should not be empty.\n"); +- return NULL; ++ /* get project */ ++ ret = project_of_group(config, group_name, proj); ++ if (ret != OPT_SUCCESS) { ++ return ret; + } + +- SLIST_FOREACH(proj, &g_projects, entry) { +- if (strcmp(proj->name, name) == 0) { +- return proj; +- } ++ /* get engine */ ++ if (eng == NULL) { ++ return OPT_SUCCESS; ++ } ++ if (*proj == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "project of group %s not existed\n", group_name); ++ return OPT_PRO_NOEXIST; + } + +- return NULL; ++ ret = engine_of_group(config, group_name, *proj, eng); ++ if (ret != OPT_SUCCESS) { ++ return ret; ++ } ++ ++ /* get task */ ++ if (tk == NULL) { ++ return OPT_SUCCESS; ++ } ++ if (*eng == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine of group %s not existed\n", group_name); ++ return OPT_ENG_NOEXIST; ++ } ++ ++ ret = task_of_group(config, group_name, *proj, *eng, tk); ++ if (ret != OPT_SUCCESS) { ++ return ret; ++ } ++ ++ return OPT_SUCCESS; + } + +-static enum opt_result check_add_params(const char *project_name, const char *file_name) ++static void project_insert_task(struct project *proj, struct engine *eng, struct task *task) + { ++ task->next = eng->tasks; ++ eng->tasks = task; ++ task->eng = eng; ++} ++ ++static void project_remove_task(struct engine *eng, struct task *task) ++{ ++ struct task **iter = &eng->tasks; ++ ++ for (; *iter != NULL && *iter != task; iter = &(*iter)->next) { ++ ; ++ } ++ ++ if (*iter == NULL) { ++ return; ++ } ++ ++ *iter = (*iter)->next; ++ task->next = NULL; ++ task->eng = NULL; ++} ++ ++static void do_remove_task(struct project *proj, struct engine *eng, struct task *tk) ++{ ++ if (proj->start && eng->ops->stop_task != NULL) { ++ eng->ops->stop_task(eng, tk); ++ } ++ if (eng->ops->clear_task_params != NULL) { ++ eng->ops->clear_task_params(tk); ++ } ++ ++ project_remove_task(eng, tk); ++ etmemd_remove_task(tk); ++} ++ ++enum opt_result etmemd_project_add_task(GKeyFile *config) ++{ ++ struct task *tk = NULL; + struct project *proj = NULL; ++ struct engine *eng = NULL; ++ enum opt_result ret; + +- if (project_name == NULL || strlen(project_name) == 0) { +- etmemd_log(ETMEMD_LOG_ERR, "project name must be given and should not be empty.\n"); +- return OPT_INVAL; ++ ret = get_group_objs(config, TASK_GROUP, &proj, &eng, &tk); ++ if (ret != OPT_SUCCESS) { ++ return ret; + } + +- if (strlen(project_name) > PROJECT_NAME_MAX_LEN) { +- etmemd_log(ETMEMD_LOG_ERR, "the length of project name should not be larger than %d\n", +- PROJECT_NAME_MAX_LEN); +- return OPT_INVAL; ++ if (tk != NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "task already exist\n"); ++ return OPT_TASK_EXISTED; + } + +- if (file_name == NULL || strlen(file_name) == 0) { +- etmemd_log(ETMEMD_LOG_ERR, "file name must be given and should not be empty.\n"); +- return OPT_INVAL; ++ tk = etmemd_add_task(config); ++ if (tk == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "create new task fail\n"); ++ return OPT_INTER_ERR; + } + +- if (strlen(file_name) > FILE_NAME_MAX_LEN) { +- etmemd_log(ETMEMD_LOG_ERR, "the length of file name should not be larger than %d\n", +- FILE_NAME_MAX_LEN); +- return OPT_INVAL; ++ project_insert_task(proj, eng, tk); ++ ++ if (eng->ops->fill_task_params != NULL && eng->ops->fill_task_params(config, tk) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "fill task param fail\n"); ++ goto remove_task; + } + +- proj = get_proj_by_name(project_name); +- if (proj != NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "project %s already exist.\n", project_name); +- return OPT_PRO_EXISTED; ++ if (proj->start && eng->ops->start_task(eng, tk) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "start added task %s fail\n", tk->name); ++ goto clear_task; + } + + return OPT_SUCCESS; ++ ++clear_task: ++ if (eng->ops->clear_task_params != NULL) { ++ eng->ops->clear_task_params(tk); ++ } ++ ++remove_task: ++ project_remove_task(eng, tk); ++ etmemd_remove_task(tk); ++ ++ return OPT_INTER_ERR; + } + +-enum opt_result etmemd_project_add(const char *project_name, const char *file_name) ++enum opt_result etmemd_project_remove_task(GKeyFile *config) + { ++ struct task *tk = NULL; + struct project *proj = NULL; +- FILE *file = NULL; ++ struct engine *eng = NULL; + enum opt_result ret; + +- ret = check_add_params(project_name, file_name); +- if (ret != 0) { ++ ret = get_group_objs(config, TASK_GROUP, &proj, &eng, &tk); ++ if (ret != OPT_SUCCESS) { + return ret; + } +- +- file = memid_project_open_conf(file_name); +- if (file == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "open %s fail.\n", file_name); +- return OPT_INVAL; ++ if (tk == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "task not exsit\n"); ++ return OPT_TASK_NOEXIST; + } + +- proj = etmemd_project_init_struct(project_name); +- if (proj == NULL) { +- goto out_close; ++ do_remove_task(proj, eng, tk); ++ return OPT_SUCCESS; ++} ++ ++static void project_insert_engine(struct project *proj, struct engine *eng) ++{ ++ eng->next = proj->engs; ++ proj->engs = eng; ++ eng->proj = proj; ++} ++ ++static void project_remove_engine(struct project *proj, struct engine *eng) ++{ ++ struct engine **iter = &(proj->engs); ++ ++ for (; *iter != NULL && *iter != eng; iter = &(*iter)->next) { ++ ; + } + +- if (etmemd_fill_proj_by_conf(proj, file) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "get project from configuration file fail.\n"); +- free_before_delete_project(proj); +- free(proj); +- proj = NULL; +- goto out_close; ++ if (*iter == NULL) { ++ return; + } + +- SLIST_INSERT_HEAD(&g_projects, proj, entry); +- fclose(file); +- return OPT_SUCCESS; ++ *iter = (*iter)->next; ++ eng->next = NULL; ++ eng->proj = NULL; ++} ++ ++static int project_start_engine(struct project *proj, struct engine *eng) ++{ ++ struct task *tk = eng->tasks; ++ int ret = 0; + +-out_close: +- fclose(file); +- return OPT_INVAL; ++ if (eng->ops->start_task == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine %s not support start\n", eng->name); ++ return -1; ++ } ++ ++ for (; tk != NULL; tk = tk->next) { ++ if (eng->ops->start_task(eng, tk) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "start task %s fail.\n", tk->value); ++ ret = -1; ++ } ++ } ++ return ret; + } + +-static void stop_tasks(struct project *proj) ++static void project_stop_engine(struct project *proj, struct engine *eng) + { +- struct task *curr_task = NULL; ++ struct task *tk = eng->tasks; + +- if (!proj->start) { ++ if (eng->ops->stop_task == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine %s not support stop\n", eng->name); + return; + } ++ for (; tk != NULL; tk = tk->next) { ++ eng->ops->stop_task(eng, tk); ++ } ++} + +- proj->start = false; ++static void do_remove_engine_tasks(struct project *proj, struct engine *eng) ++{ ++ while (eng->tasks != NULL) { ++ do_remove_task(proj, eng, eng->tasks); ++ } ++} + +- curr_task = proj->tasks; +- while (curr_task != NULL) { +- curr_task->stop_etmem(curr_task); +- etmemd_log(ETMEMD_LOG_DEBUG, "Stop for Task_value %s, project_name %s \n", curr_task->value, +- curr_task->proj->name); +- curr_task = curr_task->next; ++static void do_remove_engine(struct project *proj, struct engine *eng) ++{ ++ do_remove_engine_tasks(proj, eng); ++ if (eng->ops->clear_eng_params != NULL) { ++ eng->ops->clear_eng_params(eng); + } ++ ++ project_remove_engine(proj, eng); ++ etmemd_engine_remove(eng); + } + +-enum opt_result etmemd_project_delete(const char *project_name) ++enum opt_result etmemd_project_add_engine(GKeyFile *config) + { ++ struct engine *eng = NULL; + struct project *proj = NULL; ++ enum opt_result ret; + +- proj = get_proj_by_name(project_name); +- if (proj == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "get project fail to delete.\n"); +- return OPT_PRO_NOEXIST; ++ ret = get_group_objs(config, ENG_GROUP, &proj, &eng, NULL); ++ if (ret != OPT_SUCCESS) { ++ return ret; ++ } ++ if (eng != NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine %s exists\n", eng->name); ++ return OPT_ENG_EXISTED; + } + +- stop_tasks(proj); ++ eng = etmemd_engine_add(config); ++ if (eng == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "create engine fail\n"); ++ return OPT_INTER_ERR; ++ } + +- struct task *curr_task = NULL; +- curr_task = proj->tasks; +- while (curr_task != NULL) { +- if (curr_task->delete_etmem != NULL) { +- curr_task->delete_etmem(curr_task); +- curr_task = curr_task->next; +- } ++ project_insert_engine(proj, eng); ++ if (eng->ops->fill_eng_params != NULL && eng->ops->fill_eng_params(config, eng) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "fill %s engine params fail\n", eng->name); ++ project_remove_engine(proj, eng); ++ etmemd_engine_remove(eng); ++ return OPT_INTER_ERR; + } + +- SLIST_REMOVE(&g_projects, proj, project, entry); ++ return OPT_SUCCESS; ++} ++ ++enum opt_result etmemd_project_remove_engine(GKeyFile *config) ++{ ++ struct engine *eng = NULL; ++ struct project *proj = NULL; ++ enum opt_result ret; ++ ++ ret = get_group_objs(config, ENG_GROUP, &proj, &eng, NULL); ++ if (ret != OPT_SUCCESS) { ++ return ret; ++ } ++ if (eng == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "remove engine is not existed\n"); ++ return OPT_ENG_NOEXIST; ++ } ++ ++ do_remove_engine(proj, eng); ++ return OPT_SUCCESS; ++} + +- free_before_delete_project(proj); ++static int fill_project_name(void *obj, void *val) ++{ ++ struct project *proj = (struct project *)obj; ++ char *name = (char *)val; ++ proj->name = name; ++ return 0; ++} ++ ++static int fill_project_loop(void *obj, void *val) ++{ ++ struct project *proj = (struct project *)obj; ++ int loop = parse_to_int(val); ++ if (loop < 1 || loop > MAX_LOOP_VALUE) { ++ etmemd_log(ETMEMD_LOG_ERR, "invalid project loop value %d, it must be between 1 and %d.\n", ++ loop, MAX_LOOP_VALUE); ++ return -1; ++ } ++ ++ proj->loop = loop; ++ return 0; ++} ++ ++static int fill_project_interval(void *obj, void *val) ++{ ++ struct project *proj = (struct project *)obj; ++ int interval = parse_to_int(val); ++ if (interval < 1 || interval > MAX_INTERVAL_VALUE) { ++ etmemd_log(ETMEMD_LOG_ERR, "invalid project interval value %d, it must be between 1 and %d.\n", ++ interval, MAX_INTERVAL_VALUE); ++ return -1; ++ } ++ ++ proj->interval = interval; ++ return 0; ++} ++ ++static int fill_project_sleep(void *obj, void *val) ++{ ++ struct project *proj = (struct project *)obj; ++ int sleep = parse_to_int(val); ++ if (sleep < 1 || sleep > MAX_SLEEP_VALUE) { ++ etmemd_log(ETMEMD_LOG_ERR, "invalid project sleep value %d, it must be between 1 and %d.\n", ++ sleep, MAX_SLEEP_VALUE); ++ return -1; ++ } ++ ++ proj->sleep = sleep; ++ return 0; ++} ++ ++static struct config_item g_project_config_items[] = { ++ {"name", STR_VAL, fill_project_name, false}, ++ {"loop", INT_VAL, fill_project_loop, false}, ++ {"interval", INT_VAL, fill_project_interval, false}, ++ {"sleep", INT_VAL, fill_project_sleep, false}, ++}; ++ ++static void clear_project(struct project *proj) ++{ ++ if (proj->name != NULL) { ++ free(proj->name); ++ proj->name = NULL; ++ } ++} ++ ++static int project_fill_by_conf(GKeyFile *config, struct project *proj) ++{ ++ if (parse_file_config(config, PROJ_GROUP, g_project_config_items, ARRAY_SIZE(g_project_config_items), proj) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "parse project config fail\n"); ++ clear_project(proj); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void do_remove_project(struct project *proj) ++{ ++ SLIST_REMOVE(&g_projects, proj, project, entry); ++ while (proj->engs != NULL) { ++ do_remove_engine(proj, proj->engs); ++ } ++ clear_project(proj); + free(proj); ++} ++ ++enum opt_result etmemd_project_add(GKeyFile *config) ++{ ++ struct project *proj = NULL; ++ enum opt_result ret; ++ ++ ret = project_of_group(config, PROJ_GROUP, &proj); ++ if (ret != OPT_SUCCESS) { ++ return ret; ++ } ++ if (proj != NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "project %s existes\n", proj->name); ++ return OPT_PRO_EXISTED; ++ } ++ ++ proj = (struct project *)calloc(1, sizeof(struct project)); ++ if (proj == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc memory for project fail\n"); ++ return OPT_INTER_ERR; ++ } ++ if (project_fill_by_conf(config, proj) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "fill project from configuration file fail\n"); ++ free(proj); ++ proj = NULL; ++ return OPT_INVAL; ++ } + ++ SLIST_INSERT_HEAD(&g_projects, proj, entry); + return OPT_SUCCESS; + } + +-static void etmemd_project_print_line(void) ++enum opt_result etmemd_project_remove(GKeyFile *config) + { +- int i; ++ struct project *proj = NULL; ++ enum opt_result ret; + +- for (i = 0; i < PROJECT_SHOW_COLM_MAX; i++) { +- printf("-"); ++ ret = get_group_objs(config, PROJ_GROUP, &proj, NULL, NULL); ++ if (ret != OPT_SUCCESS) { ++ return ret; ++ } ++ ++ if (proj == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "remove project not existed\n"); ++ return OPT_PRO_NOEXIST; + } +- printf("\n"); ++ ++ do_remove_project(proj); ++ return OPT_SUCCESS; + } + +-static void etmemd_project_print(const struct project *proj) ++static void etmemd_project_print(int fd, const struct project *proj) + { +- etmemd_project_print_line(); +- printf("project: %s\n\n", proj->name); +- printf("%-8s %-32s %-32s %-32s %-16s\n", +- "number", +- "type", +- "value", +- "engine", +- "started"); +- etmemd_print_tasks(proj->tasks); +- etmemd_project_print_line(); ++ struct engine *eng = NULL; ++ ++ dprintf_all(fd, "project: %s\n", proj->name); ++ dprintf_all(fd, "%-8s %-8s %-16s %-16s %-16s %-8s\n", ++ "number", ++ "type", ++ "value", ++ "name", ++ "engine", ++ "started"); ++ for (eng = proj->engs; eng != NULL; eng = eng->next) { ++ etmemd_print_tasks(fd, eng->tasks, eng->name, proj->start); ++ } + } + +-enum opt_result etmemd_project_show(void) ++enum opt_result etmemd_project_show(const char *project_name, int sock_fd) + { + struct project *proj = NULL; + bool exists = false; + + SLIST_FOREACH(proj, &g_projects, entry) { +- etmemd_project_print(proj); ++ if (project_name != NULL && strcmp(project_name, proj->name) != 0) { ++ continue; ++ } ++ etmemd_project_print(sock_fd, proj); + exists = true; + } + + if (!exists) { +- etmemd_project_print_line(); +- printf("project: no project exits\n\n"); +- etmemd_project_print_line(); ++ if (project_name == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "no project exists\n"); ++ } else { ++ etmemd_log(ETMEMD_LOG_ERR, "project: project %s is not existed\n\n", project_name); ++ } ++ return OPT_PRO_NOEXIST; + } + +- if (fflush(stdout) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "fflush stdout fail.\n"); +- return OPT_INTER_ERR; ++ return OPT_SUCCESS; ++} ++ ++static int start_tasks(struct project *proj) ++{ ++ struct engine *eng = NULL; ++ int ret = 0; ++ ++ for (eng = proj->engs; eng != NULL; eng = eng->next) { ++ if (project_start_engine(proj, eng) != 0) { ++ ret = -1; ++ } + } + +- return OPT_SUCCESS; ++ return ret; ++} ++ ++static void stop_tasks(struct project *proj) ++{ ++ struct engine *eng = NULL; ++ ++ for (eng = proj->engs; eng != NULL; eng = eng->next) { ++ project_stop_engine(proj, eng); ++ } + } + + enum opt_result etmemd_migrate_start(const char *project_name) + { + struct project *proj = NULL; +- struct task *curr_task = NULL; +- int start_task_num = 0; ++ ++ if (project_name == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "project is not set for start cmd\n"); ++ return OPT_INVAL; ++ } + + proj = get_proj_by_name(project_name); + if (proj == NULL) { +@@ -315,27 +647,12 @@ enum opt_result etmemd_migrate_start(const char *project_name) + return OPT_PRO_STARTED; + } + +- proj->start = true; +- +- curr_task = proj->tasks; +- while (curr_task != NULL) { +- if (curr_task->start_etmem(curr_task) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "start task %s fail.\n", +- curr_task->value); +- curr_task = curr_task->next; +- continue; +- } +- +- start_task_num++; +- curr_task = curr_task->next; +- } +- +- if (start_task_num == 0) { +- etmemd_log(ETMEMD_LOG_ERR, "all tasks start fail.\n"); +- proj->start = false; ++ if (start_tasks(proj) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "some task of project %s start fail\n", project_name); + return OPT_INTER_ERR; + } + ++ proj->start = true; + return OPT_SUCCESS; + } + +@@ -343,6 +660,11 @@ enum opt_result etmemd_migrate_stop(const char *project_name) + { + struct project *proj = NULL; + ++ if (project_name == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "project is not set for stop cmd\n"); ++ return OPT_INVAL; ++ } ++ + proj = get_proj_by_name(project_name); + if (proj == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "get project fail.\n"); +@@ -360,16 +682,47 @@ enum opt_result etmemd_migrate_stop(const char *project_name) + return OPT_SUCCESS; + } + ++enum opt_result etmemd_project_mgt_engine(const char *project_name, const char *eng_name, char *cmd, char *task_name, int sock_fd) ++{ ++ struct engine *eng = NULL; ++ struct project *proj = NULL; ++ struct task *tk = NULL; ++ ++ if (project_name == NULL || eng_name == NULL || cmd == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "project, engine and cmd must all be given\n"); ++ return OPT_INVAL; ++ } ++ ++ proj = get_proj_by_name(project_name); ++ if (proj == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "project %s is not existed\n", project_name); ++ return OPT_PRO_NOEXIST; ++ } ++ if (!proj->start) { ++ etmemd_log(ETMEMD_LOG_ERR, "project %s is not started\n", project_name); ++ return OPT_INVAL; ++ } ++ ++ eng = get_eng_by_name(proj, eng_name); ++ if (eng == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine %s is not existed\n", eng_name); ++ return OPT_INVAL; ++ } ++ if (task_name != NULL) { ++ tk = get_task_by_name(proj, eng, task_name); ++ } ++ if (eng->ops->eng_mgt_func(eng, tk, cmd, sock_fd) != 0) { ++ return OPT_INVAL; ++ } ++ return OPT_SUCCESS; ++} ++ + void etmemd_stop_all_projects(void) + { + struct project *proj = NULL; + + while (!SLIST_EMPTY(&g_projects)) { + proj = SLIST_FIRST(&g_projects); +- SLIST_REMOVE_HEAD(&g_projects, entry); +- stop_tasks(proj); +- free_before_delete_project(proj); +- free(proj); +- proj = NULL; ++ do_remove_project(proj); + } + } +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index e74013a..e154083 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -18,11 +18,13 @@ + #include + #include + #include ++#include + #include "securec.h" + #include "etmemd_rpc.h" + #include "etmemd_project.h" + #include "etmemd_common.h" + #include "etmemd_log.h" ++#include "etmemd_file.h" + + /* the max length of sun_path in struct sockaddr_un is 108 */ + #define RPC_ADDR_LEN_MAX 108 +@@ -44,6 +46,9 @@ struct server_rpc_parser g_rpc_parser[] = { + {"proj_name", DECODE_STRING, (void **)&(g_rpc_params.proj_name)}, + {"file_name", DECODE_STRING, (void **)&(g_rpc_params.file_name)}, + {"cmd", DECODE_INT, (void **)&(g_rpc_params.cmd)}, ++ {"eng_name", DECODE_STRING, (void **)&(g_rpc_params.eng_name)}, ++ {"eng_cmd", DECODE_STRING, (void **)&(g_rpc_params.eng_cmd)}, ++ {"task_name", DECODE_STRING, (void **)&(g_rpc_params.task_name)}, + {NULL, DECODE_END, NULL}, + }; + +@@ -51,9 +56,13 @@ struct rpc_resp_msg g_resp_msg_arr[] = { + {OPT_SUCCESS, "success"}, + {OPT_INVAL, "error: invalid parameters"}, + {OPT_PRO_EXISTED, "error: project has been existed"}, ++ {OPT_PRO_NOEXIST, "error: project is not exist"}, + {OPT_PRO_STARTED, "error: project has been started"}, + {OPT_PRO_STOPPED, "error: project has been stopped"}, +- {OPT_PRO_NOEXIST, "error: project is not exist"}, ++ {OPT_ENG_EXISTED, "error: engine has been existed"}, ++ {OPT_ENG_NOEXIST, "error: engine is not exist"}, ++ {OPT_TASK_EXISTED, "error: task has been existed"}, ++ {OPT_TASK_NOEXIST, "error: task is not exist"}, + {OPT_INTER_ERR, "error: etmemd has internal error"}, + {OPT_RET_END, NULL}, + }; +@@ -66,27 +75,123 @@ static void etmemd_set_flag(int s) + g_sock_fd = -1; + } + ++static void etmemd_ignore_sig(int s) ++{ ++ return; ++} ++ + void etmemd_handle_signal(void) + { + signal(SIGINT, etmemd_set_flag); + signal(SIGTERM, etmemd_set_flag); ++ signal(SIGPIPE, etmemd_ignore_sig); + + return; + } + ++struct obj_cmd_item { ++ char *name; ++ enum opt_result (*func)(GKeyFile *config); ++}; ++ ++static enum opt_result do_obj_cmd(GKeyFile *config, struct obj_cmd_item *items, unsigned n) ++{ ++ unsigned i; ++ bool parsed = false; ++ enum opt_result ret; ++ ++ for (i = 0; i < n; i++) { ++ if (g_key_file_has_group(config, items[i].name) == FALSE) { ++ continue; ++ } ++ ++ ret = items[i].func(config); ++ if (ret != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "parse group %s fail\n", items[i].name); ++ return ret; ++ } ++ parsed = true; ++ } ++ ++ if (!parsed) { ++ etmemd_log(ETMEMD_LOG_ERR, "no group has been parsed\n"); ++ return OPT_INVAL; ++ } ++ ++ return OPT_SUCCESS; ++} ++ ++struct obj_cmd_item obj_add_items[] = { ++ {PROJ_GROUP, etmemd_project_add}, ++ {ENG_GROUP, etmemd_project_add_engine}, ++ {TASK_GROUP, etmemd_project_add_task}, ++}; ++ ++static enum opt_result do_obj_add(GKeyFile *config) ++{ ++ return do_obj_cmd(config, obj_add_items, ARRAY_SIZE(obj_add_items)); ++} ++ ++static struct obj_cmd_item obj_remove_items[] = { ++ {TASK_GROUP, etmemd_project_remove_task}, ++ {ENG_GROUP, etmemd_project_remove_engine}, ++ {PROJ_GROUP, etmemd_project_remove}, ++}; ++ ++static enum opt_result do_obj_remove(GKeyFile *config) ++{ ++ return do_obj_cmd(config, obj_remove_items, ARRAY_SIZE(obj_remove_items)); ++} ++ ++static enum opt_result handle_obj_cmd(char *file_name, enum cmd_type type) ++{ ++ GKeyFile *config = NULL; ++ enum opt_result ret; ++ ++ if (file_name == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "file name is not set for obj cmd\n"); ++ return OPT_INVAL; ++ } ++ ++ config = g_key_file_new(); ++ if (config == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get empty config file fail\n"); ++ return OPT_INTER_ERR; ++ } ++ ++ if (g_key_file_load_from_file(config, file_name, G_KEY_FILE_NONE, NULL) == FALSE) { ++ etmemd_log(ETMEMD_LOG_ERR, "load config file fail\n"); ++ ret = OPT_INTER_ERR; ++ goto free_file; ++ } ++ ++ switch (type) { ++ case OBJ_ADD: ++ ret = do_obj_add(config); ++ break; ++ case OBJ_DEL: ++ ret = do_obj_remove(config); ++ break; ++ default: ++ ret = OPT_INVAL; ++ } ++ ++free_file: ++ g_key_file_free(config); ++ return ret; ++} ++ + static enum opt_result etmemd_switch_cmd(const struct server_rpc_params svr_param) + { + enum opt_result ret = OPT_INVAL; + + switch (svr_param.cmd) { +- case PROJ_ADD: +- ret = etmemd_project_add(svr_param.proj_name, svr_param.file_name); +- return ret; +- case PROJ_DEL: +- ret = etmemd_project_delete(svr_param.proj_name); ++ case OBJ_ADD: ++ case OBJ_DEL: ++ ret = handle_obj_cmd(svr_param.file_name, svr_param.cmd); + return ret; + case PROJ_SHOW: +- ret = etmemd_project_show(); ++ ret = etmemd_project_show(svr_param.proj_name, svr_param.sock_fd); + return ret; + case MIG_START: + ret = etmemd_migrate_start(svr_param.proj_name); +@@ -94,6 +199,10 @@ static enum opt_result etmemd_switch_cmd(const struct server_rpc_params svr_para + case MIG_STOP: + ret = etmemd_migrate_stop(svr_param.proj_name); + return ret; ++ case ENG_CMD: ++ ret = etmemd_project_mgt_engine(svr_param.proj_name, svr_param.eng_name, ++ svr_param.eng_cmd, svr_param.task_name, svr_param.sock_fd); ++ return ret; + default: + etmemd_log(ETMEMD_LOG_ERR, "Invalid command.\n"); + return ret; +@@ -297,11 +406,24 @@ static int etmemd_rpc_decode_int(void **ptr, const char *buf, + return 0; + } + ++static bool skip_null_arg(const char *buf, unsigned long *idx) ++{ ++ if (buf[*idx] == '-') { ++ *idx += 2; // add 2 for skipping '- ' ++ return true; ++ } ++ return false; ++} ++ + static int etmemd_rpc_decode(struct server_rpc_parser *parser, const char *buf, + unsigned long buf_len, unsigned long *idx) + { + int ret; + ++ if (skip_null_arg(buf, idx)) { ++ return 0; ++ } ++ + switch (parser->type) { + case DECODE_STRING: + ret = etmemd_rpc_decode_str(parser->member_ptr, buf, buf_len, idx); +@@ -377,6 +499,10 @@ static void etmemd_rpc_send_response_msg(int sock_fd, enum opt_result result) + int i = 0; + ssize_t ret = -1; + ++ if (result == OPT_SUCCESS) { ++ return; ++ } ++ + while (g_resp_msg_arr[i].msg != NULL) { + if (result != g_resp_msg_arr[i].result) { + i++; +@@ -398,6 +524,7 @@ static void etmemd_rpc_handle(int sock_fd) + { + enum opt_result ret; + ++ g_rpc_params.sock_fd = sock_fd; + ret = etmemd_switch_cmd(g_rpc_params); + if (ret != OPT_SUCCESS) { + etmemd_log(ETMEMD_LOG_ERR, "operate cmd %d fail\n", g_rpc_params.cmd); +@@ -474,7 +601,7 @@ static int etmemd_rpc_accept(int sock_fd) + goto RPC_EXIT; + } + +- etmemd_log(ETMEMD_LOG_INFO, "etmemd get socket message \"%s\"\n", recv_buf); ++ etmemd_log(ETMEMD_LOG_DEBUG, "etmemd get socket message \"%s\"\n", recv_buf); + if (etmemd_rpc_parse(recv_buf, (unsigned long)rc) == 0) { + etmemd_rpc_handle(accp_fd); + } +diff --git a/src/etmemd_src/etmemd_scan.c b/src/etmemd_src/etmemd_scan.c +index 66694a1..bb8dfa3 100644 +--- a/src/etmemd_src/etmemd_scan.c ++++ b/src/etmemd_src/etmemd_scan.c +@@ -17,10 +17,12 @@ + #include + #include + #include ++#include + + #include "etmemd.h" + #include "etmemd_scan.h" + #include "etmemd_project.h" ++#include "etmemd_engine.h" + #include "etmemd_common.h" + #include "etmemd_log.h" + #include "securec.h" +@@ -30,6 +32,8 @@ + #define PUD_SIZE_SHIFT 30 + #define HEXADECIMAL_RADIX 16 + #define PMD_IDLE_PTES_PARAMETER 512 ++#define VMFLAG_MAX_LEN 100 ++#define VMFLAG_MAX_NUM 30 + + static const enum page_type g_page_type_by_idle_kind[] = { + PTE_TYPE, +@@ -45,11 +49,12 @@ static const enum page_type g_page_type_by_idle_kind[] = { + PAGE_TYPE_INVAL, + }; + +-static u_int64_t g_page_size[PAGE_TYPE_INVAL] = { +- 1UL << PTE_SIZE_SHIFT, /* PTE size */ +- 1UL << PMD_SIZE_SHIFT, /* PMD size */ +- 1UL << PUD_SIZE_SHIFT, /* PUD size */ +-}; ++static uint64_t g_page_size[PAGE_TYPE_INVAL]; ++ ++int page_type_to_size(enum page_type type) ++{ ++ return g_page_size[type]; ++} + + static unsigned int get_page_shift(long pagesize) + { +@@ -260,13 +265,91 @@ exit: + return NULL; + } + +-struct vmas *get_vmas(const char *pid) ++static bool is_vma_with_vmflags(FILE *fp, char *vmflags_array[], int vmflags_num) ++{ ++ char parse_line[FILE_LINE_MAX_LEN]; ++ size_t len; ++ int i; ++ ++ len = strlen(VMFLAG_HEAD); ++ while (fgets(parse_line, FILE_LINE_MAX_LEN - 1, fp) != NULL) { ++ /* skip the line which has no match length */ ++ if (strlen(parse_line) <= len) { ++ continue; ++ } ++ if (strncmp(VMFLAG_HEAD, parse_line, len) != 0) { ++ continue; ++ } ++ ++ /* check any flag in flags is set */ ++ for (i = 0; i < vmflags_num; i++) { ++ if (strstr(parse_line, vmflags_array[i]) == NULL) { ++ return false; ++ } ++ } ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool is_vmflags_match(FILE *fp, char *vmflags_array[], int vmflags_num) ++{ ++ if (vmflags_num == 0) { ++ return true; ++ } ++ return is_vma_with_vmflags(fp, vmflags_array, vmflags_num); ++} ++ ++static bool is_anon_match(bool is_anon_only, struct vma *vma) ++{ ++ if (!is_anon_only) { ++ return true; ++ } ++ return is_anonymous(vma); ++} ++ ++int split_vmflags(char ***vmflags_array, char *vmflags) ++{ ++ char *flag = NULL; ++ char *saveptr = NULL; ++ char *tmp_array[VMFLAG_MAX_NUM] = {}; ++ int vmflags_num = 0; ++ int i; ++ ++ for (flag = strtok_r(vmflags, " ", &saveptr); flag != NULL; flag = strtok_r(NULL, " ,", &saveptr)) { ++ tmp_array[vmflags_num++] = flag; ++ if (vmflags_num == VMFLAG_MAX_NUM) { ++ break; ++ } ++ } ++ ++ *vmflags_array = malloc(sizeof(char *) * vmflags_num); ++ if (*vmflags_array == NULL) { ++ return -1; ++ } ++ ++ for (i = 0; i < vmflags_num; i++) { ++ (*vmflags_array)[i] = tmp_array[i]; ++ } ++ ++ return vmflags_num; ++} ++ ++struct vmas *get_vmas_with_flags(const char *pid, char *vmflags_array[], int vmflags_num, bool is_anon_only) + { + struct vmas *ret_vmas = NULL; + struct vma **tmp_vma = NULL; + FILE *fp = NULL; + char maps_line[FILE_LINE_MAX_LEN]; + size_t len; ++ char *maps_file = NULL; ++ ++ if (vmflags_num == 0) { ++ maps_file = MAPS_FILE; ++ } else { ++ maps_file = SMAPS_FILE; ++ } + + ret_vmas = (struct vmas *)calloc(1, sizeof(struct vmas)); + if (ret_vmas == NULL) { +@@ -274,9 +357,9 @@ struct vmas *get_vmas(const char *pid) + return NULL; + } + +- fp = etmemd_get_proc_file(pid, MAPS_FILE, "r"); ++ fp = etmemd_get_proc_file(pid, maps_file, 0, "r"); + if (fp == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "open %s file of %s fail\n", MAPS_FILE, pid); ++ etmemd_log(ETMEMD_LOG_ERR, "open %s file of %s fail\n", maps_file, pid); + free(ret_vmas); + return NULL; + } +@@ -291,23 +374,35 @@ struct vmas *get_vmas(const char *pid) + ret_vmas = NULL; + break; + } +- tmp_vma = &((*tmp_vma)->next); +- ret_vmas->vma_cnt++; + +- /* if the file path is too long, maps_line cannot read file line completely, clean invalid characters. */ ++ /* if the file path is too long, maps_line cannot read file line completely, clean invalid characters */ + while (maps_line[len - 1] != '\n') { + if (fgets(maps_line, FILE_LINE_MAX_LEN - 1, fp) != NULL) { + len = strlen(maps_line); + continue; + } + } ++ ++ /* skip vma without vmflags */ ++ if (!is_vmflags_match(fp, vmflags_array, vmflags_num) || !is_anon_match(is_anon_only, *tmp_vma)) { ++ free(*tmp_vma); ++ *tmp_vma = NULL; ++ continue; ++ } ++ ++ tmp_vma = &((*tmp_vma)->next); ++ ret_vmas->vma_cnt++; + } + + fclose(fp); +- + return ret_vmas; + } + ++struct vmas *get_vmas(const char *pid) ++{ ++ return get_vmas_with_flags(pid, NULL, 0, true); ++} ++ + static u_int64_t get_address_from_buf(const unsigned char *buf, u_int64_t index) + { + u_int64_t address; +@@ -408,9 +503,9 @@ static struct page_refs **record_parse_result(u_int64_t addr, enum page_idle_typ + enum page_type page_size_type; + + /* ignore unaligned address when walk, because pages handled need to be aligned */ +- if ((addr & (g_page_size[g_page_type_by_idle_kind[type]] - 1)) > 0) { ++ if ((addr & (page_type_to_size(g_page_type_by_idle_kind[type]) - 1)) > 0) { + etmemd_log(ETMEMD_LOG_WARN, "ignore address %lx which not aligned %lx for type %d\n", addr, +- g_page_size[g_page_type_by_idle_kind[type]], type); ++ page_type_to_size(g_page_type_by_idle_kind[type]), type); + return pf; + } + +@@ -429,7 +524,7 @@ static struct page_refs **record_parse_result(u_int64_t addr, enum page_idle_typ + break; + } + +- addr += g_page_size[page_size_type]; ++ addr += page_type_to_size(page_size_type); + } + + return pf; +@@ -480,23 +575,23 @@ static struct page_refs **parse_vma_result(const unsigned char *buf, u_int64_t s + } else if (type < PMD_IDLE_PTES) { + pf = record_parse_result(address, type, nr, pf); + } else { +- address = address + (u_int64_t)nr * g_page_size[g_page_type_by_idle_kind[type]]; ++ address = address + (u_int64_t)nr * page_type_to_size(g_page_type_by_idle_kind[type]); + continue; + } + + if (pf == NULL) { + return NULL; + } +- address = address + (u_int64_t)nr * g_page_size[g_page_type_by_idle_kind[type]]; ++ address = address + (u_int64_t)nr * page_type_to_size(g_page_type_by_idle_kind[type]); + } + *end = address; + return pf; + } + +-static struct page_refs **walk_vmas(int fd, +- struct walk_address *walk_address, +- struct page_refs **pf, +- unsigned long *use_rss) ++struct page_refs **walk_vmas(int fd, ++ struct walk_address *walk_address, ++ struct page_refs **pf, ++ unsigned long *use_rss) + { + unsigned char *buf = NULL; + u_int64_t size; +@@ -504,7 +599,7 @@ static struct page_refs **walk_vmas(int fd, + + /* we make the buffer size as fitable as within a vma. + * because the size of buffer passed to kernel will be calculated again (<< (3 + PAGE_SHIFT)) */ +- size = ((walk_address->walk_end - walk_address->walk_start) >> 3) / g_page_size[PTE_TYPE]; ++ size = ((walk_address->walk_end - walk_address->walk_start) >> 3) / page_type_to_size(PTE_TYPE); + + /* we need to compare the size to the minimum size that kernel handled */ + size = size < EPT_IDLE_BUF_MIN ? EPT_IDLE_BUF_MIN : size; +@@ -547,7 +642,7 @@ int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **p + struct page_refs **tmp_page_refs = NULL; + struct walk_address walk_address = {0, 0, 0}; + +- scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, "r"); ++ scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, 0, "r"); + if (scan_fp == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "open %s file fail\n", IDLE_SCAN_FILE); + return -1; +@@ -567,11 +662,6 @@ int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **p + continue; + } + +- if (!(is_anonymous(vma))) { +- vma = vma->next; +- continue; +- } +- + /* meeting this branch means the end of address for last scan is between the address of + * start and end this round, so we start from lastScanEnd address in case of scan repeatly. */ + walk_address.walk_end = vma->end; +@@ -630,7 +720,7 @@ struct page_refs *etmemd_do_scan(const struct task_pid *tpid, const struct task + } + + /* loop for scanning idle_pages to get result of memory access. */ +- for (i = 0; i < tk->proj->loop; i++) { ++ for (i = 0; i < tk->eng->proj->loop; i++) { + ret = get_page_refs(vmas, pid, &page_refs, NULL); + if (ret != 0) { + etmemd_log(ETMEMD_LOG_ERR, "scan operation failed\n"); +@@ -639,7 +729,7 @@ struct page_refs *etmemd_do_scan(const struct task_pid *tpid, const struct task + page_refs = NULL; + break; + } +- sleep((unsigned)tk->proj->sleep); ++ sleep((unsigned)tk->eng->proj->sleep); + } + + free_vmas(vmas); +diff --git a/src/etmemd_src/etmemd_slide.c b/src/etmemd_src/etmemd_slide.c +index fe8ae92..ea9ccb4 100644 +--- a/src/etmemd_src/etmemd_slide.c ++++ b/src/etmemd_src/etmemd_slide.c +@@ -26,57 +26,7 @@ + #include "etmemd_scan.h" + #include "etmemd_migrate.h" + #include "etmemd_pool_adapter.h" +- +-static int fill_slide_param_t(struct engine *eng, const char *val) +-{ +- int value; +- struct slide_params *s_param = (struct slide_params *)eng->params; +- struct task *tk = (struct task *)eng->task; +- +- if (get_int_value(val, &value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid engine param T value.\n"); +- return -1; +- } +- +- /* the max value of T watermark is weight of write multipled by time of loop */ +- if (value < 1 || value > tk->proj->loop * WRITE_TYPE_WEIGHT) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid engine param T value, must between 1 and loop.\n"); +- return -1; +- } +- +- s_param->t = value; +- +- return 0; +-} +- +-static int parse_slide_params(struct engine *eng, FILE *file) +-{ +- char key[KEY_VALUE_MAX_LEN] = {}; +- char value[KEY_VALUE_MAX_LEN] = {}; +- char *get_line = NULL; +- +- get_line = skip_blank_line(file); +- if (get_line == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "lack of config for slide engine privately\n"); +- return -1; +- } +- +- if (get_keyword_and_value(get_line, key, value) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "get engine param keyword and value fail\n"); +- return -1; +- } +- +- if (strcmp(key, "T") != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "invalid slide parameter keyword, must be T\n"); +- return -1; +- } +- +- if (fill_slide_param_t(eng, value) != 0) { +- return -1; +- } +- +- return 0; +-} ++#include "etmemd_file.h" + + static struct memory_grade *slide_policy_interface(struct page_refs **page_refs, void *params) + { +@@ -125,32 +75,20 @@ static int slide_do_migrate(unsigned int pid, const struct memory_grade *memory_ + return ret; + } + +-static void *slide_exector(void *arg) ++static void *slide_executor(void *arg) + { + struct task_pid *tk_pid = (struct task_pid *)arg; + struct page_refs *page_refs = NULL; + struct memory_grade *memory_grade = NULL; +- struct engine *eng = NULL; +- +- eng = tk_pid->tk->eng; +- if (eng == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "pid %u engine is null!\n", tk_pid->pid); +- return NULL; +- } +- +- if (eng->adp == NULL || eng->adp->do_scan == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "pid %u scan function is not registered!\n", tk_pid->pid); +- return NULL; +- } + + /* register cleanup function in case of unexpected cancellation detected, + * and register for memory_grade first, because it needs to clean after page_refs is cleaned */ + pthread_cleanup_push(clean_memory_grade_unexpected, &memory_grade); + pthread_cleanup_push(clean_page_refs_unexpected, &page_refs); + +- page_refs = eng->adp->do_scan(tk_pid, tk_pid->tk); ++ page_refs = etmemd_do_scan(tk_pid, tk_pid->tk); + if (page_refs != NULL) { +- memory_grade = eng->mig_policy_func(&page_refs, eng->params); ++ memory_grade = slide_policy_interface(&page_refs, tk_pid->tk->params); + } + + /* no need to use page_refs any longer. +@@ -165,12 +103,7 @@ static void *slide_exector(void *arg) + goto exit; + } + +- if (eng->adp->do_migrate == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "pid %u migrate function is not registered!\n", tk_pid->pid); +- goto exit; +- } +- +- if (eng->adp->do_migrate(tk_pid->pid, memory_grade) != 0) { ++ if (slide_do_migrate(tk_pid->pid, memory_grade) != 0) { + etmemd_log(ETMEMD_LOG_DEBUG, "slide migrate for pid %u fail\n", tk_pid->pid); + } + +@@ -184,41 +117,104 @@ exit: + return NULL; + } + +-static int alloc_slide_params(struct task_pid **tk_pid) ++static int fill_task_threshold(void *obj, void *val) + { +- (*tk_pid)->params = NULL; ++ struct slide_params *params = (struct slide_params *)obj; ++ int t = parse_to_int(val); ++ ++ if (t < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "slide engine param T should not be less than 0"); ++ return -1; ++ } ++ ++ params->t = t; + return 0; + } + +-int fill_engine_type_slide(struct engine *eng) ++static struct config_item g_slide_task_config_items[] = { ++ {"T", INT_VAL, fill_task_threshold, false}, ++}; ++ ++static int slide_fill_task(GKeyFile *config, struct task *tk) + { +- struct slide_params *s_param = NULL; +- struct task *tk = (struct task *)eng->task; ++ struct slide_params *params = calloc(1, sizeof(struct slide_params)); + +- s_param = (struct slide_params *)calloc(1, sizeof(struct slide_params)); +- if (s_param == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "malloc slide engine params fail\n"); ++ if (params == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc slide param fail\n"); + return -1; + } + +- eng->adp = (struct adapter *)calloc(1, sizeof(struct adapter)); +- if (eng->adp == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "malloc adapter for task %s engine fail\n", tk->value); +- free(s_param); ++ if (parse_file_config(config, TASK_GROUP, g_slide_task_config_items, ARRAY_SIZE(g_slide_task_config_items), ++ (void *)params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "slide fill task fail\n"); ++ goto free_params; ++ } ++ ++ if (params->t > tk->eng->proj->loop * WRITE_TYPE_WEIGHT) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine param T must less than loop.\n"); ++ goto free_params; ++ } ++ tk->params = params; ++ return 0; ++ ++free_params: ++ free(params); ++ return -1; ++} ++ ++static void slide_clear_task(struct task *tk) ++{ ++ free(tk->params); ++ tk->params = NULL; ++} ++ ++static int slide_start_task(struct engine *eng, struct task *tk) ++{ ++ struct slide_params *params = tk->params; ++ ++ params->executor = malloc(sizeof(struct task_executor)); ++ if (params->executor == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "slide alloc memory for task_executor fail\n"); + return -1; + } + +- eng->params = (void *)s_param; +- eng->engine_type = SLIDE_ENGINE; +- eng->parse_param_conf = parse_slide_params; +- eng->mig_policy_func = slide_policy_interface; +- eng->adp->do_scan = etmemd_do_scan; +- eng->adp->do_migrate = slide_do_migrate; +- eng->alloc_params = alloc_slide_params; +- tk->start_etmem = start_threadpool_work; +- tk->stop_etmem = stop_and_delete_threadpool_work; +- tk->delete_etmem = stop_and_delete_threadpool_work; +- tk->workflow_engine = slide_exector; ++ params->executor->tk = tk; ++ params->executor->func = slide_executor; ++ if (start_threadpool_work(params->executor) != 0) { ++ free(params->executor); ++ params->executor = NULL; ++ etmemd_log(ETMEMD_LOG_ERR, "slide start task executor fail\n"); ++ return -1; ++ } ++ ++ return 0; ++} + ++static void slide_stop_task(struct engine *eng, struct task *tk) ++{ ++ struct slide_params *params = tk->params; ++ ++ stop_and_delete_threadpool_work(tk); ++ free(params->executor); ++ params->executor = NULL; ++} ++ ++struct engine_ops slide_eng_ops = { ++ .fill_eng_params = NULL, ++ .clear_eng_params = NULL, ++ .fill_task_params = slide_fill_task, ++ .clear_task_params = slide_clear_task, ++ .start_task = slide_start_task, ++ .stop_task = slide_stop_task, ++ .alloc_pid_params = NULL, ++ .free_pid_params = NULL, ++ .eng_mgt_func = NULL, ++}; ++ ++int fill_engine_type_slide(struct engine *eng) ++{ ++ eng->ops = &slide_eng_ops; ++ eng->engine_type = SLIDE_ENGINE; ++ eng->name = "slide"; + return 0; + } +diff --git a/src/etmemd_src/etmemd_task.c b/src/etmemd_src/etmemd_task.c +index 8474c6c..5c81b74 100644 +--- a/src/etmemd_src/etmemd_task.c ++++ b/src/etmemd_src/etmemd_task.c +@@ -20,12 +20,14 @@ + #include + #include + #include ++#include + + #include "securec.h" + #include "etmemd_log.h" + #include "etmemd_common.h" + #include "etmemd_task.h" + #include "etmemd_engine.h" ++#include "etmemd_file.h" + + static int get_pid_through_pipe(char *arg_pid[], const int *pipefd) + { +@@ -74,7 +76,10 @@ static int get_pid_through_pipe(char *arg_pid[], const int *pipefd) + + void free_task_pid_mem(struct task_pid **tk_pid) + { +- etmemd_safe_free((void **)(&((*tk_pid)->params))); ++ struct engine *eng = (*tk_pid)->tk->eng; ++ if (eng->ops->free_pid_params != NULL) { ++ eng->ops->free_pid_params(eng, tk_pid); ++ } + etmemd_safe_free((void **)tk_pid); + } + +@@ -91,8 +96,8 @@ static void clean_nouse_pid(struct task_pid **tk_pid) + + static struct task_pid *alloc_tkpid_node(unsigned int pid, struct task *tk) + { +- int ret; + struct task_pid *tk_pid = NULL; ++ struct engine *eng = tk->eng; + + tk_pid = (struct task_pid *)calloc(1, sizeof(struct task_pid)); + if (tk_pid == NULL) { +@@ -102,8 +107,7 @@ static struct task_pid *alloc_tkpid_node(unsigned int pid, struct task *tk) + tk_pid->pid = pid; + tk_pid->tk = tk; + +- ret = tk->eng->alloc_params(&tk_pid); +- if (ret != 0) { ++ if (eng->ops->alloc_pid_params != NULL && eng->ops->alloc_pid_params(eng, &tk_pid) != 0) { + free(tk_pid); + return NULL; + } +@@ -362,6 +366,13 @@ int etmemd_get_task_pids(struct task *tk) + return 0; + } + ++static void clear_task_struct(struct task *task) ++{ ++ etmemd_safe_free((void **)&task->type); ++ etmemd_safe_free((void **)&task->value); ++ etmemd_safe_free((void **)&task->name); ++} ++ + void etmemd_free_task_struct(struct task **tk) + { + struct task *task = NULL; +@@ -371,36 +382,125 @@ void etmemd_free_task_struct(struct task **tk) + } + + task = *tk; +- etmemd_safe_free((void **)&task->type); +- etmemd_safe_free((void **)&task->value); +- +- if (task->eng != NULL) { +- etmemd_safe_free((void **)&task->eng->params); +- etmemd_safe_free((void **)&task->eng->adp); +- task->eng->task = NULL; +- etmemd_safe_free((void **)&task->eng); +- task->eng = NULL; +- } +- +- task->proj = NULL; ++ clear_task_struct(task); + free(task); + *tk = NULL; + } + +-void etmemd_print_tasks(const struct task *tk) ++void etmemd_print_tasks(int fd, const struct task *tk, char *eng_name, bool started) + { + const struct task *tmp = tk; + int i = 1; + + while (tmp != NULL) { +- printf("%-8d %-32s %-32s %-32s %-16s\n", +- i, +- tmp->type, +- tmp->value, +- etmemd_get_eng_name(tmp->eng->engine_type), +- tmp->timer_inst == NULL ? "false" : "true"); ++ dprintf_all(fd, "%-8d %-8s %-16s %-16s %-16s %-8s\n", ++ i, ++ tmp->type, ++ tmp->value, ++ tmp->name, ++ eng_name, ++ started ? "true" : "false"); + + tmp = tmp->next; + i++; + } + } ++ ++static int fill_task_name(void *obj, void *val) ++{ ++ struct task *tk = (struct task *)obj; ++ char *name = (char *)val; ++ tk->name = name; ++ return 0; ++} ++ ++static int fill_task_type(void *obj, void *val) ++{ ++ struct task *tk = (struct task *)obj; ++ char *type = (char *)val; ++ if (strcmp(val, "pid") != 0 && strcmp(val, "name") != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "invalid task type, must be pid or name.\n"); ++ return -1; ++ } ++ ++ tk->type = type; ++ return 0; ++} ++ ++static int fill_task_value(void *obj, void *val) ++{ ++ struct task *tk = (struct task *)obj; ++ char *value = (char *)val; ++ tk->value = value; ++ return 0; ++} ++ ++static int fill_task_threads(void *obj, void *val) ++{ ++ struct task *tk = (struct task *)obj; ++ int max_threads = parse_to_int(val); ++ int core; ++ ++ if (max_threads < 0) { ++ etmemd_log(ETMEMD_LOG_WARN, ++ "Thread count is abnormal, set the default minimum of current thread count to 1\n"); ++ max_threads = 1; ++ } ++ ++ core = get_nprocs(); ++ /* ++ * For IO intensive bussinesses, max-threads is limited to 2N + 1 of the maximum number ++ * of threads ++ */ ++ if (max_threads > 2 * core + 1) { ++ etmemd_log(ETMEMD_LOG_WARN, ++ "max-threads is limited to 2N+1 of the maximum number of threads\n"); ++ max_threads = 2 * core + 1; ++ } ++ ++ tk->max_threads = max_threads; ++ return 0; ++} ++ ++struct config_item g_task_config_items[] = { ++ {"name", STR_VAL, fill_task_name, false}, ++ {"type", STR_VAL, fill_task_type, false}, ++ {"value", STR_VAL, fill_task_value, false}, ++ {"max_threads", INT_VAL, fill_task_threads, true}, ++}; ++ ++static int task_fill_by_conf(GKeyFile *config, struct task *tk) ++{ ++ if (parse_file_config(config, TASK_GROUP, g_task_config_items, ++ ARRAY_SIZE(g_task_config_items), (void *)tk) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "parse task config fail\n"); ++ clear_task_struct(tk); ++ return -1; ++ } ++ return 0; ++} ++ ++struct task *etmemd_add_task(GKeyFile *config) ++{ ++ struct task *tk = calloc(1, sizeof(struct task)); ++ ++ if (tk == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc task struct fail\n"); ++ return NULL; ++ } ++ ++ /* set default count of the thread pool to 1 */ ++ tk->max_threads = 1; ++ if (task_fill_by_conf(config, tk) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "fill task from configuration file fail.\n"); ++ free(tk); ++ return NULL; ++ } ++ return tk; ++} ++ ++void etmemd_remove_task(struct task *tk) ++{ ++ clear_task_struct(tk); ++ free(tk); ++} +-- +2.27.0 + diff --git a/0005-fix-code-check-problems.patch b/0005-fix-code-check-problems.patch new file mode 100644 index 0000000..15f2eca --- /dev/null +++ b/0005-fix-code-check-problems.patch @@ -0,0 +1,256 @@ +From b54b30489959a7692cc6d484e3b16d1d54f7ed85 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Sun, 25 Apr 2021 21:44:44 +0800 +Subject: [PATCH 05/50] fix code check problems + +Signed-off-by: Kemeng Shi +--- + inc/etmemd_inc/etmemd_project.h | 3 ++- + src/etmem_src/etmem_common.c | 2 +- + src/etmemd_src/etmemd_common.c | 2 ++ + src/etmemd_src/etmemd_cslide.c | 32 +++++++++++++++++++++----------- + src/etmemd_src/etmemd_project.c | 9 ++++++--- + src/etmemd_src/etmemd_rpc.c | 4 ++-- + src/etmemd_src/etmemd_slide.c | 4 ++-- + 7 files changed, 36 insertions(+), 20 deletions(-) + +diff --git a/inc/etmemd_inc/etmemd_project.h b/inc/etmemd_inc/etmemd_project.h +index d15c7fd..e574a84 100644 +--- a/inc/etmemd_inc/etmemd_project.h ++++ b/inc/etmemd_inc/etmemd_project.h +@@ -102,7 +102,8 @@ enum opt_result etmemd_migrate_start(const char *project_name); + * */ + enum opt_result etmemd_migrate_stop(const char *project_name); + +-enum opt_result etmemd_project_mgt_engine(const char *project_name, const char *eng_name, char *cmd, char *task_name, int sock_fd); ++enum opt_result etmemd_project_mgt_engine(const char *project_name, const char *eng_name, char *cmd, char *task_name, ++ int sock_fd); + enum opt_result etmemd_project_add_engine(GKeyFile *config); + enum opt_result etmemd_project_remove_engine(GKeyFile *config); + enum opt_result etmemd_project_add_task(GKeyFile *config); +diff --git a/src/etmem_src/etmem_common.c b/src/etmem_src/etmem_common.c +index 65d3690..8d0cee3 100644 +--- a/src/etmem_src/etmem_common.c ++++ b/src/etmem_src/etmem_common.c +@@ -36,7 +36,7 @@ int parse_name_string(const char *val, char **name_str, size_t max_len) + return -EINVAL; + } + if (len > max_len) { +- printf("string is too long, it should not be larger than %lu\n", max_len); ++ printf("string is too long, it should not be larger than %zu\n", max_len); + return -ENAMETOOLONG; + } + +diff --git a/src/etmemd_src/etmemd_common.c b/src/etmemd_src/etmemd_common.c +index 43ed013..4b9c4cb 100644 +--- a/src/etmemd_src/etmemd_common.c ++++ b/src/etmemd_src/etmemd_common.c +@@ -403,12 +403,14 @@ int dprintf_all(int fd, const char *format, ...) + ret = vsprintf_s(line, FILE_LINE_MAX_LEN, format, args_in); + if (ret > FILE_LINE_MAX_LEN) { + etmemd_log(ETMEMD_LOG_ERR, "fprintf_all fail as truncated.\n"); ++ va_end(args_in); + return -1; + } + + ret = write_all(fd, line); + if (ret < 0) { + etmemd_log(ETMEMD_LOG_ERR, "write_all fail.\n"); ++ va_end(args_in); + return -1; + } + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index a3692ad..5fd1c32 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -8,7 +8,7 @@ + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. +- * Author: louhongxiang ++ * Author: shikemeng + * Create: 2021-4-19 + * Description: Memigd cslide API. + ******************************************************************************/ +@@ -44,7 +44,9 @@ + #define BATCHSIZE (1 << 16) + + #define factory_foreach_working_pid_params(iter, factory) \ +- for ((iter) = (factory)->working_head, next_working_params(&(iter)); (iter) != NULL; (iter) = (iter)->next, next_working_params(&(iter))) ++ for ((iter) = (factory)->working_head, next_working_params(&(iter)); \ ++ (iter) != NULL; \ ++ (iter) = (iter)->next, next_working_params(&(iter))) + + #define factory_foreach_pid_params(iter, factory) \ + for ((iter) = (factory)->working_head; (iter) != NULL; (iter) = (iter)->next) +@@ -184,7 +186,8 @@ struct page_filter { + void (*flow_cal_func)(struct flow_ctrl *ctrl); + long long (*flow_move_func)(struct flow_ctrl *ctrl, long long target, int node); + bool (*flow_enough)(struct flow_ctrl *ctrl); +- void (*filter_policy)(struct page_filter *filter, struct node_pair *pair, struct count_page_refs *cpf, struct memory_grade *memory_grade); ++ void (*filter_policy)(struct page_filter *filter, struct node_pair *pair, ++ struct count_page_refs *cpf, struct memory_grade *memory_grade); + struct flow_ctrl *ctrl; + int count_start; + int count_end; +@@ -509,7 +512,6 @@ static int add_node_pair(struct node_map *map, int cold_node, int hot_node) + return 0; + } + +- + static int init_node_verifier(struct node_verifier *nv, int node_num) + { + nv->nodes_map_count = calloc(node_num, sizeof(int)); +@@ -933,7 +935,8 @@ static bool node_cal_cold_can_move(struct node_ctrl *node_ctrl) + { + long long can_move; + +- can_move = node_ctrl->quota < node_ctrl->reserve - node_ctrl->free ? node_ctrl->quota : node_ctrl->reserve - node_ctrl->free; ++ can_move = node_ctrl->quota < node_ctrl->reserve - node_ctrl->free ? ++ node_ctrl->quota : node_ctrl->reserve - node_ctrl->free; + if (can_move > node_ctrl->cold_free) { + can_move = node_ctrl->cold_free; + } +@@ -956,7 +959,8 @@ static inline bool node_move_cold(struct node_ctrl *node_ctrl, long long *target + return cap_cost(&node_ctrl->cold_move_cap, target); + } + +-static int init_flow_ctrl(struct flow_ctrl *ctrl, struct sys_mem *sys_mem, struct node_map *node_map, long long quota, long long reserve) ++static int init_flow_ctrl(struct flow_ctrl *ctrl, struct sys_mem *sys_mem, struct node_map *node_map, ++ long long quota, long long reserve) + { + struct node_pair *pair = NULL; + struct node_ctrl *tmp = NULL; +@@ -1114,7 +1118,8 @@ static void do_filter(struct page_filter *filter, struct cslide_eng_params *eng_ + } + } + +-static void to_hot_policy(struct page_filter *filter, struct node_pair *pair, struct count_page_refs *cpf, struct memory_grade *memory_grade) ++static void to_hot_policy(struct page_filter *filter, struct node_pair *pair, ++ struct count_page_refs *cpf, struct memory_grade *memory_grade) + { + long long can_move; + struct node_page_refs *npf = &cpf->node_pfs[pair->cold_node]; +@@ -1123,7 +1128,8 @@ static void to_hot_policy(struct page_filter *filter, struct node_pair *pair, st + move_npf_to_list(npf, &memory_grade->hot_pages, can_move); + } + +-static void to_cold_policy(struct page_filter *filter, struct node_pair *pair, struct count_page_refs *cpf, struct memory_grade *memory_grade) ++static void to_cold_policy(struct page_filter *filter, struct node_pair *pair, ++ struct count_page_refs *cpf, struct memory_grade *memory_grade) + { + long long can_move; + struct node_page_refs *npf = &cpf->node_pfs[pair->hot_node]; +@@ -1376,7 +1382,9 @@ static int cslide_merge_share_vmas(struct cslide_eng_params *eng_params) + + vma_pf = g_share_vma_head; + while (vma_pf != NULL) { +- for (iter = vma_pf->next, count = 1; iter != NULL && iter->vma->inode == vma_pf->vma->inode; iter = iter->next, count++) { ++ for (iter = vma_pf->next, count = 1; ++ iter != NULL && iter->vma->inode == vma_pf->vma->inode; ++ iter = iter->next, count++) { + ; + } + if (count > 1) { +@@ -1403,7 +1411,8 @@ static int cslide_get_vmas(struct cslide_pid_params *pid_params) + etmemd_log(ETMEMD_LOG_ERR, "sprintf pid %u fail\n", pid_params->pid); + return -1; + } +- pid_params->vmas = get_vmas_with_flags(pid, task_params->vmflags_array, task_params->vmflags_num, task_params->anon_only); ++ pid_params->vmas = get_vmas_with_flags(pid, task_params->vmflags_array, task_params->vmflags_num, ++ task_params->anon_only); + if (pid_params->vmas == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "get vmas for %s fail\n", pid); + return -1; +@@ -2108,7 +2117,8 @@ static int fill_node_pair(void *obj, void *val) + return ret; + } + +- for (pair = strtok_r(node_pair_str, pair_delim, &saveptr_pair); pair != NULL; pair = strtok_r(NULL, pair_delim, &saveptr_pair)) { ++ for (pair = strtok_r(node_pair_str, pair_delim, &saveptr_pair); pair != NULL; ++ pair = strtok_r(NULL, pair_delim, &saveptr_pair)) { + hot_node_str = strtok_r(pair, node_delim, &saveptr_node); + if (hot_node_str == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "parse hot node failed\n"); +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index 9ead14c..bd21819 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -132,7 +132,8 @@ static enum opt_result engine_of_group(GKeyFile *config, char *group_name, struc + return OPT_SUCCESS; + } + +-static enum opt_result task_of_group(GKeyFile *config, char *group_name, struct project *proj, struct engine *eng, struct task **tk) ++static enum opt_result task_of_group(GKeyFile *config, char *group_name, ++ struct project *proj, struct engine *eng, struct task **tk) + { + char *task_name = NULL; + char *key = NULL; +@@ -155,7 +156,8 @@ static enum opt_result task_of_group(GKeyFile *config, char *group_name, struct + return OPT_SUCCESS; + } + +-static enum opt_result get_group_objs(GKeyFile *config, char *group_name, struct project **proj, struct engine **eng, struct task **tk) ++static enum opt_result get_group_objs(GKeyFile *config, char *group_name, ++ struct project **proj, struct engine **eng, struct task **tk) + { + enum opt_result ret; + +@@ -682,7 +684,8 @@ enum opt_result etmemd_migrate_stop(const char *project_name) + return OPT_SUCCESS; + } + +-enum opt_result etmemd_project_mgt_engine(const char *project_name, const char *eng_name, char *cmd, char *task_name, int sock_fd) ++enum opt_result etmemd_project_mgt_engine(const char *project_name, const char *eng_name, char *cmd, char *task_name, ++ int sock_fd) + { + struct engine *eng = NULL; + struct project *proj = NULL; +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index e154083..2e8e49d 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -121,7 +121,7 @@ static enum opt_result do_obj_cmd(GKeyFile *config, struct obj_cmd_item *items, + return OPT_SUCCESS; + } + +-struct obj_cmd_item obj_add_items[] = { ++struct obj_cmd_item g_obj_add_items[] = { + {PROJ_GROUP, etmemd_project_add}, + {ENG_GROUP, etmemd_project_add_engine}, + {TASK_GROUP, etmemd_project_add_task}, +@@ -129,7 +129,7 @@ struct obj_cmd_item obj_add_items[] = { + + static enum opt_result do_obj_add(GKeyFile *config) + { +- return do_obj_cmd(config, obj_add_items, ARRAY_SIZE(obj_add_items)); ++ return do_obj_cmd(config, g_obj_add_items, ARRAY_SIZE(g_obj_add_items)); + } + + static struct obj_cmd_item obj_remove_items[] = { +diff --git a/src/etmemd_src/etmemd_slide.c b/src/etmemd_src/etmemd_slide.c +index ea9ccb4..f7609f4 100644 +--- a/src/etmemd_src/etmemd_slide.c ++++ b/src/etmemd_src/etmemd_slide.c +@@ -199,7 +199,7 @@ static void slide_stop_task(struct engine *eng, struct task *tk) + params->executor = NULL; + } + +-struct engine_ops slide_eng_ops = { ++struct engine_ops g_slide_eng_ops = { + .fill_eng_params = NULL, + .clear_eng_params = NULL, + .fill_task_params = slide_fill_task, +@@ -213,7 +213,7 @@ struct engine_ops slide_eng_ops = { + + int fill_engine_type_slide(struct engine *eng) + { +- eng->ops = &slide_eng_ops; ++ eng->ops = &g_slide_eng_ops; + eng->engine_type = SLIDE_ENGINE; + eng->name = "slide"; + return 0; +-- +2.27.0 + diff --git a/0006-remove-unused-share-vmas-merge.patch b/0006-remove-unused-share-vmas-merge.patch new file mode 100644 index 0000000..d3946c1 --- /dev/null +++ b/0006-remove-unused-share-vmas-merge.patch @@ -0,0 +1,240 @@ +From c367b624d3674a572701e9ceee93ca5b73107f0c Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Mon, 26 Apr 2021 17:04:07 +0800 +Subject: [PATCH 06/50] remove unused share vmas merge + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 197 --------------------------------- + 1 file changed, 197 deletions(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 5fd1c32..3983a32 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -194,18 +194,11 @@ struct page_filter { + int count_step; + }; + +-struct page_offset { +- struct page_refs *page_refs; +- uint64_t to_offset; +-}; +- + struct cslide_cmd_item { + char *name; + int (*func)(void *params, int fd); + }; + +-struct vma_pf *g_share_vma_head = NULL; +- + static inline int get_node_num(void) + { + return numa_num_configured_nodes(); +@@ -1215,191 +1208,6 @@ static int cslide_policy(struct cslide_eng_params *eng_params) + return 0; + } + +-static void sort_add_vma_pf(struct vma_pf *vma_pf) +-{ +- struct vma_pf **iter = &g_share_vma_head; +- +- for (; *iter != NULL && (*iter)->vma->inode < vma_pf->vma->inode; iter = &((*iter)->next)) { +- ; +- } +- +- vma_pf->next = *iter; +- *iter = vma_pf; +-} +- +-static bool is_share(struct vma_pf *vma_pf) +-{ +- struct vma *vma = vma_pf->vma; +- +- if (vma->inode != 0 && vma->stat[VMA_STAT_MAY_SHARE]) { +- return true; +- } +- +- return false; +-} +- +-static inline uint64_t to_offset(struct page_offset *po) +-{ +- return po->page_refs->addr + po->to_offset; +-} +- +-static int page_offset_cmp(const void *a, const void *b) +-{ +- struct page_offset *l = (struct page_offset *)a; +- struct page_offset *r = (struct page_offset *)b; +- +- return to_offset(l) - to_offset(r); +-} +- +-static inline void init_merge_po(struct page_offset *to_merge_po, int count) +-{ +- qsort(to_merge_po, count, sizeof(struct page_offset), page_offset_cmp); +-} +- +-static void next_po(struct page_offset *to_merge_po, int *count) +-{ +- struct page_offset *po = to_merge_po; +- struct page_offset tmp; +- uint64_t offset; +- int i; +- +- po->page_refs = po->page_refs->next; +- if (po->page_refs == NULL) { +- for (i = 1; i < *count; i++) { +- to_merge_po[i - 1] = to_merge_po[i]; +- } +- (*count)--; +- return; +- } +- +- tmp = *po; +- offset = to_offset(po); +- for (i = 1; i < *count; i++) { +- if (to_offset(&to_merge_po[i]) >= offset) { +- break; +- } +- to_merge_po[i - 1] = to_merge_po[i]; +- } +- to_merge_po[i - 1] = tmp; +-} +- +-static void merge_share_pfs(struct page_refs **share_pfs, int share_pfs_num) +-{ +- int max_count = -1; +- struct page_refs *max_pf = NULL; +- int i; +- +- /* only keep one page_refs with max count */ +- for (i = 0; i < share_pfs_num; i++) { +- if (share_pfs[i]->count > max_count) { +- max_pf = share_pfs[i]; +- max_count = share_pfs[i]->count; +- } +- share_pfs[i]->count = -1; +- } +- max_pf->count = max_count; +-} +- +-static int do_merge_vma_pf(struct vma_pf *vma_pf, int count) +-{ +- struct page_refs **share_pfs = NULL; +- struct page_offset *to_merge_po = NULL; +- struct page_offset *iter = NULL; +- int share_pfs_num; +- uint64_t cur_offset = 0; +- uint64_t next_offset; +- int i; +- +- share_pfs = calloc(count, sizeof(struct page_refs *)); +- if (share_pfs == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "alloc share_pfs fail\n"); +- return -1; +- } +- +- to_merge_po = calloc(count, sizeof(struct page_offset)); +- if (to_merge_po == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "alloc iter_pfs fail\n"); +- free(share_pfs); +- return -1; +- } +- +- for (i = 0; i < count; i++) { +- to_merge_po[i].page_refs = vma_pf->page_refs; +- to_merge_po[i].to_offset = vma_pf->vma->offset - vma_pf->vma->start; +- vma_pf = vma_pf->next; +- } +- +- init_merge_po(to_merge_po, count); +- iter = to_merge_po; +- share_pfs[0] = iter->page_refs; +- share_pfs_num = 1; +- cur_offset = to_offset(iter); +- +- for (next_po(to_merge_po, &count); count > 0; next_po(to_merge_po, &count)) { +- iter = to_merge_po; +- next_offset = to_offset(iter); +- if (next_offset == cur_offset) { +- share_pfs[share_pfs_num] = iter->page_refs; +- share_pfs_num++; +- } else { +- if (share_pfs_num > 1) { +- merge_share_pfs(share_pfs, share_pfs_num); +- } +- share_pfs[0] = iter->page_refs; +- share_pfs_num = 1; +- cur_offset = next_offset; +- } +- +- } +- if (share_pfs_num > 1) { +- merge_share_pfs(share_pfs, share_pfs_num); +- } +- +- free(to_merge_po); +- free(share_pfs); +- return 0; +-} +- +-static int cslide_merge_share_vmas(struct cslide_eng_params *eng_params) +-{ +- struct cslide_pid_params *pid_params = NULL; +- struct vma_pf *vma_pf = NULL; +- struct vma_pf *iter = NULL; +- int count; +- uint64_t i; +- +- factory_foreach_working_pid_params(pid_params, &eng_params->factory) { +- vma_pf = pid_params->vma_pf; +- if (vma_pf == NULL) { +- continue; +- } +- for (i = 0; i < pid_params->vmas->vma_cnt; i++) { +- if (is_share(&vma_pf[i])) { +- sort_add_vma_pf(&vma_pf[i]); +- } +- } +- } +- +- vma_pf = g_share_vma_head; +- while (vma_pf != NULL) { +- for (iter = vma_pf->next, count = 1; +- iter != NULL && iter->vma->inode == vma_pf->vma->inode; +- iter = iter->next, count++) { +- ; +- } +- if (count > 1) { +- if (do_merge_vma_pf(vma_pf, count) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "merge vma with inode %lld fail\n", vma_pf->vma->inode); +- g_share_vma_head = NULL; +- return -1; +- } +- } +- vma_pf = iter; +- } +- g_share_vma_head = NULL; +- return 0; +-} +- + static int cslide_get_vmas(struct cslide_pid_params *pid_params) + { + struct cslide_task_params *task_params = pid_params->task_params; +@@ -1525,11 +1333,6 @@ static int cslide_do_scan(struct cslide_eng_params *eng_params) + sleep(eng_params->sleep); + } + +- if (cslide_merge_share_vmas(eng_params) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "cslide merge share vams fail\n"); +- return -1; +- } +- + return 0; + } + +-- +2.27.0 + diff --git a/0007-fix-error-when-open-idle_pages-failed.patch b/0007-fix-error-when-open-idle_pages-failed.patch new file mode 100644 index 0000000..66fa3d4 --- /dev/null +++ b/0007-fix-error-when-open-idle_pages-failed.patch @@ -0,0 +1,52 @@ +From 910519ccf986b80a7ee5a5aab90b62828bdc8b84 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Wed, 28 Apr 2021 09:54:06 +0800 +Subject: [PATCH 07/50] fix error when open idle_pages failed + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 3983a32..618cafe 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -1281,7 +1281,6 @@ static int cslide_scan_vmas(struct cslide_pid_params *params) + scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, SCAN_AS_HUGE, "r"); + if (scan_fp == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "open %s file for pid %u fail\n", IDLE_SCAN_FILE, params->pid); +- params->vma_pf = NULL; + return -1; + } + +@@ -1298,7 +1297,6 @@ static int cslide_scan_vmas(struct cslide_pid_params *params) + walk_address.walk_end = vma->end; + if (walk_vmas(fd, &walk_address, &vma_pf->page_refs, NULL) == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "scan vma start %llu end %llu fail\n", vma->start, vma->end); +- cslide_free_vmas(params); + fclose(scan_fp); + return -1; + } +@@ -1308,6 +1306,8 @@ static int cslide_scan_vmas(struct cslide_pid_params *params) + return 0; + } + ++// allocted data will be cleaned in cslide_main->cslide_clean_params ++// ->cslide_free_vmas + static int cslide_do_scan(struct cslide_eng_params *eng_params) + { + struct cslide_pid_params *iter = NULL; +@@ -1531,7 +1531,9 @@ static void cslide_clean_params(struct cslide_eng_params *eng_params) + struct cslide_pid_params *iter = NULL; + + factory_foreach_pid_params(iter, &eng_params->factory) { ++ // clean memory allocted in cslide_policy + clean_pid_param(iter); ++ // clean memory allocted in cslide_do_scan + cslide_free_vmas(iter); + } + } +-- +2.27.0 + diff --git a/0008-fix-memleak.patch b/0008-fix-memleak.patch new file mode 100644 index 0000000..ce7f29a --- /dev/null +++ b/0008-fix-memleak.patch @@ -0,0 +1,134 @@ +From c76f33082c0a67fe95fd7a00b079fb7191da32d5 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Wed, 28 Apr 2021 16:39:49 +0800 +Subject: [PATCH 08/50] fix memleak + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 23 ++++++++++++++++++----- + src/etmemd_src/etmemd_rpc.c | 17 ++++++++++++++++- + 2 files changed, 34 insertions(+), 6 deletions(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 618cafe..18cf740 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -689,6 +689,14 @@ static void factory_remove_pid_params(struct cslide_params_factory *factory, str + + static void factory_free_pid_params(struct cslide_params_factory *factory, struct cslide_pid_params *params) + { ++ // Pid not started i.e not used. Free it here ++ if (params->state == STATE_NONE) { ++ free_pid_params(params); ++ return; ++ } ++ ++ // Pid in use, free by cslide main when call factory_update_pid_params ++ // Avoid data race + params->state = STATE_FREE; + } + +@@ -771,7 +779,7 @@ static int cslide_count_node_pfs(struct cslide_pid_params *params) + void **pages = NULL; + int *status = NULL; + int actual_num = 0; +- int ret = -1; ++ int ret = 0; + int vma_i = 0; + + if (params->vmas == NULL || params->vma_pf == NULL) { +@@ -787,6 +795,7 @@ static int cslide_count_node_pfs(struct cslide_pid_params *params) + pages = malloc(sizeof(void *) * batch_size); + if (pages == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "malloc pages fail\n"); ++ ret = -1; + goto free_status; + } + +@@ -800,7 +809,9 @@ static int cslide_count_node_pfs(struct cslide_pid_params *params) + if (actual_num == batch_size || page_refs->next == NULL) { + if (move_pages(pid, actual_num, pages, NULL, status, MPOL_MF_MOVE_ALL) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "get page refs numa node fail\n"); +- goto free_pages; ++ clean_page_refs_unexpected(&last); ++ ret = -1; ++ break; + } + insert_count_pfs(params->count_page_refs, last, status, actual_num); + last = page_refs->next; +@@ -808,10 +819,10 @@ static int cslide_count_node_pfs(struct cslide_pid_params *params) + } + page_refs = page_refs->next; + } ++ ++ // this must be called before return + setup_count_pfs_tail(params->count_page_refs, params->count); +- ret = 0; + +-free_pages: + free(pages); + pages = NULL; + free_status: +@@ -2033,7 +2044,7 @@ static int cslide_fill_eng(GKeyFile *config, struct engine *eng) + + if (init_cslide_eng_params(params) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "init cslide engine params fail\n"); +- return -1; ++ goto free_eng_params; + } + + params->loop = eng->proj->loop; +@@ -2055,6 +2066,8 @@ static int cslide_fill_eng(GKeyFile *config, struct engine *eng) + + destroy_eng_params: + destroy_cslide_eng_params(params); ++free_eng_params: ++ free(params); + return -1; + } + +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index 2e8e49d..49c292d 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -492,6 +492,21 @@ static void free_server_rpc_params(struct server_rpc_params *svr) + free(svr->file_name); + svr->file_name = NULL; + } ++ ++ if (svr->eng_name != NULL) { ++ free(svr->eng_name); ++ svr->eng_name = NULL; ++ } ++ ++ if (svr->eng_cmd != NULL) { ++ free(svr->eng_cmd); ++ svr->eng_cmd = NULL; ++ } ++ ++ if (svr->task_name != NULL) { ++ free(svr->task_name); ++ svr->task_name = NULL; ++ } + } + + static void etmemd_rpc_send_response_msg(int sock_fd, enum opt_result result) +@@ -531,7 +546,6 @@ static void etmemd_rpc_handle(int sock_fd) + } + + etmemd_rpc_send_response_msg(sock_fd, ret); +- free_server_rpc_params(&g_rpc_params); + return; + } + +@@ -605,6 +619,7 @@ static int etmemd_rpc_accept(int sock_fd) + if (etmemd_rpc_parse(recv_buf, (unsigned long)rc) == 0) { + etmemd_rpc_handle(accp_fd); + } ++ free_server_rpc_params(&g_rpc_params); + ret = 0; + + RPC_EXIT: +-- +2.27.0 + diff --git a/0009-fix-some-bugs-that-occur-when-execute-obj-add-or-del.patch b/0009-fix-some-bugs-that-occur-when-execute-obj-add-or-del.patch new file mode 100644 index 0000000..ceea45c --- /dev/null +++ b/0009-fix-some-bugs-that-occur-when-execute-obj-add-or-del.patch @@ -0,0 +1,56 @@ +From a3e62729dafbb634a73921c2200337fb46ab923e Mon Sep 17 00:00:00 2001 +From: louhongxiang +Date: Thu, 29 Apr 2021 10:47:51 +0800 +Subject: [PATCH 09/50] fix some bugs that occur when execute obj add or del + command. + +--- + src/etmem_src/etmem_rpc.c | 2 +- + src/etmemd_src/etmemd_file.c | 4 ++++ + src/etmemd_src/etmemd_rpc.c | 2 +- + 3 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/etmem_src/etmem_rpc.c b/src/etmem_src/etmem_rpc.c +index 8d03914..fadf1ea 100644 +--- a/src/etmem_src/etmem_rpc.c ++++ b/src/etmem_src/etmem_rpc.c +@@ -182,7 +182,7 @@ static int etmem_client_recv(int sockfd) + + recv_msg = (char *)recv_buf; + recv_msg[recv_size] = '\0'; +- printf("%s", recv_msg); ++ printf("%s\n", recv_msg); + if (etmem_recv_find_fail_keyword(recv_msg)) { + printf("error occurs when getting response from etmemd server\n"); + goto EXIT; +diff --git a/src/etmemd_src/etmemd_file.c b/src/etmemd_src/etmemd_file.c +index ac2654e..8b478c6 100644 +--- a/src/etmemd_src/etmemd_file.c ++++ b/src/etmemd_src/etmemd_file.c +@@ -35,6 +35,10 @@ static int parse_item(GKeyFile *config, char *group_name, struct config_item *it + break; + case STR_VAL: + val = (void *)g_key_file_get_string(config, group_name, item->key, &error); ++ if (val == NULL || strlen(val) == 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "section %s of group [%s] should not be empty\n", item->key, group_name); ++ return -1; ++ } + break; + default: + etmemd_log(ETMEMD_LOG_ERR, "config item type %d not support\n", item->type); +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index 49c292d..a8653e2 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -63,7 +63,7 @@ struct rpc_resp_msg g_resp_msg_arr[] = { + {OPT_ENG_NOEXIST, "error: engine is not exist"}, + {OPT_TASK_EXISTED, "error: task has been existed"}, + {OPT_TASK_NOEXIST, "error: task is not exist"}, +- {OPT_INTER_ERR, "error: etmemd has internal error"}, ++ {OPT_INTER_ERR, "error: etmemd has internal error, see reason details in messages"}, + {OPT_RET_END, NULL}, + }; + +-- +2.27.0 + diff --git a/0010-clean-code.patch b/0010-clean-code.patch new file mode 100644 index 0000000..69d60fa --- /dev/null +++ b/0010-clean-code.patch @@ -0,0 +1,334 @@ +From 146be685ec749239979023358a653ef960652f6c Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Wed, 28 Apr 2021 19:19:30 +0800 +Subject: [PATCH 10/50] clean code + +Signed-off-by: Kemeng Shi +--- + inc/etmem_inc/etmem_common.h | 2 - + src/etmem_src/etmem.c | 2 +- + src/etmem_src/etmem_common.c | 73 --------------------------------- + src/etmem_src/etmem_engine.c | 18 +++++--- + src/etmem_src/etmem_obj.c | 46 ++------------------- + src/etmem_src/etmem_project.c | 22 +++------- + src/etmem_src/etmem_rpc.c | 2 +- + src/etmemd_src/etmemd_project.c | 6 ++- + 8 files changed, 30 insertions(+), 141 deletions(-) + +diff --git a/inc/etmem_inc/etmem_common.h b/inc/etmem_inc/etmem_common.h +index 294d216..09f6e1a 100644 +--- a/inc/etmem_inc/etmem_common.h ++++ b/inc/etmem_inc/etmem_common.h +@@ -36,8 +36,6 @@ struct mem_proj { + char *eng_cmd; + }; + +-int parse_name_string(const char *val, char **name_str, size_t max_len); + int etmem_parse_check_result(int params_cnt, int argc); +-void free_proj_member(struct mem_proj *proj); + + #endif +diff --git a/src/etmem_src/etmem.c b/src/etmem_src/etmem.c +index 863f91b..7f04ad1 100644 +--- a/src/etmem_src/etmem.c ++++ b/src/etmem_src/etmem.c +@@ -34,7 +34,7 @@ static void usage(void) + " etmem OBJECT COMMAND\n" + " etmem help\n" + "\nParameters:\n" +- " OBJECT := { project | migrate }\n" ++ " OBJECT := { project | obj }\n" + " COMMAND := { add | del | start | stop | show | help }\n"); + } + +diff --git a/src/etmem_src/etmem_common.c b/src/etmem_src/etmem_common.c +index 8d0cee3..66fbfc9 100644 +--- a/src/etmem_src/etmem_common.c ++++ b/src/etmem_src/etmem_common.c +@@ -20,43 +20,6 @@ + #include "securec.h" + #include "etmem_common.h" + +-int parse_name_string(const char *val, char **name_str, size_t max_len) +-{ +- size_t len; +- int ret; +- +- if (val == NULL) { +- printf("name string should not be NULL\n"); +- return -EINVAL; +- } +- +- len = strlen(val) + 1; +- if (len == 1) { +- printf("name string should not be empty\n"); +- return -EINVAL; +- } +- if (len > max_len) { +- printf("string is too long, it should not be larger than %zu\n", max_len); +- return -ENAMETOOLONG; +- } +- +- *name_str = (char *)calloc(len, sizeof(char)); +- if (*name_str == NULL) { +- printf("malloc project name failed.\n"); +- return -ENOMEM; +- } +- +- ret = strncpy_s(*name_str, len, val, len - 1); +- if (ret != EOK) { +- printf("strncpy_s project name failed.\n"); +- free(*name_str); +- *name_str = NULL; +- return ret; +- } +- +- return 0; +-} +- + int etmem_parse_check_result(int params_cnt, int argc) + { + if (params_cnt > 0 && argc - 1 > params_cnt * 2) { /* maximum number of args is limited to params_cnt * 2+1 */ +@@ -66,39 +29,3 @@ int etmem_parse_check_result(int params_cnt, int argc) + + return 0; + } +- +-void free_proj_member(struct mem_proj *proj) +-{ +- if (proj->proj_name != NULL) { +- free(proj->proj_name); +- proj->proj_name = NULL; +- } +- +- if (proj->file_name != NULL) { +- free(proj->file_name); +- proj->file_name = NULL; +- } +- +- if (proj->sock_name != NULL) { +- free(proj->sock_name); +- proj->sock_name = NULL; +- } +- +- if (proj->eng_name != NULL) { +- free(proj->eng_name); +- proj->eng_name = NULL; +- } +- +- if (proj->task_name != NULL) { +- free(proj->task_name); +- proj->task_name = NULL; +- } +- +- if (proj->eng_cmd != NULL) { +- free(proj->eng_cmd); +- proj->eng_cmd = NULL; +- } +- +-} +- +- +diff --git a/src/etmem_src/etmem_engine.c b/src/etmem_src/etmem_engine.c +index 7673205..e744aaa 100644 +--- a/src/etmem_src/etmem_engine.c ++++ b/src/etmem_src/etmem_engine.c +@@ -23,15 +23,23 @@ + + static void engine_help(void) + { +- printf("etmem engine help information\n"); ++ printf("\nUsage:\n" ++ " memig engine eng_cmd [options]\n" ++ " memig engine help\n" ++ "\nOptions:\n" ++ " -n|--proj_name project engine belongs to\n" ++ " -s|--socket socket name to connect\n" ++ " -e|--engine engine to execute cmd\n" ++ " -t|--task_name task for cmd\n" ++ "\nNotes:\n" ++ " 1. project name must be given.\n" ++ " 2. socket name must be given.\n" ++ " 3. engine name must be given.\n" ++ " 4. engine cmd must be given.\n"); + } + + static int engine_parse_cmd(struct etmem_conf *conf, struct mem_proj *proj) + { +- if (conf->argc == 0) { +- printf("too few params for etmem client engine command\n"); +- return -1; +- } + proj->eng_cmd = conf->argv[0]; + proj->cmd = ETMEM_CMD_ENGINE; + return 0; +diff --git a/src/etmem_src/etmem_obj.c b/src/etmem_src/etmem_obj.c +index a3f66fe..a5517ea 100644 +--- a/src/etmem_src/etmem_obj.c ++++ b/src/etmem_src/etmem_obj.c +@@ -61,34 +61,6 @@ static int obj_parse_cmd(struct etmem_conf *conf, struct mem_proj *proj) + return -1; + } + +-static int parse_file_name(const char *val, char **file_name) +-{ +- size_t len; +- int ret; +- +- len = strlen(val) + 1; +- if (len > FILE_NAME_MAX_LEN) { +- printf("file name is too long, should not be larger than %u\n", FILE_NAME_MAX_LEN); +- return -ENAMETOOLONG; +- } +- +- *file_name = (char *)calloc(len, sizeof(char)); +- if (*file_name == NULL) { +- printf("malloc file name failed\n"); +- return -ENOMEM; +- } +- +- ret = strncpy_s(*file_name, len, val, len - 1); +- if (ret != EOK) { +- printf("strncpy_s file name fail\n"); +- free(*file_name); +- *file_name = NULL; +- return ret; +- } +- +- return 0; +-} +- + static int obj_parse_args(struct etmem_conf *conf, struct mem_proj *proj) + { + int opt, ret; +@@ -102,18 +74,10 @@ static int obj_parse_args(struct etmem_conf *conf, struct mem_proj *proj) + while ((opt = getopt_long(conf->argc, conf->argv, "f:s:", opts, NULL)) != -1) { + switch (opt) { + case 'f': +- ret = parse_file_name(optarg, &proj->file_name); +- if (ret != 0) { +- printf("parse file name failed\n"); +- return ret; +- } ++ proj->file_name = optarg; + break; + case 's': +- ret = parse_name_string(optarg, &proj->sock_name, SOCKET_NAME_MAX_LEN); +- if (ret != 0) { +- printf("parse socket name failed.\n"); +- return ret; +- } ++ proj->sock_name = optarg; + break; + case '?': + /* fallthrough */ +@@ -164,19 +128,17 @@ static int obj_do_cmd(struct etmem_conf *conf) + ret = obj_parse_args(conf, &proj); + if (ret != 0) { + printf("obj_parse_args fail\n"); +- goto EXIT; ++ return ret; + } + + ret = obj_check_params(&proj); + if (ret != 0) { + printf("obj_check_params fail\n"); +- goto EXIT; ++ return ret; + } + + ret = etmem_rpc_client(&proj); + +-EXIT: +- free_proj_member(&proj); + return ret; + } + +diff --git a/src/etmem_src/etmem_project.c b/src/etmem_src/etmem_project.c +index 790979e..bb53df3 100644 +--- a/src/etmem_src/etmem_project.c ++++ b/src/etmem_src/etmem_project.c +@@ -78,22 +78,14 @@ static int project_parse_args(const struct etmem_conf *conf, struct mem_proj *pr + {NULL, 0, NULL, 0}, + }; + +- while ((opt = getopt_long(conf->argc, conf->argv, "f:n:s:", ++ while ((opt = getopt_long(conf->argc, conf->argv, "n:s:", + opts, NULL)) != -1) { + switch (opt) { + case 'n': +- ret = parse_name_string(optarg, &proj->proj_name, PROJECT_NAME_MAX_LEN); +- if (ret != 0) { +- printf("parse project name failed.\n"); +- return ret; +- } ++ proj->proj_name = optarg; + break; + case 's': +- ret = parse_name_string(optarg, &proj->sock_name, SOCKET_NAME_MAX_LEN); +- if (ret != 0) { +- printf("parse socket name failed.\n"); +- return ret; +- } ++ proj->sock_name = optarg; + break; + case '?': + /* fallthrough */ +@@ -148,18 +140,16 @@ static int project_do_cmd(struct etmem_conf *conf) + + ret = project_parse_args(conf, &proj); + if (ret != 0) { +- goto EXIT; ++ return ret; + } + + ret = project_check_params(&proj); + if (ret != 0) { +- goto EXIT; ++ return ret; + } + +- etmem_rpc_client(&proj); ++ ret = etmem_rpc_client(&proj); + +-EXIT: +- free_proj_member(&proj); + return ret; + } + +diff --git a/src/etmem_src/etmem_rpc.c b/src/etmem_src/etmem_rpc.c +index 8d03914..76fadb8 100644 +--- a/src/etmem_src/etmem_rpc.c ++++ b/src/etmem_src/etmem_rpc.c +@@ -134,7 +134,7 @@ static int etmem_client_send(const struct mem_proj *proj, int sockfd) + } + + if (send(sockfd, reg_cmd, reg_cmd_len, 0) < 0) { +- perror("send failed:"); ++ perror("send failed:"); + goto EXIT; + } + ret = 0; +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index bd21819..b3158d8 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -709,10 +709,14 @@ enum opt_result etmemd_project_mgt_engine(const char *project_name, const char * + eng = get_eng_by_name(proj, eng_name); + if (eng == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "engine %s is not existed\n", eng_name); +- return OPT_INVAL; ++ return OPT_ENG_NOEXIST; + } + if (task_name != NULL) { + tk = get_task_by_name(proj, eng, task_name); ++ if (tk == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "task %s not found\n", task_name); ++ return OPT_TASK_NOEXIST; ++ } + } + if (eng->ops->eng_mgt_func(eng, tk, cmd, sock_fd) != 0) { + return OPT_INVAL; +-- +2.27.0 + diff --git a/0011-wait-for-next-period-when-error-occurs-in-this-perio.patch b/0011-wait-for-next-period-when-error-occurs-in-this-perio.patch new file mode 100644 index 0000000..aa82585 --- /dev/null +++ b/0011-wait-for-next-period-when-error-occurs-in-this-perio.patch @@ -0,0 +1,111 @@ +From e92f5b0da3bde551281df30c498e701c767e3335 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Wed, 28 Apr 2021 19:36:57 +0800 +Subject: [PATCH 11/50] wait for next period when error occurs in this period + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 18cf740..1749383 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -1184,7 +1184,7 @@ static void move_cold_pages(struct cslide_eng_params *eng_params, struct flow_ct + do_filter(&filter, eng_params); + } + +-static void cslide_filter_pfs(struct cslide_eng_params *eng_params) ++static int cslide_filter_pfs(struct cslide_eng_params *eng_params) + { + struct flow_ctrl ctrl; + long long quota = (long long)eng_params->mig_quota * HUGE_1M_SIZE; +@@ -1192,7 +1192,7 @@ static void cslide_filter_pfs(struct cslide_eng_params *eng_params) + + if (init_flow_ctrl(&ctrl, &eng_params->mem, &eng_params->node_map, quota, reserve) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "init_flow_ctrl fail\n"); +- return; ++ return -1; + } + + move_hot_pages(eng_params, &ctrl); +@@ -1200,6 +1200,7 @@ static void cslide_filter_pfs(struct cslide_eng_params *eng_params) + move_cold_pages(eng_params, &ctrl); + + destroy_flow_ctrl(&ctrl); ++ return 0; + } + + static int cslide_policy(struct cslide_eng_params *eng_params) +@@ -1215,8 +1216,7 @@ static int cslide_policy(struct cslide_eng_params *eng_params) + } + } + +- cslide_filter_pfs(eng_params); +- return 0; ++ return cslide_filter_pfs(eng_params); + } + + static int cslide_get_vmas(struct cslide_pid_params *pid_params) +@@ -1225,6 +1225,7 @@ static int cslide_get_vmas(struct cslide_pid_params *pid_params) + struct vma *vma = NULL; + char pid[PID_STR_MAX_LEN] = {0}; + uint64_t i; ++ int ret = -1; + + if (snprintf_s(pid, PID_STR_MAX_LEN, PID_STR_MAX_LEN - 1, "%u", pid_params->pid) <= 0) { + etmemd_log(ETMEMD_LOG_ERR, "sprintf pid %u fail\n", pid_params->pid); +@@ -1236,6 +1237,13 @@ static int cslide_get_vmas(struct cslide_pid_params *pid_params) + etmemd_log(ETMEMD_LOG_ERR, "get vmas for %s fail\n", pid); + return -1; + } ++ // avoid calloc for vma_pf with size 0 below ++ // return success as vma may be created later ++ if (pid_params->vmas->vma_cnt == 0) { ++ etmemd_log(ETMEMD_LOG_WARN, "no vma detect for %s\n", pid); ++ ret = 0; ++ goto free_vmas; ++ } + + pid_params->vma_pf = calloc(pid_params->vmas->vma_cnt, sizeof(struct vma_pf)); + if (pid_params->vma_pf == NULL) { +@@ -1253,7 +1261,7 @@ static int cslide_get_vmas(struct cslide_pid_params *pid_params) + free_vmas: + free_vmas(pid_params->vmas); + pid_params->vmas = NULL; +- return -1; ++ return ret; + } + + static void cslide_free_vmas(struct cslide_pid_params *params) +@@ -1327,7 +1335,7 @@ static int cslide_do_scan(struct cslide_eng_params *eng_params) + factory_foreach_working_pid_params(iter, &eng_params->factory) { + if (cslide_get_vmas(iter) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "cslide get vmas fail\n"); +- continue; ++ return -1; + } + } + +@@ -1338,7 +1346,7 @@ static int cslide_do_scan(struct cslide_eng_params *eng_params) + } + if (cslide_scan_vmas(iter) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "cslide scan vmas fail\n"); +- continue; ++ return -1; + } + } + sleep(eng_params->sleep); +@@ -1387,7 +1395,7 @@ static int do_migrate_pages(unsigned int pid, struct page_refs *page_refs, int n + actual_num = 0; + if (ret != 0) { + etmemd_log(ETMEMD_LOG_ERR, "task %d move_pages fail with %d errno %d\n", pid, ret, errno); +- continue; ++ break; + } + } + } +-- +2.27.0 + diff --git a/0012-add-recursive-in-etmemd_get_task_pids.patch b/0012-add-recursive-in-etmemd_get_task_pids.patch new file mode 100644 index 0000000..65faf51 --- /dev/null +++ b/0012-add-recursive-in-etmemd_get_task_pids.patch @@ -0,0 +1,110 @@ +From 2eba7f18281d1a7a6a728095cd16b1ebb1b36c0a Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Wed, 28 Apr 2021 19:48:33 +0800 +Subject: [PATCH 12/50] add recursive in etmemd_get_task_pids to control if it + should get child pids. cslide will not get child pids. + +Signed-off-by: Kemeng Shi +--- + inc/etmemd_inc/etmemd_task.h | 2 +- + src/etmemd_src/etmemd_cslide.c | 2 +- + src/etmemd_src/etmemd_pool_adapter.c | 2 +- + src/etmemd_src/etmemd_task.c | 23 +++++++++++++---------- + 4 files changed, 16 insertions(+), 13 deletions(-) + +diff --git a/inc/etmemd_inc/etmemd_task.h b/inc/etmemd_inc/etmemd_task.h +index d6d89ea..3f32be5 100644 +--- a/inc/etmemd_inc/etmemd_task.h ++++ b/inc/etmemd_inc/etmemd_task.h +@@ -51,7 +51,7 @@ struct task { + struct task *next; + }; + +-int etmemd_get_task_pids(struct task *tk); ++int etmemd_get_task_pids(struct task *tk, bool recursive); + + void etmemd_free_task_pids(struct task *tk); + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 1749383..43d8108 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -1899,7 +1899,7 @@ static int cslide_fill_task(GKeyFile *config, struct task *tk) + } + + tk->params = params; +- if (etmemd_get_task_pids(tk) != 0) { ++ if (etmemd_get_task_pids(tk, false) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "cslide fail to get task pids\n"); + tk->params = NULL; + goto exit; +diff --git a/src/etmemd_src/etmemd_pool_adapter.c b/src/etmemd_src/etmemd_pool_adapter.c +index 417f864..b879dbc 100644 +--- a/src/etmemd_src/etmemd_pool_adapter.c ++++ b/src/etmemd_src/etmemd_pool_adapter.c +@@ -49,7 +49,7 @@ static void *launch_threadtimer_executor(void *arg) + int scheduing_count; + + if (tk->eng->proj->start) { +- if (etmemd_get_task_pids(tk) != 0) { ++ if (etmemd_get_task_pids(tk, true) != 0) { + return NULL; + } + +diff --git a/src/etmemd_src/etmemd_task.c b/src/etmemd_src/etmemd_task.c +index 5c81b74..61ba0df 100644 +--- a/src/etmemd_src/etmemd_task.c ++++ b/src/etmemd_src/etmemd_task.c +@@ -264,19 +264,13 @@ int get_pid_from_task_type(const struct task *tk, char *pid) + return -1; + } + +-static int get_and_fill_pids(struct task *tk, char *pid) ++static int fill_task_child_pid(struct task *tk, char *pid) + { + char *arg_pid[] = {"/usr/bin/pgrep", "-P", pid, NULL}; + FILE *file = NULL; + int ret; + int pipefd[2]; /* used for pipefd[2] communication to obtain the task PID */ + +- /* first, insert the pid of task into the pids list */ +- if (fill_task_pid(tk, pid) != 0) { +- etmemd_log(ETMEMD_LOG_WARN, "fill task pid fail\n"); +- return -1; +- } +- + if (pipe(pipefd) == -1) { + return -1; + } +@@ -341,7 +335,7 @@ void etmemd_free_task_pids(struct task *tk) + } + } + +-int etmemd_get_task_pids(struct task *tk) ++int etmemd_get_task_pids(struct task *tk, bool recursive) + { + char pid[PID_STR_MAX_LEN] = {0}; + +@@ -356,8 +350,17 @@ int etmemd_get_task_pids(struct task *tk) + return -1; + } + +- /* then fill the pids according to the pid of task */ +- if (get_and_fill_pids(tk, pid) != 0) { ++ /* first, insert the pid of task into the pids list */ ++ if (fill_task_pid(tk, pid) != 0) { ++ etmemd_log(ETMEMD_LOG_WARN, "fill task pid fail\n"); ++ return -1; ++ } ++ if (!recursive) { ++ return 0; ++ } ++ ++ /* then fill the child pids according to the pid of task */ ++ if (fill_task_child_pid(tk, pid) != 0) { + etmemd_free_task_pids(tk); + etmemd_log(ETMEMD_LOG_WARN, "get task child pids fail\n"); + return -1; +-- +2.27.0 + diff --git a/0013-check-permission-according-cmd-to-be-executed.patch b/0013-check-permission-according-cmd-to-be-executed.patch new file mode 100644 index 0000000..9ba7154 --- /dev/null +++ b/0013-check-permission-according-cmd-to-be-executed.patch @@ -0,0 +1,130 @@ +From c4aca9bea94bc7fd639a6b508675b3f113e3736e Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 29 Apr 2021 09:26:06 +0800 +Subject: [PATCH 13/50] check permission according cmd to be executed + +Signed-off-by: Kemeng Shi +--- + inc/etmemd_inc/etmemd_rpc.h | 2 + + src/etmemd_src/etmemd_rpc.c | 75 ++++++++++++++++++++++--------------- + 2 files changed, 46 insertions(+), 31 deletions(-) + +diff --git a/inc/etmemd_inc/etmemd_rpc.h b/inc/etmemd_inc/etmemd_rpc.h +index 146cec3..4f61390 100644 +--- a/inc/etmemd_inc/etmemd_rpc.h ++++ b/inc/etmemd_inc/etmemd_rpc.h +@@ -55,5 +55,7 @@ int etmemd_parse_sock_name(const char *sock_name); + int etmemd_rpc_server(void); + bool etmemd_sock_name_set(void); + void etmemd_sock_name_free(void); ++// some engine cmd need to check socket permission ++int check_socket_permission(int sock_fd); + + #endif +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index 49c292d..09497b3 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -181,10 +181,54 @@ free_file: + return ret; + } + ++int check_socket_permission(int sock_fd) { ++ struct ucred cred; ++ socklen_t len; ++ ssize_t rc; ++ ++ len = sizeof(struct ucred); ++ ++ rc = getsockopt(sock_fd, ++ SOL_SOCKET, ++ SO_PEERCRED, ++ &cred, ++ &len); ++ if (rc < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "getsockopt failed, err(%s)\n", ++ strerror(errno)); ++ return -1; ++ } ++ ++ if (cred.uid != 0 || cred.gid != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "client socket connect failed, permition denied\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++// ENG_CMD cmd permission checked inside engine ++static int check_cmd_permission(int sock_fd, int cmd) ++{ ++ switch (cmd) { ++ case OBJ_ADD: ++ case OBJ_DEL: ++ case MIG_STOP: ++ case MIG_START: ++ return check_socket_permission(sock_fd); ++ default: ++ return 0; ++ } ++} ++ + static enum opt_result etmemd_switch_cmd(const struct server_rpc_params svr_param) + { + enum opt_result ret = OPT_INVAL; + ++ if (check_cmd_permission(svr_param.sock_fd, svr_param.cmd) != 0) { ++ return OPT_INVAL; ++ } ++ + switch (svr_param.cmd) { + case OBJ_ADD: + case OBJ_DEL: +@@ -549,32 +593,6 @@ static void etmemd_rpc_handle(int sock_fd) + return; + } + +-static int check_socket_permission(int sock_fd) { +- struct ucred cred; +- socklen_t len; +- ssize_t rc; +- +- len = sizeof(struct ucred); +- +- rc = getsockopt(sock_fd, +- SOL_SOCKET, +- SO_PEERCRED, +- &cred, +- &len); +- if (rc < 0) { +- etmemd_log(ETMEMD_LOG_ERR, "getsockopt failed, err(%s)\n", +- strerror(errno)); +- return -1; +- } +- +- if (cred.uid != 0 || cred.gid != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "client socket connect failed, permition denied\n"); +- return -1; +- } +- +- return 0; +-} +- + static int etmemd_rpc_accept(int sock_fd) + { + char *recv_buf = NULL; +@@ -597,11 +615,6 @@ static int etmemd_rpc_accept(int sock_fd) + return 0; + } + +- rc = check_socket_permission(accp_fd); +- if (rc != 0) { +- goto RPC_EXIT; +- } +- + rc = recv(accp_fd, recv_buf, RPC_BUFF_LEN_MAX, 0); + if (rc <= 0) { + etmemd_log(ETMEMD_LOG_WARN, "socket recive from client fail, error(%s)\n", +-- +2.27.0 + diff --git a/0014-stat-pages-info-early-only-replace-cold-mem-in-hot-nodes.patch b/0014-stat-pages-info-early-only-replace-cold-mem-in-hot-nodes.patch new file mode 100644 index 0000000..ab0ecc8 --- /dev/null +++ b/0014-stat-pages-info-early-only-replace-cold-mem-in-hot-nodes.patch @@ -0,0 +1,300 @@ +From 2a63484709098a551cbf6996c5362f25f6539ca5 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 29 Apr 2021 11:32:07 +0800 +Subject: [PATCH 14/50] stat pages info early only replace cold mem in hot node + in order to reduce pages to move + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 134 ++++++++++++++++++++------------- + 1 file changed, 81 insertions(+), 53 deletions(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 43d8108..7c30508 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -36,6 +36,7 @@ + #define HUGE_1G_SIZE (1 << 30) + #define BYTE_TO_KB(s) ((s) >> 10) + #define KB_TO_BYTE(s) ((s) << 10) ++#define HUGE_2M_TO_KB(s) ((s) << 11) + + #define TO_PCT 100 + #define MAX_WM 100 +@@ -154,6 +155,7 @@ struct cslide_eng_params { + int sleep; + }; + struct cslide_params_factory factory; ++ struct node_pages_info *host_pages_info; + bool finish; + }; + +@@ -166,12 +168,13 @@ struct node_ctrl { + struct ctrl_cap hot_move_cap; + struct ctrl_cap hot_prefetch_cap; + struct ctrl_cap cold_move_cap; +- long long cold_replaced; +- long long cold_free; +- long long free; +- long long total; +- long long quota; +- long long reserve; ++ long long cold_replaced; // cold mem in hot node replace by hot mem in cold node ++ long long cold_free; // free mem in cold node ++ long long free; // free mem in hot node ++ long long cold; // cold mem in hot node ++ long long total; // total mem in hot node ++ long long quota; // move quota ++ long long reserve; // reserve space can't used by cold mem + }; + + struct flow_ctrl { +@@ -854,17 +857,21 @@ static bool node_cal_hot_can_move(struct node_ctrl *node_ctrl) + { + long long can_move; + ++ // can_move limited by quota + if (node_ctrl->quota < node_ctrl->free) { + can_move = node_ctrl->quota; + } else { ++ // can_move limited by hot node free + can_move = node_ctrl->free + (node_ctrl->quota - node_ctrl->free) / 2; ++ // can_move limited by cold node free + if (can_move > node_ctrl->free + node_ctrl->cold_free) { + can_move = node_ctrl->free + node_ctrl->cold_free; + } + } + +- if (can_move > node_ctrl->total) { +- can_move = node_ctrl->total; ++ // can_move limited by free and cold mem in hot node ++ if (can_move > node_ctrl->cold + node_ctrl->free) { ++ can_move = node_ctrl->cold + node_ctrl->free; + } + node_ctrl->hot_move_cap.cap = can_move; + return can_move > 0; +@@ -963,9 +970,13 @@ static inline bool node_move_cold(struct node_ctrl *node_ctrl, long long *target + return cap_cost(&node_ctrl->cold_move_cap, target); + } + +-static int init_flow_ctrl(struct flow_ctrl *ctrl, struct sys_mem *sys_mem, struct node_map *node_map, +- long long quota, long long reserve) ++static int init_flow_ctrl(struct flow_ctrl *ctrl, struct cslide_eng_params *eng_params) + { ++ ++ long long quota = (long long)eng_params->mig_quota * HUGE_1M_SIZE; ++ long long reserve = (long long)eng_params->hot_reserve * HUGE_1M_SIZE; ++ struct sys_mem *sys_mem = &eng_params->mem; ++ struct node_map *node_map = &eng_params->node_map; + struct node_pair *pair = NULL; + struct node_ctrl *tmp = NULL; + int i; +@@ -985,6 +996,7 @@ static int init_flow_ctrl(struct flow_ctrl *ctrl, struct sys_mem *sys_mem, struc + tmp = &ctrl->node_ctrl[i]; + tmp->cold_free = sys_mem->node_mem[pair->cold_node].huge_free; + tmp->free = sys_mem->node_mem[pair->hot_node].huge_free; ++ tmp->cold = KB_TO_BYTE((unsigned long long)eng_params->host_pages_info[pair->hot_node].cold); + tmp->total = sys_mem->node_mem[pair->hot_node].huge_total; + tmp->quota = quota; + tmp->reserve = reserve; +@@ -1187,10 +1199,8 @@ static void move_cold_pages(struct cslide_eng_params *eng_params, struct flow_ct + static int cslide_filter_pfs(struct cslide_eng_params *eng_params) + { + struct flow_ctrl ctrl; +- long long quota = (long long)eng_params->mig_quota * HUGE_1M_SIZE; +- long long reserve = (long long)eng_params->hot_reserve * HUGE_1M_SIZE; + +- if (init_flow_ctrl(&ctrl, &eng_params->mem, &eng_params->node_map, quota, reserve) != 0) { ++ if (init_flow_ctrl(&ctrl, eng_params) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "init_flow_ctrl fail\n"); + return -1; + } +@@ -1203,22 +1213,6 @@ static int cslide_filter_pfs(struct cslide_eng_params *eng_params) + return 0; + } + +-static int cslide_policy(struct cslide_eng_params *eng_params) +-{ +- struct cslide_pid_params *pid_params = NULL; +- int ret; +- +- factory_foreach_working_pid_params(pid_params, &eng_params->factory) { +- ret = cslide_count_node_pfs(pid_params); +- if (ret != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "count node page refs fail\n"); +- return ret; +- } +- } +- +- return cslide_filter_pfs(eng_params); +-} +- + static int cslide_get_vmas(struct cslide_pid_params *pid_params) + { + struct cslide_task_params *task_params = pid_params->task_params; +@@ -1510,26 +1504,41 @@ static bool need_migrate(struct cslide_eng_params *eng_params) + return false; + } + +-static void get_node_pages_info(struct cslide_pid_params *pid_params) ++static void init_host_pages_info(struct cslide_eng_params *eng_params) ++{ ++ int n; ++ int node_num = eng_params->mem.node_num; ++ struct node_pages_info *host_pages = eng_params->host_pages_info; ++ ++ for (n = 0; n < node_num; n++) { ++ host_pages[n].cold = 0; ++ host_pages[n].hot = 0; ++ } ++} ++ ++static void update_pages_info(struct cslide_eng_params *eng_params, struct cslide_pid_params *pid_params) + { +- struct cslide_eng_params *eng_params = pid_params->eng_params; + int n, c; + int t = eng_params->hot_threshold; + int count = pid_params->count; + int actual_t = t > count ? count + 1 : t; + int node_num = pid_params->count_page_refs->node_num; +- struct node_pages_info *info = pid_params->node_pages_info; ++ struct node_pages_info *task_pages = pid_params->node_pages_info; ++ struct node_pages_info *host_pages = eng_params->host_pages_info; + + for (n = 0; n < node_num; n++) { +- info[n].cold = 0; +- info[n].hot = 0; ++ task_pages[n].cold = 0; ++ task_pages[n].hot = 0; + + for (c = 0; c < actual_t; c++) { +- info[n].cold += pid_params->count_page_refs[c].node_pfs[n].num * 2 * 1024; ++ task_pages[n].cold += HUGE_2M_TO_KB(pid_params->count_page_refs[c].node_pfs[n].num); + } + for (; c <= count; c++) { +- info[n].hot += pid_params->count_page_refs[c].node_pfs[n].num * 2 * 1024; ++ task_pages[n].hot += HUGE_2M_TO_KB(pid_params->count_page_refs[c].node_pfs[n].num); + } ++ ++ host_pages[n].cold += task_pages[n].cold; ++ host_pages[n].hot += task_pages[n].hot; + } + } + +@@ -1538,13 +1547,33 @@ static void cslide_stat(struct cslide_eng_params *eng_params) + struct cslide_pid_params *iter = NULL; + + pthread_mutex_lock(&eng_params->stat_mtx); ++ init_host_pages_info(eng_params); + factory_foreach_working_pid_params(iter, &eng_params->factory) { +- get_node_pages_info(iter); ++ update_pages_info(eng_params, iter); + } + eng_params->stat_time = time(NULL); + pthread_mutex_unlock(&eng_params->stat_mtx); + } + ++static int cslide_policy(struct cslide_eng_params *eng_params) ++{ ++ struct cslide_pid_params *pid_params = NULL; ++ int ret; ++ ++ factory_foreach_working_pid_params(pid_params, &eng_params->factory) { ++ ret = cslide_count_node_pfs(pid_params); ++ if (ret != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "count node page refs fail\n"); ++ return ret; ++ } ++ } ++ ++ // update pages info now, so cslide_filter_pfs can use this info ++ cslide_stat(eng_params); ++ ++ return cslide_filter_pfs(eng_params); ++} ++ + static void cslide_clean_params(struct cslide_eng_params *eng_params) + { + struct cslide_pid_params *iter = NULL; +@@ -1559,6 +1588,8 @@ static void cslide_clean_params(struct cslide_eng_params *eng_params) + + static void destroy_cslide_eng_params(struct cslide_eng_params *params) + { ++ free(params->host_pages_info); ++ params->host_pages_info = NULL; + destroy_factory(¶ms->factory); + pthread_mutex_destroy(¶ms->stat_mtx); + destroy_node_map(¶ms->node_map); +@@ -1567,6 +1598,8 @@ static void destroy_cslide_eng_params(struct cslide_eng_params *params) + + static int init_cslide_eng_params(struct cslide_eng_params *params) + { ++ int node_num; ++ + if (init_sys_mem(¶ms->mem) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "init system memory fail\n"); + return -1; +@@ -1587,8 +1620,18 @@ static int init_cslide_eng_params(struct cslide_eng_params *params) + goto destroy_stat_mtx; + } + ++ node_num = params->mem.node_num; ++ params->host_pages_info = calloc(node_num, sizeof(struct node_pages_info)); ++ if (params->host_pages_info == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc host_pages_info fail\n"); ++ goto destroy_factory; ++ } ++ + return 0; + ++destroy_factory: ++ destroy_factory(¶ms->factory); ++ + destroy_stat_mtx: + pthread_mutex_destroy(¶ms->stat_mtx); + +@@ -1642,7 +1685,6 @@ static void *cslide_main(void *arg) + } + + next: +- cslide_stat(eng_params); + sleep(eng_params->interval); + cslide_clean_params(eng_params); + } +@@ -1745,24 +1787,11 @@ static struct cslide_cmd_item g_task_cmd_items[] = { + static int show_host_pages(void *params, int fd) + { + struct cslide_eng_params *eng_params = (struct cslide_eng_params *)params; +- struct cslide_pid_params *iter = NULL; + char *time_str = NULL; + int node_num = eng_params->mem.node_num; + int n; + uint32_t total; +- struct node_pages_info *info = calloc(node_num, sizeof(struct node_pages_info)); +- +- if (info == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "alloc memory for node_page_info fail\n"); +- return -1; +- } +- +- factory_foreach_working_pid_params(iter, &eng_params->factory) { +- for (n = 0; n < node_num; n++) { +- info[n].hot += iter->node_pages_info[n].hot; +- info[n].cold += iter->node_pages_info[n].cold; +- } +- } ++ struct node_pages_info *info = eng_params->host_pages_info; + + time_str = get_time_stamp(&eng_params->stat_time); + if (time_str != NULL) { +@@ -1776,7 +1805,6 @@ static int show_host_pages(void *params, int fd) + n, total, info[n].hot + info[n].cold, info[n].hot, info[n].cold); + } + +- free(info); + return 0; + } + +-- +2.27.0 + diff --git a/0015-limit-mig_quota-hot_reserve-to-0-INT_MAX.patch b/0015-limit-mig_quota-hot_reserve-to-0-INT_MAX.patch new file mode 100644 index 0000000..466c1b9 --- /dev/null +++ b/0015-limit-mig_quota-hot_reserve-to-0-INT_MAX.patch @@ -0,0 +1,41 @@ +From fd0ac585faf4f7893c728cb7898c265767f51082 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 29 Apr 2021 13:54:39 +0800 +Subject: [PATCH 15/50] limit mig_quota, hot_reserve to [0, INT_MAX] + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 7c30508..18a78d3 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -2048,6 +2048,11 @@ static int fill_hot_reserve(void *obj, void *val) + struct cslide_eng_params *params = (struct cslide_eng_params *)obj; + int hot_reserve = parse_to_int(val); + ++ if (hot_reserve < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "config hot reserve %d not valid\n", hot_reserve); ++ return -1; ++ } ++ + params->hot_reserve = hot_reserve; + return 0; + } +@@ -2057,6 +2062,11 @@ static int fill_mig_quota(void *obj, void *val) + struct cslide_eng_params *params = (struct cslide_eng_params *)obj; + int mig_quota = parse_to_int(val); + ++ if (mig_quota < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "config mig quota %d not valid\n", mig_quota); ++ return -1; ++ } ++ + params->mig_quota = mig_quota; + return 0; + } +-- +2.27.0 + diff --git a/0016-add-some-dfx-info.patch b/0016-add-some-dfx-info.patch new file mode 100644 index 0000000..f5d5a58 --- /dev/null +++ b/0016-add-some-dfx-info.patch @@ -0,0 +1,122 @@ +From 3ffad08c0870cabea2656de19047b558c53d7fbd Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 29 Apr 2021 14:33:52 +0800 +Subject: [PATCH 16/50] add some dfx info + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 43 +++++++++++++++++++++++----------- + 1 file changed, 29 insertions(+), 14 deletions(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 18a78d3..f311a44 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -1300,7 +1300,7 @@ static int cslide_scan_vmas(struct cslide_pid_params *params) + fd = fileno(scan_fp); + if (fd == -1) { + fclose(scan_fp); +- etmemd_log(ETMEMD_LOG_ERR, "fileno file fail for %s\n", IDLE_SCAN_FILE); ++ etmemd_log(ETMEMD_LOG_ERR, "task %u fileno file fail for %s\n", params->pid, IDLE_SCAN_FILE); + return -1; + } + for (i = 0; i < vmas->vma_cnt; i++) { +@@ -1309,7 +1309,7 @@ static int cslide_scan_vmas(struct cslide_pid_params *params) + walk_address.walk_start = vma->start; + walk_address.walk_end = vma->end; + if (walk_vmas(fd, &walk_address, &vma_pf->page_refs, NULL) == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "scan vma start %llu end %llu fail\n", vma->start, vma->end); ++ etmemd_log(ETMEMD_LOG_ERR, "task %u scan vma start %llu end %llu fail\n", params->pid, vma->start, vma->end); + fclose(scan_fp); + return -1; + } +@@ -1349,14 +1349,16 @@ static int cslide_do_scan(struct cslide_eng_params *eng_params) + return 0; + } + ++// error return -1; success return moved pages number + static int do_migrate_pages(unsigned int pid, struct page_refs *page_refs, int node) + { + int batch_size = BATCHSIZE; +- int ret = -1; ++ int ret; + void **pages = NULL; + int *nodes = NULL; + int *status = NULL; + int actual_num = 0; ++ int moved = -1; + + if (page_refs == NULL) { + return 0; +@@ -1379,6 +1381,8 @@ static int do_migrate_pages(unsigned int pid, struct page_refs *page_refs, int n + etmemd_log(ETMEMD_LOG_ERR, "malloc pages fail\n"); + goto free_status; + } ++ ++ moved = 0; + while (page_refs != NULL) { + pages[actual_num] = (void *)page_refs->addr; + nodes[actual_num] = node; +@@ -1386,11 +1390,13 @@ static int do_migrate_pages(unsigned int pid, struct page_refs *page_refs, int n + page_refs = page_refs->next; + if (actual_num == batch_size || page_refs == NULL) { + ret = move_pages(pid, actual_num, pages, nodes, status, MPOL_MF_MOVE_ALL); +- actual_num = 0; + if (ret != 0) { + etmemd_log(ETMEMD_LOG_ERR, "task %d move_pages fail with %d errno %d\n", pid, ret, errno); ++ moved = -1; + break; + } ++ moved += actual_num; ++ actual_num = 0; + } + } + +@@ -1402,25 +1408,34 @@ free_status: + free_nodes: + free(nodes); + nodes = NULL; +- return ret; ++ return moved; + } + + static int migrate_single_task(unsigned int pid, const struct memory_grade *memory_grade, int hot_node, int cold_node) + { +- int ret = -1; ++ int moved; + +- if (do_migrate_pages(pid, memory_grade->cold_pages, cold_node) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "migrate cold pages fail\n"); +- return ret; ++ moved = do_migrate_pages(pid, memory_grade->cold_pages, cold_node); ++ if (moved == -1) { ++ etmemd_log(ETMEMD_LOG_ERR, "task %u migrate cold pages fail\n", pid); ++ return -1; ++ } ++ if (moved != 0) { ++ etmemd_log(ETMEMD_LOG_INFO, "task %u move pages %lld KB from node %d to node %d\n", ++ pid, HUGE_2M_TO_KB((unsigned int)moved), hot_node, cold_node); + } + +- if (do_migrate_pages(pid, memory_grade->hot_pages, hot_node) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "migrate hot pages fail\n"); +- return ret; ++ moved = do_migrate_pages(pid, memory_grade->hot_pages, hot_node); ++ if (moved == -1) { ++ etmemd_log(ETMEMD_LOG_ERR, "task %u migrate hot pages fail\n", pid); ++ return -1; ++ } ++ if (moved != 0) { ++ etmemd_log(ETMEMD_LOG_INFO, "task %u move pages %lld KB from node %d to %d\n", ++ pid, HUGE_2M_TO_KB((unsigned int)moved), cold_node, hot_node); + } + +- ret = 0; +- return ret; ++ return 0; + } + + static int cslide_do_migrate(struct cslide_eng_params *eng_params) +-- +2.27.0 + diff --git a/0017-do-not-stop-the-process-when-failed-to-delete-any-obj.patch b/0017-do-not-stop-the-process-when-failed-to-delete-any-obj.patch new file mode 100644 index 0000000..121ec8e --- /dev/null +++ b/0017-do-not-stop-the-process-when-failed-to-delete-any-obj.patch @@ -0,0 +1,73 @@ +From 598735e135a95bf646da66708bab80a673f1344f Mon Sep 17 00:00:00 2001 +From: louhongxiang +Date: Thu, 29 Apr 2021 15:28:22 +0800 +Subject: [PATCH 17/50] do not stop the process when failed to delete any obj, + continue to delte the next one in config file specified. + +--- + src/etmemd_src/etmemd_rpc.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index a8653e2..8360f5a 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -94,11 +94,12 @@ struct obj_cmd_item { + enum opt_result (*func)(GKeyFile *config); + }; + +-static enum opt_result do_obj_cmd(GKeyFile *config, struct obj_cmd_item *items, unsigned n) ++static enum opt_result do_obj_cmd(GKeyFile *config, struct obj_cmd_item *items, unsigned n,bool add_opt) + { + unsigned i; + bool parsed = false; + enum opt_result ret; ++ enum opt_result err_ret = OPT_SUCCESS; + + for (i = 0; i < n; i++) { + if (g_key_file_has_group(config, items[i].name) == FALSE) { +@@ -108,7 +109,10 @@ static enum opt_result do_obj_cmd(GKeyFile *config, struct obj_cmd_item *items, + ret = items[i].func(config); + if (ret != 0) { + etmemd_log(ETMEMD_LOG_ERR, "parse group %s fail\n", items[i].name); +- return ret; ++ if (add_opt) { ++ return ret; ++ } ++ err_ret = ret; + } + parsed = true; + } +@@ -118,6 +122,11 @@ static enum opt_result do_obj_cmd(GKeyFile *config, struct obj_cmd_item *items, + return OPT_INVAL; + } + ++ if (err_ret != OPT_SUCCESS) { ++ etmemd_log(ETMEMD_LOG_ERR, "error occurs in %s operation\n", add_opt ? "add" : "del"); ++ return err_ret; ++ } ++ + return OPT_SUCCESS; + } + +@@ -129,7 +138,7 @@ struct obj_cmd_item g_obj_add_items[] = { + + static enum opt_result do_obj_add(GKeyFile *config) + { +- return do_obj_cmd(config, g_obj_add_items, ARRAY_SIZE(g_obj_add_items)); ++ return do_obj_cmd(config, g_obj_add_items, ARRAY_SIZE(g_obj_add_items), true); + } + + static struct obj_cmd_item obj_remove_items[] = { +@@ -140,7 +149,7 @@ static struct obj_cmd_item obj_remove_items[] = { + + static enum opt_result do_obj_remove(GKeyFile *config) + { +- return do_obj_cmd(config, obj_remove_items, ARRAY_SIZE(obj_remove_items)); ++ return do_obj_cmd(config, obj_remove_items, ARRAY_SIZE(obj_remove_items), false); + } + + static enum opt_result handle_obj_cmd(char *file_name, enum cmd_type type) +-- +2.27.0 + diff --git a/0018-fix-code-check-warnning.patch b/0018-fix-code-check-warnning.patch new file mode 100644 index 0000000..1f96fe1 --- /dev/null +++ b/0018-fix-code-check-warnning.patch @@ -0,0 +1,41 @@ +From 6d9c2711f4fee6ec29ffcbf6bda5991e37cd12bb Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 29 Apr 2021 16:17:55 +0800 +Subject: [PATCH 18/50] fix code check warnning remove redundant space + +Signed-off-by: Kemeng Shi +--- + src/etmem_src/etmem_project.c | 2 +- + src/etmemd_src/etmemd_cslide.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/etmem_src/etmem_project.c b/src/etmem_src/etmem_project.c +index bb53df3..5892789 100644 +--- a/src/etmem_src/etmem_project.c ++++ b/src/etmem_src/etmem_project.c +@@ -107,7 +107,7 @@ static int project_check_params(const struct mem_proj *proj) + printf("socket name to connect must all be given, please check.\n"); + return -EINVAL; + } +- ++ + if (proj->cmd == ETMEM_CMD_SHOW) { + return 0; + } +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index f311a44..5914ca1 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -1309,7 +1309,8 @@ static int cslide_scan_vmas(struct cslide_pid_params *params) + walk_address.walk_start = vma->start; + walk_address.walk_end = vma->end; + if (walk_vmas(fd, &walk_address, &vma_pf->page_refs, NULL) == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "task %u scan vma start %llu end %llu fail\n", params->pid, vma->start, vma->end); ++ etmemd_log(ETMEMD_LOG_ERR, "task %u scan vma start %llu end %llu fail\n", ++ params->pid, vma->start, vma->end); + fclose(scan_fp); + return -1; + } +-- +2.27.0 + diff --git a/0019-accept-review-advise.patch b/0019-accept-review-advise.patch new file mode 100644 index 0000000..903ccc0 --- /dev/null +++ b/0019-accept-review-advise.patch @@ -0,0 +1,78 @@ +From a8bea6d5ffcfe66020832eb57d233f4962aa3672 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 29 Apr 2021 18:58:52 +0800 +Subject: [PATCH 19/50] accept review advise + +Signed-off-by: Kemeng Shi +--- + src/etmem_src/etmem_engine.c | 7 ++++--- + src/etmemd_src/etmemd_cslide.c | 4 ++-- + src/etmemd_src/etmemd_rpc.c | 3 +++ + 3 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/src/etmem_src/etmem_engine.c b/src/etmem_src/etmem_engine.c +index e744aaa..bafcfe6 100644 +--- a/src/etmem_src/etmem_engine.c ++++ b/src/etmem_src/etmem_engine.c +@@ -24,8 +24,8 @@ + static void engine_help(void) + { + printf("\nUsage:\n" +- " memig engine eng_cmd [options]\n" +- " memig engine help\n" ++ " etmem engine eng_cmd [options]\n" ++ " etmem engine help\n" + "\nOptions:\n" + " -n|--proj_name project engine belongs to\n" + " -s|--socket socket name to connect\n" +@@ -35,7 +35,8 @@ static void engine_help(void) + " 1. project name must be given.\n" + " 2. socket name must be given.\n" + " 3. engine name must be given.\n" +- " 4. engine cmd must be given.\n"); ++ " 4. engine cmd must be given.\n" ++ " 5. eng_cmd is supported by engine own.\n"); + } + + static int engine_parse_cmd(struct etmem_conf *conf, struct mem_proj *proj) +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 5914ca1..9c65464 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -1422,7 +1422,7 @@ static int migrate_single_task(unsigned int pid, const struct memory_grade *memo + return -1; + } + if (moved != 0) { +- etmemd_log(ETMEMD_LOG_INFO, "task %u move pages %lld KB from node %d to node %d\n", ++ etmemd_log(ETMEMD_LOG_INFO, "task %u move pages %llu KB from node %d to node %d\n", + pid, HUGE_2M_TO_KB((unsigned int)moved), hot_node, cold_node); + } + +@@ -1432,7 +1432,7 @@ static int migrate_single_task(unsigned int pid, const struct memory_grade *memo + return -1; + } + if (moved != 0) { +- etmemd_log(ETMEMD_LOG_INFO, "task %u move pages %lld KB from node %d to %d\n", ++ etmemd_log(ETMEMD_LOG_INFO, "task %u move pages %llu KB from node %d to %d\n", + pid, HUGE_2M_TO_KB((unsigned int)moved), cold_node, hot_node); + } + +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index 09497b3..fe0b975 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -212,8 +212,11 @@ static int check_cmd_permission(int sock_fd, int cmd) + { + switch (cmd) { + case OBJ_ADD: ++ /* fallthrough */ + case OBJ_DEL: ++ /* fallthrough */ + case MIG_STOP: ++ /* fallthrough */ + case MIG_START: + return check_socket_permission(sock_fd); + default: +-- +2.27.0 + diff --git a/0020-revert-socket-permission-check.patch b/0020-revert-socket-permission-check.patch new file mode 100644 index 0000000..fb1381d --- /dev/null +++ b/0020-revert-socket-permission-check.patch @@ -0,0 +1,133 @@ +From 40e9ddb6fafbcbeda9db7d848967d0b4f38b1514 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 6 May 2021 09:22:05 +0800 +Subject: [PATCH 20/50] revert socket permission check + +Signed-off-by: Kemeng Shi +--- + inc/etmemd_inc/etmemd_rpc.h | 2 - + src/etmemd_src/etmemd_rpc.c | 78 +++++++++++++++---------------------- + 2 files changed, 31 insertions(+), 49 deletions(-) + +diff --git a/inc/etmemd_inc/etmemd_rpc.h b/inc/etmemd_inc/etmemd_rpc.h +index 4f61390..146cec3 100644 +--- a/inc/etmemd_inc/etmemd_rpc.h ++++ b/inc/etmemd_inc/etmemd_rpc.h +@@ -55,7 +55,5 @@ int etmemd_parse_sock_name(const char *sock_name); + int etmemd_rpc_server(void); + bool etmemd_sock_name_set(void); + void etmemd_sock_name_free(void); +-// some engine cmd need to check socket permission +-int check_socket_permission(int sock_fd); + + #endif +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index fe0b975..d7bf8d7 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -181,57 +181,10 @@ free_file: + return ret; + } + +-int check_socket_permission(int sock_fd) { +- struct ucred cred; +- socklen_t len; +- ssize_t rc; +- +- len = sizeof(struct ucred); +- +- rc = getsockopt(sock_fd, +- SOL_SOCKET, +- SO_PEERCRED, +- &cred, +- &len); +- if (rc < 0) { +- etmemd_log(ETMEMD_LOG_ERR, "getsockopt failed, err(%s)\n", +- strerror(errno)); +- return -1; +- } +- +- if (cred.uid != 0 || cred.gid != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "client socket connect failed, permition denied\n"); +- return -1; +- } +- +- return 0; +-} +- +-// ENG_CMD cmd permission checked inside engine +-static int check_cmd_permission(int sock_fd, int cmd) +-{ +- switch (cmd) { +- case OBJ_ADD: +- /* fallthrough */ +- case OBJ_DEL: +- /* fallthrough */ +- case MIG_STOP: +- /* fallthrough */ +- case MIG_START: +- return check_socket_permission(sock_fd); +- default: +- return 0; +- } +-} +- + static enum opt_result etmemd_switch_cmd(const struct server_rpc_params svr_param) + { + enum opt_result ret = OPT_INVAL; + +- if (check_cmd_permission(svr_param.sock_fd, svr_param.cmd) != 0) { +- return OPT_INVAL; +- } +- + switch (svr_param.cmd) { + case OBJ_ADD: + case OBJ_DEL: +@@ -596,6 +549,32 @@ static void etmemd_rpc_handle(int sock_fd) + return; + } + ++int check_socket_permission(int sock_fd) { ++ struct ucred cred; ++ socklen_t len; ++ ssize_t rc; ++ ++ len = sizeof(struct ucred); ++ ++ rc = getsockopt(sock_fd, ++ SOL_SOCKET, ++ SO_PEERCRED, ++ &cred, ++ &len); ++ if (rc < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "getsockopt failed, err(%s)\n", ++ strerror(errno)); ++ return -1; ++ } ++ ++ if (cred.uid != 0 || cred.gid != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "client socket connect failed, permition denied\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ + static int etmemd_rpc_accept(int sock_fd) + { + char *recv_buf = NULL; +@@ -618,6 +597,11 @@ static int etmemd_rpc_accept(int sock_fd) + return 0; + } + ++ rc = check_socket_permission(accp_fd); ++ if (rc != 0) { ++ goto RPC_EXIT; ++ } ++ + rc = recv(accp_fd, recv_buf, RPC_BUFF_LEN_MAX, 0); + if (rc <= 0) { + etmemd_log(ETMEMD_LOG_WARN, "socket recive from client fail, error(%s)\n", +-- +2.27.0 + diff --git a/0021-add-thirdpart-engine.patch b/0021-add-thirdpart-engine.patch new file mode 100644 index 0000000..c3260c0 --- /dev/null +++ b/0021-add-thirdpart-engine.patch @@ -0,0 +1,549 @@ +From c009890697542083329ee384ac0e72f3c976f331 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 6 May 2021 10:32:50 +0800 +Subject: [PATCH 21/50] add thirdpart engine + +Signed-off-by: Kemeng Shi +--- + CMakeLists.txt | 1 + + inc/etmemd_inc/etmemd_cslide.h | 2 +- + inc/etmemd_inc/etmemd_engine.h | 1 + + inc/etmemd_inc/etmemd_slide.h | 2 +- + inc/etmemd_inc/etmemd_thirdparty.h | 24 ++++ + src/etmemd_src/etmemd_cslide.c | 2 +- + src/etmemd_src/etmemd_engine.c | 51 +++++++-- + src/etmemd_src/etmemd_project.c | 75 ++++++------ + src/etmemd_src/etmemd_rpc.c | 2 +- + src/etmemd_src/etmemd_slide.c | 2 +- + src/etmemd_src/etmemd_thirdparty.c | 178 +++++++++++++++++++++++++++++ + 11 files changed, 291 insertions(+), 49 deletions(-) + create mode 100644 inc/etmemd_inc/etmemd_thirdparty.h + create mode 100644 src/etmemd_src/etmemd_thirdparty.c + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index fa64b89..9ce4724 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -33,6 +33,7 @@ set(ETMEMD_SRC + ${ETMEMD_SRC_DIR}/etmemd_engine.c + ${ETMEMD_SRC_DIR}/etmemd_slide.c + ${ETMEMD_SRC_DIR}/etmemd_cslide.c ++ ${ETMEMD_SRC_DIR}/etmemd_thirdparty.c + ${ETMEMD_SRC_DIR}/etmemd_task.c + ${ETMEMD_SRC_DIR}/etmemd_scan.c + ${ETMEMD_SRC_DIR}/etmemd_threadpool.c +diff --git a/inc/etmemd_inc/etmemd_cslide.h b/inc/etmemd_inc/etmemd_cslide.h +index 2405f2d..9b03f6f 100644 +--- a/inc/etmemd_inc/etmemd_cslide.h ++++ b/inc/etmemd_inc/etmemd_cslide.h +@@ -18,6 +18,6 @@ + + #include "etmemd_engine.h" + +-int fill_engine_type_cslide(struct engine *eng); ++int fill_engine_type_cslide(struct engine *eng, GKeyFile *config); + + #endif +diff --git a/inc/etmemd_inc/etmemd_engine.h b/inc/etmemd_inc/etmemd_engine.h +index 77916a5..36e1760 100644 +--- a/inc/etmemd_inc/etmemd_engine.h ++++ b/inc/etmemd_inc/etmemd_engine.h +@@ -42,6 +42,7 @@ struct engine { + struct task *tasks; + uint64_t page_cnt; /* number of pages */ + struct engine *next; ++ void *handler; + }; + + struct engine_ops { +diff --git a/inc/etmemd_inc/etmemd_slide.h b/inc/etmemd_inc/etmemd_slide.h +index e76e97a..af48be7 100644 +--- a/inc/etmemd_inc/etmemd_slide.h ++++ b/inc/etmemd_inc/etmemd_slide.h +@@ -24,6 +24,6 @@ struct slide_params { + int t; /* watermark */ + }; + +-int fill_engine_type_slide(struct engine *eng); ++int fill_engine_type_slide(struct engine *eng, GKeyFile *config); + + #endif +diff --git a/inc/etmemd_inc/etmemd_thirdparty.h b/inc/etmemd_inc/etmemd_thirdparty.h +new file mode 100644 +index 0000000..1cd750c +--- /dev/null ++++ b/inc/etmemd_inc/etmemd_thirdparty.h +@@ -0,0 +1,24 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: shikemeng ++ * Create: 2021-4-30 ++ * Description: This is a header file of the function declaration for thirdparty function. ++ ******************************************************************************/ ++ ++#ifndef ETMEMD_THIRDPARTY_H ++#define ETMEMD_THIRDPARTY_H ++ ++#include "etmemd_engine.h" ++ ++int fill_engine_type_thirdparty(struct engine *eng, GKeyFile *config); ++void clear_engine_type_thirdparty(struct engine *eng); ++ ++#endif +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 9c65464..71b510f 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -2153,7 +2153,7 @@ struct engine_ops g_cslide_eng_ops = { + .eng_mgt_func = cslide_engine_do_cmd, + }; + +-int fill_engine_type_cslide(struct engine *eng) ++int fill_engine_type_cslide(struct engine *eng, GKeyFile *config) + { + eng->ops = &g_cslide_eng_ops; + eng->engine_type = CSLIDE_ENGINE; +diff --git a/src/etmemd_src/etmemd_engine.c b/src/etmemd_src/etmemd_engine.c +index 98a7430..c745e15 100644 +--- a/src/etmemd_src/etmemd_engine.c ++++ b/src/etmemd_src/etmemd_engine.c +@@ -18,27 +18,51 @@ + #include "etmemd_engine.h" + #include "etmemd_slide.h" + #include "etmemd_cslide.h" ++#include "etmemd_thirdparty.h" + #include "etmemd_log.h" + #include "etmemd_common.h" + #include "etmemd_file.h" + +-struct engine_item { ++struct engine_add_item { + char *name; +- int (*fill_eng_func)(struct engine *eng); ++ int (*fill_eng_func)(struct engine *eng, GKeyFile *config); + }; + +-static struct engine_item g_engine_items[] = { ++struct engine_remove_item { ++ int type; ++ void (*clear_eng_func)(struct engine *eng); ++}; ++ ++static struct engine_add_item g_engine_add_items[] = { + {"slide", fill_engine_type_slide}, + {"cslide", fill_engine_type_cslide}, ++ {"thirdparty", fill_engine_type_thirdparty}, ++}; ++ ++static struct engine_add_item *find_engine_add_item(const char *name) ++{ ++ unsigned i; ++ ++ for (i = 0; i < ARRAY_SIZE(g_engine_add_items); i++) { ++ if (strcmp(name, g_engine_add_items[i].name) == 0) { ++ return &g_engine_add_items[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static struct engine_remove_item g_engine_remove_items[] = { ++ {THIRDPARTY_ENGINE, clear_engine_type_thirdparty}, + }; + +-static struct engine_item *find_engine_item(const char *name) ++static struct engine_remove_item *find_engine_remove_item(int type) + { + unsigned i; + +- for (i = 0; i < ARRAY_SIZE(g_engine_items); i++) { +- if (strcmp(name, g_engine_items[i].name) == 0) { +- return &g_engine_items[i]; ++ for (i = 0; i < ARRAY_SIZE(g_engine_remove_items); i++) { ++ if (g_engine_remove_items[i].type == type) { ++ return &g_engine_remove_items[i]; + } + } + +@@ -48,7 +72,7 @@ static struct engine_item *find_engine_item(const char *name) + struct engine *etmemd_engine_add(GKeyFile *config) + { + struct engine *eng = NULL; +- struct engine_item *item = NULL; ++ struct engine_add_item *item = NULL; + char *name = NULL; + + if (g_key_file_has_key(config, ENG_GROUP, "name", NULL) == FALSE) { +@@ -62,7 +86,7 @@ struct engine *etmemd_engine_add(GKeyFile *config) + return NULL; + } + +- item = find_engine_item(name); ++ item = find_engine_add_item(name); + if (item == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "engine %s not support\n", name); + goto free_name; +@@ -74,7 +98,7 @@ struct engine *etmemd_engine_add(GKeyFile *config) + goto free_name; + } + +- if (item->fill_eng_func(eng) != 0) { ++ if (item->fill_eng_func(eng, config) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "fill engine %s fail\n", name); + free(eng); + eng = NULL; +@@ -94,5 +118,12 @@ free_name: + + void etmemd_engine_remove(struct engine *eng) + { ++ struct engine_remove_item *item = NULL; ++ ++ item = find_engine_remove_item(eng->engine_type); ++ if (item != NULL) { ++ item->clear_eng_func(eng); ++ } ++ + free(eng); + } +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index b3158d8..885c86e 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -76,7 +76,7 @@ static struct task *get_task_by_name(struct project *proj, struct engine *eng, c + return NULL; + } + +-static char *get_obj_key(char *obj_name, const char *group_name) ++static const char *get_obj_key(const char *obj_name, const char *group_name) + { + if (strcmp(obj_name, group_name) == 0) { + return "name"; +@@ -85,46 +85,61 @@ static char *get_obj_key(char *obj_name, const char *group_name) + } + } + +-static enum opt_result project_of_group(GKeyFile *config, const char *group_name, struct project **proj) ++static enum opt_result get_name_by_key(GKeyFile *config, const char *group_name, const char *key, char **name) + { +- *proj = NULL; +- char *proj_name = NULL; +- char *key = NULL; +- +- key = get_obj_key(PROJ_GROUP, group_name); + if (g_key_file_has_key(config, group_name, key, NULL) == FALSE) { +- etmemd_log(ETMEMD_LOG_ERR, "project name is not set for %s\n", group_name); ++ etmemd_log(ETMEMD_LOG_ERR, "key %s is not set in group %s\n", key, group_name); + return OPT_INVAL; + } + +- proj_name = g_key_file_get_string(config, group_name, key, NULL); +- if (proj_name == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "get project name from %s fail\n", group_name); ++ *name = g_key_file_get_string(config, group_name, key, NULL); ++ if (*name == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get value of key %s from group %s fail\n", key, group_name); + return OPT_INTER_ERR; + } + +- *proj = get_proj_by_name(proj_name); ++ return OPT_SUCCESS; ++} ++ ++static enum opt_result get_obj_name(GKeyFile *config, const char *group_name, const char *obj, char **name) ++{ ++ const char *key = get_obj_key(obj, group_name); ++ ++ return get_name_by_key(config, group_name, key, name); ++} + ++static enum opt_result project_of_group(GKeyFile *config, const char *group_name, struct project **proj) ++{ ++ char *proj_name = NULL; ++ enum opt_result ret; ++ ++ ret = get_obj_name(config, group_name, PROJ_GROUP, &proj_name); ++ if (ret != OPT_SUCCESS) { ++ return ret; ++ } ++ ++ *proj = get_proj_by_name(proj_name); + free(proj_name); + return OPT_SUCCESS; + } + + static enum opt_result engine_of_group(GKeyFile *config, char *group_name, struct project *proj, struct engine **eng) + { +- char *key = NULL; + char *eng_name = NULL; +- *eng = NULL; ++ enum opt_result ret; + +- key = get_obj_key(ENG_GROUP, group_name); +- if (g_key_file_has_key(config, group_name, key, NULL) == FALSE) { +- etmemd_log(ETMEMD_LOG_ERR, "engine is not set for %s\n", group_name); +- return OPT_INVAL; ++ ret = get_obj_name(config, group_name, ENG_GROUP, &eng_name); ++ if (ret != OPT_SUCCESS) { ++ return ret; + } + +- eng_name = g_key_file_get_string(config, group_name, key, NULL); +- if (eng_name == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "get engine name from %s fail\n", group_name); +- return OPT_INTER_ERR; ++ // real engine name is set with "eng_name" for thirdparty engine ++ if (strcmp(eng_name, "thirdparty") == 0 && strcmp(group_name, ENG_GROUP) == 0) { ++ free(eng_name); ++ ret = get_name_by_key(config, ENG_GROUP, "eng_name", &eng_name); ++ if (ret != OPT_SUCCESS) { ++ return ret; ++ } + } + + *eng = get_eng_by_name(proj, eng_name); +@@ -136,19 +151,11 @@ static enum opt_result task_of_group(GKeyFile *config, char *group_name, + struct project *proj, struct engine *eng, struct task **tk) + { + char *task_name = NULL; +- char *key = NULL; +- *tk = NULL; +- +- key = get_obj_key(TASK_GROUP, group_name); +- if (g_key_file_has_key(config, group_name, key, NULL) == FALSE) { +- etmemd_log(ETMEMD_LOG_ERR, "task name is not set for %s\n", group_name); +- return OPT_INVAL; +- } ++ enum opt_result ret; + +- task_name = g_key_file_get_string(config, group_name, key, NULL); +- if (task_name == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "get task name from %s fail\n", group_name); +- return OPT_INTER_ERR; ++ ret = get_obj_name(config, group_name, TASK_GROUP, &task_name); ++ if (ret != OPT_SUCCESS) { ++ return ret; + } + + *tk = get_task_by_name(proj, eng, task_name); +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index d7bf8d7..49c292d 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -549,7 +549,7 @@ static void etmemd_rpc_handle(int sock_fd) + return; + } + +-int check_socket_permission(int sock_fd) { ++static int check_socket_permission(int sock_fd) { + struct ucred cred; + socklen_t len; + ssize_t rc; +diff --git a/src/etmemd_src/etmemd_slide.c b/src/etmemd_src/etmemd_slide.c +index f7609f4..64d0533 100644 +--- a/src/etmemd_src/etmemd_slide.c ++++ b/src/etmemd_src/etmemd_slide.c +@@ -211,7 +211,7 @@ struct engine_ops g_slide_eng_ops = { + .eng_mgt_func = NULL, + }; + +-int fill_engine_type_slide(struct engine *eng) ++int fill_engine_type_slide(struct engine *eng, GKeyFile *config) + { + eng->ops = &g_slide_eng_ops; + eng->engine_type = SLIDE_ENGINE; +diff --git a/src/etmemd_src/etmemd_thirdparty.c b/src/etmemd_src/etmemd_thirdparty.c +new file mode 100644 +index 0000000..1a05512 +--- /dev/null ++++ b/src/etmemd_src/etmemd_thirdparty.c +@@ -0,0 +1,178 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: shikemeng ++ * Create: 2021-04-30 ++ * Description: Memigd thirdparty API. ++ ******************************************************************************/ ++ ++#include ++#include ++ ++#include "etmemd_engine.h" ++#include "etmemd_file.h" ++#include "etmemd_log.h" ++#include "etmemd_common.h" ++#include "etmemd_thirdparty.h" ++#include "securec.h" ++ ++struct thirdparty_params { ++ char *eng_name; ++ char *libname; ++ char *ops_name; ++}; ++ ++static int fill_eng_name(void *obj, void *val) ++{ ++ char *eng_name = (char *)val; ++ struct thirdparty_params *params = (struct thirdparty_params *)obj; ++ ++ params->eng_name = eng_name; ++ return 0; ++} ++ ++static int fill_libname(void *obj, void *val) ++{ ++ char *libname = (char *)val; ++ struct thirdparty_params *params = (struct thirdparty_params *)obj; ++ ++ params->libname = libname; ++ return 0; ++} ++ ++static int fill_ops_name(void *obj, void *val) ++{ ++ char *ops_name = (char *)val; ++ struct thirdparty_params *params = (struct thirdparty_params *)obj; ++ ++ params->ops_name = ops_name; ++ return 0; ++} ++ ++static struct config_item g_thirdparty_configs[] = { ++ {"eng_name", STR_VAL, fill_eng_name, false}, ++ {"libname", STR_VAL, fill_libname, false}, ++ {"ops_name", STR_VAL, fill_ops_name, false}, ++}; ++ ++static void clear_thirdparty_params(struct thirdparty_params *params) ++{ ++ if (params->eng_name != NULL) { ++ free(params->eng_name); ++ params->eng_name = NULL; ++ } ++ if (params->libname != NULL) { ++ free(params->libname); ++ params->libname = NULL; ++ } ++ if (params->ops_name != NULL) { ++ free(params->ops_name); ++ params->ops_name = NULL; ++ } ++} ++ ++static int set_engine_ops(struct engine *eng, struct thirdparty_params *params) ++{ ++ void *handler = NULL; ++ struct engine_ops *ops = NULL; ++ char *err = NULL; ++ ++ handler = dlopen(params->libname, RTLD_NOW | RTLD_LOCAL); ++ if (handler == NULL) { ++ err = dlerror(); ++ etmemd_log(ETMEMD_LOG_ERR, "load library %s fail with error: %s\n", params->libname, err); ++ return -1; ++ } ++ ++ /* Clear error */ ++ dlerror(); ++ ops = dlsym(handler, params->ops_name); ++ err = dlerror(); ++ if (err != NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "load engine_ops symbol %s fail with error: %s\n", params->ops_name, err); ++ dlclose(handler); ++ return -1; ++ } ++ ++ eng->ops = ops; ++ eng->handler = handler; ++ return 0; ++} ++ ++static void clear_engine_ops(struct engine *eng) ++{ ++ dlclose(eng->handler); ++ eng->handler = NULL; ++ eng->ops = NULL; ++} ++ ++static void set_engine_name(struct engine *eng, struct thirdparty_params *params) ++{ ++ eng->name = params->eng_name; ++ /* avoid that eng_name will be freed in clear_thirdparty_params */ ++ params->eng_name = NULL; ++} ++ ++static void clear_engine_name(struct engine *eng) ++{ ++ free(eng->name); ++ eng->name = NULL; ++} ++ ++static int set_engine(struct engine *eng, struct thirdparty_params *params) ++{ ++ if (set_engine_ops(eng, params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "set engine ops fail\n"); ++ return -1; ++ } ++ set_engine_name(eng, params); ++ eng->engine_type = THIRDPARTY_ENGINE; ++ ++ return 0; ++} ++ ++static void clear_engine(struct engine *eng) ++{ ++ clear_engine_name(eng); ++ clear_engine_ops(eng); ++} ++ ++int fill_engine_type_thirdparty(struct engine *eng, GKeyFile *config) ++{ ++ struct thirdparty_params params; ++ int ret = -1; ++ ++ if (memset_s(¶ms, sizeof(struct thirdparty_params), 0, sizeof(struct thirdparty_params)) != EOK) { ++ etmemd_log(ETMEMD_LOG_ERR, "memset_s for thirdparty_params fail\n"); ++ return -1; ++ } ++ ++ if (parse_file_config(config, ENG_GROUP, g_thirdparty_configs, ++ ARRAY_SIZE(g_thirdparty_configs), ¶ms) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "parse thirdparty_params fail\n"); ++ goto clear_params; ++ } ++ ++ if (set_engine(eng, ¶ms) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "set engine fail\n"); ++ goto clear_params; ++ } ++ ++ ret = 0; ++ ++clear_params: ++ clear_thirdparty_params(¶ms); ++ return ret; ++} ++ ++void clear_engine_type_thirdparty(struct engine *eng) ++{ ++ clear_engine(eng); ++} +-- +2.27.0 + diff --git a/0022-export-symbols-for-user-defined-thirdparty-engine.patch b/0022-export-symbols-for-user-defined-thirdparty-engine.patch new file mode 100644 index 0000000..a9e8122 --- /dev/null +++ b/0022-export-symbols-for-user-defined-thirdparty-engine.patch @@ -0,0 +1,321 @@ +From 2191a3f804026b73a82d146dfe834be0e515fc0e Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 6 May 2021 14:20:29 +0800 +Subject: [PATCH 22/50] export symbols for user defined thirdparty engine + +Signed-off-by: Kemeng Shi +--- + inc/etmemd_inc/etmem_thirdparty.h | 23 +++++++++++++ + inc/etmemd_inc/etmemd_engine.h | 30 +---------------- + inc/etmemd_inc/etmemd_engine_exp.h | 52 +++++++++++++++++++++++++++++ + inc/etmemd_inc/etmemd_project.h | 13 +------- + inc/etmemd_inc/etmemd_project_exp.h | 33 ++++++++++++++++++ + inc/etmemd_inc/etmemd_task.h | 19 +---------- + inc/etmemd_inc/etmemd_task_exp.h | 43 ++++++++++++++++++++++++ + 7 files changed, 154 insertions(+), 59 deletions(-) + create mode 100644 inc/etmemd_inc/etmem_thirdparty.h + create mode 100644 inc/etmemd_inc/etmemd_engine_exp.h + create mode 100644 inc/etmemd_inc/etmemd_project_exp.h + create mode 100644 inc/etmemd_inc/etmemd_task_exp.h + +diff --git a/inc/etmemd_inc/etmem_thirdparty.h b/inc/etmemd_inc/etmem_thirdparty.h +new file mode 100644 +index 0000000..0e128ce +--- /dev/null ++++ b/inc/etmemd_inc/etmem_thirdparty.h +@@ -0,0 +1,23 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: shikemeng ++ * Create: 2021-4-30 ++ * Description: This is a header file of the function declaration for user defined thirdparty engine. ++ ******************************************************************************/ ++ ++#ifndef ETMEM_THIRDPARTY_H ++#define ETMEM_THIRDPARTY_H ++ ++#include "etmemd_project_exp.h" ++#include "etmemd_engine_exp.h" ++#include "etmemd_task_exp.h" ++ ++#endif +diff --git a/inc/etmemd_inc/etmemd_engine.h b/inc/etmemd_inc/etmemd_engine.h +index 36e1760..b513ae8 100644 +--- a/inc/etmemd_inc/etmemd_engine.h ++++ b/inc/etmemd_inc/etmemd_engine.h +@@ -16,9 +16,9 @@ + #ifndef ETMEMD_ENGINE_H + #define ETMEMD_ENGINE_H + +-#include + #include "etmemd.h" + #include "etmemd_task.h" ++#include "etmemd_engine_exp.h" + + enum eng_type { + SLIDE_ENGINE = 0, +@@ -29,34 +29,6 @@ enum eng_type { + ENGINE_TYPE_CNT, + }; + +-/* +- * engine struct +- * */ +-struct engine { +- int engine_type; /* engine type used for elimination strategy */ +- char *name; +- void *params; /* point to engine parameter struct */ +- struct project *proj; +- struct page_refs *page_ref; /* scan result */ +- struct engine_ops *ops; +- struct task *tasks; +- uint64_t page_cnt; /* number of pages */ +- struct engine *next; +- void *handler; +-}; +- +-struct engine_ops { +- int (*fill_eng_params)(GKeyFile *config, struct engine *eng); +- void (*clear_eng_params)(struct engine *eng); +- int (*fill_task_params)(GKeyFile *config, struct task *task); +- void (*clear_task_params)(struct task *tk); +- int (*start_task)(struct engine *eng, struct task *tk); +- void (*stop_task)(struct engine *eng, struct task *tk); +- int (*alloc_pid_params)(struct engine *eng, struct task_pid **tk_pid); +- void (*free_pid_params)(struct engine *eng, struct task_pid **tk_pid); +- int (*eng_mgt_func)(struct engine *eng, struct task *tk, char *cmd, int fd); +-}; +- + struct engine *etmemd_engine_add(GKeyFile *config); + void etmemd_engine_remove(struct engine *eng); + +diff --git a/inc/etmemd_inc/etmemd_engine_exp.h b/inc/etmemd_inc/etmemd_engine_exp.h +new file mode 100644 +index 0000000..2c119ec +--- /dev/null ++++ b/inc/etmemd_inc/etmemd_engine_exp.h +@@ -0,0 +1,52 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: shikemeng ++ * Create: 2021-04-30 ++ * Description: This is a header file of the export engine symbols. ++ ******************************************************************************/ ++ ++#ifndef ETMEMD_ENGINE_EXP_H ++#define ETMEMD_ENGINE_EXP_H ++ ++#include ++#include ++ ++struct task_pid; ++ ++/* ++ * engine struct ++ * */ ++struct engine { ++ int engine_type; /* engine type used for elimination strategy */ ++ char *name; ++ void *params; /* point to engine parameter struct */ ++ struct project *proj; ++ struct page_refs *page_ref; /* scan result */ ++ struct engine_ops *ops; ++ struct task *tasks; ++ uint64_t page_cnt; /* number of pages */ ++ struct engine *next; ++ void *handler; ++}; ++ ++struct engine_ops { ++ int (*fill_eng_params)(GKeyFile *config, struct engine *eng); ++ void (*clear_eng_params)(struct engine *eng); ++ int (*fill_task_params)(GKeyFile *config, struct task *task); ++ void (*clear_task_params)(struct task *tk); ++ int (*start_task)(struct engine *eng, struct task *tk); ++ void (*stop_task)(struct engine *eng, struct task *tk); ++ int (*alloc_pid_params)(struct engine *eng, struct task_pid **tk_pid); ++ void (*free_pid_params)(struct engine *eng, struct task_pid **tk_pid); ++ int (*eng_mgt_func)(struct engine *eng, struct task *tk, char *cmd, int fd); ++}; ++ ++#endif +diff --git a/inc/etmemd_inc/etmemd_project.h b/inc/etmemd_inc/etmemd_project.h +index e574a84..b44d68b 100644 +--- a/inc/etmemd_inc/etmemd_project.h ++++ b/inc/etmemd_inc/etmemd_project.h +@@ -16,26 +16,15 @@ + #ifndef ETMEMD_PROJECT_H + #define ETMEMD_PROJECT_H + +-#include + #include "etmemd_task.h" + #include "etmemd_engine.h" ++#include "etmemd_project_exp.h" + + /* set the length of project name to 32 */ + #define PROJECT_NAME_MAX_LEN 32 + #define FILE_NAME_MAX_LEN 256 + #define PROJECT_SHOW_COLM_MAX 128 + +-struct project { +- char *name; +- int interval; +- int loop; +- int sleep; +- bool start; +- struct engine *engs; +- +- SLIST_ENTRY(project) entry; +-}; +- + enum opt_result { + OPT_SUCCESS = 0, + OPT_INVAL, +diff --git a/inc/etmemd_inc/etmemd_project_exp.h b/inc/etmemd_inc/etmemd_project_exp.h +new file mode 100644 +index 0000000..bcd5108 +--- /dev/null ++++ b/inc/etmemd_inc/etmemd_project_exp.h +@@ -0,0 +1,33 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: shikemeng ++ * Create: 2021-4-30 ++ * Description: This is a header file of the export project symbols. ++ ******************************************************************************/ ++ ++#ifndef ETMEMD_PROJECT_EXP_H ++#define ETMEMD_PROJECT_EXP_H ++ ++#include ++#include ++ ++struct project { ++ char *name; ++ int interval; ++ int loop; ++ int sleep; ++ bool start; ++ struct engine *engs; ++ ++ SLIST_ENTRY(project) entry; ++}; ++ ++#endif +diff --git a/inc/etmemd_inc/etmemd_task.h b/inc/etmemd_inc/etmemd_task.h +index 3f32be5..be3ade3 100644 +--- a/inc/etmemd_inc/etmemd_task.h ++++ b/inc/etmemd_inc/etmemd_task.h +@@ -17,12 +17,11 @@ + #ifndef ETMEMD_TASK_H + #define ETMEMD_TASK_H + +-#include + #include +-#include + #include + #include "etmemd_threadpool.h" + #include "etmemd_threadtimer.h" ++#include "etmemd_task_exp.h" + + /* in some system the max length of pid may be larger than 5, so we use 10 here */ + #define PID_STR_MAX_LEN 10 +@@ -35,22 +34,6 @@ struct task_pid { + struct task_pid *next; + }; + +-struct task { +- char *type; +- char *value; +- char *name; +- uint64_t max_threads; +- +- struct task_pid *pids; +- struct engine *eng; +- void *params; +- pthread_t task_pt; +- timer_thread *timer_inst; +- thread_pool *threadpool_inst; +- +- struct task *next; +-}; +- + int etmemd_get_task_pids(struct task *tk, bool recursive); + + void etmemd_free_task_pids(struct task *tk); +diff --git a/inc/etmemd_inc/etmemd_task_exp.h b/inc/etmemd_inc/etmemd_task_exp.h +new file mode 100644 +index 0000000..b62f382 +--- /dev/null ++++ b/inc/etmemd_inc/etmemd_task_exp.h +@@ -0,0 +1,43 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: shikemeng ++ * Create: 2021-4-30 ++ * Description: This is a header file of the export task symbols. ++ ******************************************************************************/ ++ ++#ifndef ETMEMD_TASK_EXP_H ++#define ETMEMD_TASK_EXP_H ++ ++#include ++#include ++ ++struct timer_thread_t; ++typedef struct timer_thread_t timer_thread; ++struct thread_pool_t; ++typedef struct thread_pool_t thread_pool; ++ ++struct task { ++ char *type; ++ char *value; ++ char *name; ++ uint64_t max_threads; ++ ++ struct task_pid *pids; ++ struct engine *eng; ++ void *params; ++ pthread_t task_pt; ++ timer_thread *timer_inst; ++ thread_pool *threadpool_inst; ++ ++ struct task *next; ++}; ++ ++#endif +-- +2.27.0 + diff --git a/0023-accept-review-advise.patch b/0023-accept-review-advise.patch new file mode 100644 index 0000000..b5f49c0 --- /dev/null +++ b/0023-accept-review-advise.patch @@ -0,0 +1,95 @@ +From 0cf348d3f3288237855b7e05b0500c886ee98be0 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Sat, 8 May 2021 11:46:55 +0800 +Subject: [PATCH 23/50] accept review advise + +Signed-off-by: Kemeng Shi +--- + inc/etmemd_inc/etmemd_engine.h | 1 + + .../{etmem_thirdparty.h => etmemd_thirdparty_export.h} | 4 ++-- + src/etmemd_src/etmemd_project.c | 9 ++++++++- + src/etmemd_src/etmemd_thirdparty.c | 6 ++---- + 4 files changed, 13 insertions(+), 7 deletions(-) + rename inc/etmemd_inc/{etmem_thirdparty.h => etmemd_thirdparty_export.h} (93%) + +diff --git a/inc/etmemd_inc/etmemd_engine.h b/inc/etmemd_inc/etmemd_engine.h +index b513ae8..0134d21 100644 +--- a/inc/etmemd_inc/etmemd_engine.h ++++ b/inc/etmemd_inc/etmemd_engine.h +@@ -16,6 +16,7 @@ + #ifndef ETMEMD_ENGINE_H + #define ETMEMD_ENGINE_H + ++#include + #include "etmemd.h" + #include "etmemd_task.h" + #include "etmemd_engine_exp.h" +diff --git a/inc/etmemd_inc/etmem_thirdparty.h b/inc/etmemd_inc/etmemd_thirdparty_export.h +similarity index 93% +rename from inc/etmemd_inc/etmem_thirdparty.h +rename to inc/etmemd_inc/etmemd_thirdparty_export.h +index 0e128ce..9d145ce 100644 +--- a/inc/etmemd_inc/etmem_thirdparty.h ++++ b/inc/etmemd_inc/etmemd_thirdparty_export.h +@@ -13,8 +13,8 @@ + * Description: This is a header file of the function declaration for user defined thirdparty engine. + ******************************************************************************/ + +-#ifndef ETMEM_THIRDPARTY_H +-#define ETMEM_THIRDPARTY_H ++#ifndef ETMEM_THIRDPARTY_EXPORT_H ++#define ETMEM_THIRDPARTY_EXPORT_H + + #include "etmemd_project_exp.h" + #include "etmemd_engine_exp.h" +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index 885c86e..deeaf5e 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -33,6 +33,8 @@ + #define MAX_SLEEP_VALUE 1200 + #define MAX_LOOP_VALUE 120 + ++#define MAX_OBJ_NAME_LEN 64 ++ + static SLIST_HEAD(project_list, project) g_projects = SLIST_HEAD_INITIALIZER(g_projects); + + static struct project *get_proj_by_name(const char *name) +@@ -95,7 +97,12 @@ static enum opt_result get_name_by_key(GKeyFile *config, const char *group_name, + *name = g_key_file_get_string(config, group_name, key, NULL); + if (*name == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "get value of key %s from group %s fail\n", key, group_name); +- return OPT_INTER_ERR; ++ return OPT_INVAL; ++ } ++ if (strlen(*name) > MAX_OBJ_NAME_LEN) { ++ etmemd_log(ETMEMD_LOG_ERR, "name len should not be greater than %d\n", MAX_OBJ_NAME_LEN); ++ free(*name); ++ return OPT_INVAL; + } + + return OPT_SUCCESS; +diff --git a/src/etmemd_src/etmemd_thirdparty.c b/src/etmemd_src/etmemd_thirdparty.c +index 1a05512..0fd2a70 100644 +--- a/src/etmemd_src/etmemd_thirdparty.c ++++ b/src/etmemd_src/etmemd_thirdparty.c +@@ -85,14 +85,12 @@ static int set_engine_ops(struct engine *eng, struct thirdparty_params *params) + char *err = NULL; + + handler = dlopen(params->libname, RTLD_NOW | RTLD_LOCAL); +- if (handler == NULL) { +- err = dlerror(); ++ err = dlerror(); ++ if (err != NULL && handler == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "load library %s fail with error: %s\n", params->libname, err); + return -1; + } + +- /* Clear error */ +- dlerror(); + ops = dlsym(handler, params->ops_name); + err = dlerror(); + if (err != NULL) { +-- +2.27.0 + diff --git a/0024-correct-etmemd-name.patch b/0024-correct-etmemd-name.patch new file mode 100644 index 0000000..84b975d --- /dev/null +++ b/0024-correct-etmemd-name.patch @@ -0,0 +1,194 @@ +From 3ea01a06171bba33358edbec6c8b5cb4101c8e8f Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Sat, 8 May 2021 11:48:12 +0800 +Subject: [PATCH 24/50] correct etmemd name + +Signed-off-by: Kemeng Shi +--- + src/etmem_src/etmem_project.c | 2 +- + src/etmemd_src/etmemd_cslide.c | 2 +- + src/etmemd_src/etmemd_engine.c | 2 +- + src/etmemd_src/etmemd_log.c | 2 +- + src/etmemd_src/etmemd_migrate.c | 2 +- + src/etmemd_src/etmemd_pool_adapter.c | 2 +- + src/etmemd_src/etmemd_project.c | 2 +- + src/etmemd_src/etmemd_scan.c | 2 +- + src/etmemd_src/etmemd_slide.c | 2 +- + src/etmemd_src/etmemd_task.c | 2 +- + src/etmemd_src/etmemd_thirdparty.c | 2 +- + src/etmemd_src/etmemd_threadpool.c | 2 +- + src/etmemd_src/etmemd_threadtimer.c | 2 +- + 13 files changed, 13 insertions(+), 13 deletions(-) + +diff --git a/src/etmem_src/etmem_project.c b/src/etmem_src/etmem_project.c +index 5892789..ef2d8fe 100644 +--- a/src/etmem_src/etmem_project.c ++++ b/src/etmem_src/etmem_project.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memig project command API. ++ * Description: Etmem project command API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 71b510f..47a3608 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: shikemeng + * Create: 2021-4-19 +- * Description: Memigd cslide API. ++ * Description: Etmemd cslide API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_engine.c b/src/etmemd_src/etmemd_engine.c +index c745e15..f57d52b 100644 +--- a/src/etmemd_src/etmemd_engine.c ++++ b/src/etmemd_src/etmemd_engine.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd engine API. ++ * Description: Etmemd engine API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_log.c b/src/etmemd_src/etmemd_log.c +index 86c8857..fc49db8 100644 +--- a/src/etmemd_src/etmemd_log.c ++++ b/src/etmemd_src/etmemd_log.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd log API. ++ * Description: Etmemd log API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_migrate.c b/src/etmemd_src/etmemd_migrate.c +index a7aa9b8..2f29f31 100644 +--- a/src/etmemd_src/etmemd_migrate.c ++++ b/src/etmemd_src/etmemd_migrate.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd migration API. ++ * Description: Etmemd migration API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_pool_adapter.c b/src/etmemd_src/etmemd_pool_adapter.c +index b879dbc..8c0068e 100644 +--- a/src/etmemd_src/etmemd_pool_adapter.c ++++ b/src/etmemd_src/etmemd_pool_adapter.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd pool adapter API. ++ * Description: Etmemd pool adapter API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index deeaf5e..3b12296 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd project API. ++ * Description: Etmemd project API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_scan.c b/src/etmemd_src/etmemd_scan.c +index bb8dfa3..fb4dd33 100644 +--- a/src/etmemd_src/etmemd_scan.c ++++ b/src/etmemd_src/etmemd_scan.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd scan API. ++ * Description: Etmemd scan API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_slide.c b/src/etmemd_src/etmemd_slide.c +index 64d0533..96d3dcc 100644 +--- a/src/etmemd_src/etmemd_slide.c ++++ b/src/etmemd_src/etmemd_slide.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd slide API. ++ * Description: Etmemd slide API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_task.c b/src/etmemd_src/etmemd_task.c +index 61ba0df..b948c63 100644 +--- a/src/etmemd_src/etmemd_task.c ++++ b/src/etmemd_src/etmemd_task.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd task API. ++ * Description: Etmemd task API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_thirdparty.c b/src/etmemd_src/etmemd_thirdparty.c +index 0fd2a70..53d4b8e 100644 +--- a/src/etmemd_src/etmemd_thirdparty.c ++++ b/src/etmemd_src/etmemd_thirdparty.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: shikemeng + * Create: 2021-04-30 +- * Description: Memigd thirdparty API. ++ * Description: Etmemd thirdparty API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_threadpool.c b/src/etmemd_src/etmemd_threadpool.c +index 953d5a4..dac42d1 100644 +--- a/src/etmemd_src/etmemd_threadpool.c ++++ b/src/etmemd_src/etmemd_threadpool.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd threadpool API. ++ * Description: Etmemd threadpool API. + ******************************************************************************/ + + #include +diff --git a/src/etmemd_src/etmemd_threadtimer.c b/src/etmemd_src/etmemd_threadtimer.c +index 660085b..d18b3e0 100644 +--- a/src/etmemd_src/etmemd_threadtimer.c ++++ b/src/etmemd_src/etmemd_threadtimer.c +@@ -10,7 +10,7 @@ + * See the Mulan PSL v2 for more details. + * Author: louhongxiang + * Create: 2019-12-10 +- * Description: Memigd threadtimer API. ++ * Description: Etmemd threadtimer API. + ******************************************************************************/ + + #include +-- +2.27.0 + diff --git a/0025-add-support-for-systemctl-mode-to-start-etmem.patch b/0025-add-support-for-systemctl-mode-to-start-etmem.patch new file mode 100644 index 0000000..6813af6 --- /dev/null +++ b/0025-add-support-for-systemctl-mode-to-start-etmem.patch @@ -0,0 +1,243 @@ +From 7701548a6a1d131e642e74ef39a5a38093023b3f Mon Sep 17 00:00:00 2001 +From: louhongxiang +Date: Mon, 10 May 2021 20:31:23 +0800 +Subject: [PATCH 25/50] add support for systemctl mode to start etmem + +--- + inc/etmemd_inc/etmemd_common.h | 7 ++- + inc/etmemd_inc/etmemd_rpc.h | 1 + + inc/etmemd_inc/etmemd_task.h | 3 -- + src/etmemd_src/etmemd_common.c | 7 ++- + src/etmemd_src/etmemd_rpc.c | 80 ++++++++++++++++++++++++++++++++++ + src/etmemd_src/etmemd_task.c | 4 +- + 6 files changed, 95 insertions(+), 7 deletions(-) + +diff --git a/inc/etmemd_inc/etmemd_common.h b/inc/etmemd_inc/etmemd_common.h +index 1b62bbd..e228476 100644 +--- a/inc/etmemd_inc/etmemd_common.h ++++ b/inc/etmemd_inc/etmemd_common.h +@@ -23,10 +23,15 @@ + #define FILE_LINE_MAX_LEN 1024 + #define KEY_VALUE_MAX_LEN 64 + #define DECIMAL_RADIX 10 +-#define ETMEMD_MAX_PARAMETER_NUM 5 ++#define ETMEMD_MAX_PARAMETER_NUM 6 + + #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + ++/* in some system the max length of pid may be larger than 5, so we use 10 herr */ ++#define PID_STR_MAX_LEN 10 ++ ++#define PIPE_FD_LEN 2 ++ + /* + * function: parse cmdline passed to etmemd server. + * +diff --git a/inc/etmemd_inc/etmemd_rpc.h b/inc/etmemd_inc/etmemd_rpc.h +index 146cec3..aa0a49b 100644 +--- a/inc/etmemd_inc/etmemd_rpc.h ++++ b/inc/etmemd_inc/etmemd_rpc.h +@@ -55,5 +55,6 @@ int etmemd_parse_sock_name(const char *sock_name); + int etmemd_rpc_server(void); + bool etmemd_sock_name_set(void); + void etmemd_sock_name_free(void); ++int etmemd_deal_systemctl(void); + + #endif +diff --git a/inc/etmemd_inc/etmemd_task.h b/inc/etmemd_inc/etmemd_task.h +index be3ade3..29e8e8f 100644 +--- a/inc/etmemd_inc/etmemd_task.h ++++ b/inc/etmemd_inc/etmemd_task.h +@@ -23,9 +23,6 @@ + #include "etmemd_threadtimer.h" + #include "etmemd_task_exp.h" + +-/* in some system the max length of pid may be larger than 5, so we use 10 here */ +-#define PID_STR_MAX_LEN 10 +- + struct task_pid { + unsigned int pid; + float rt_swapin_rate; /* real time swapin rate */ +diff --git a/src/etmemd_src/etmemd_common.c b/src/etmemd_src/etmemd_common.c +index 4b9c4cb..155a64b 100644 +--- a/src/etmemd_src/etmemd_common.c ++++ b/src/etmemd_src/etmemd_common.c +@@ -37,6 +37,7 @@ static void usage(void) + "\noptions:\n" + " -l|--log-level Log level\n" + " -s|--socket Socket name to listen to\n" ++ " -m|--mode-systemctl mode used to start(systemctl)\n" + " -h|--help Show this message\n"); + } + +@@ -66,6 +67,9 @@ static int etmemd_parse_opts_valid(int opt, bool *is_help) + *is_help = true; + usage(); + break; ++ case 'm': ++ ret = etmemd_deal_systemctl(); ++ break; + case '?': + printf("error: parse parameters failed\n"); + /* fallthrough */ +@@ -99,12 +103,13 @@ static int etmemd_parse_check_result(int params_cnt, int argc, const bool *is_he + + int etmemd_parse_cmdline(int argc, char *argv[], bool *is_help) + { +- const char *op_str = "s:l:h"; ++ const char *op_str = "s:l:mh"; + int params_cnt = 0; + int opt, ret; + struct option long_options[] = { + {"socket", required_argument, NULL, 's'}, + {"log-level", required_argument, NULL, 'l'}, ++ {"mode-systemctl", no_argument, NULL, 'm'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0}, + }; +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index 8360f5a..ba5971c 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -19,6 +19,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include "securec.h" + #include "etmemd_rpc.h" + #include "etmemd_project.h" +@@ -35,6 +38,8 @@ + static bool g_exit = true; + static char *g_sock_name = NULL; + static int g_sock_fd; ++static int g_fd[PIPE_FD_LEN]; ++static int g_use_systemctl = 0; + struct server_rpc_params g_rpc_params; + + struct rpc_resp_msg { +@@ -67,6 +72,12 @@ struct rpc_resp_msg g_resp_msg_arr[] = { + {OPT_RET_END, NULL}, + }; + ++int etmemd_deal_systemctl(void) ++{ ++ g_use_systemctl = 1; ++ return 0; ++} ++ + static void etmemd_set_flag(int s) + { + etmemd_log(ETMEMD_LOG_ERR, "caught signal %d\n", s); +@@ -637,8 +648,69 @@ RPC_EXIT: + return ret; + } + ++static int rpc_deal_parent(void) ++{ ++ int len, handle, pid; ++ char pid_s[PID_STR_MAX_LEN]; ++ int val = 0; ++ ++ /* in systemctl mode, parent process need to write child pid */ ++ if (socketpair(AF_UNIX, SOCK_STREAM, 0, g_fd) < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "Error initing pipefd\n"); ++ return -1; ++ } ++ ++ pid = fork(); ++ if (pid != 0) { ++ if ((handle = open("/run/etmemd.pid", O_WRONLY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE)) == -1) { ++ etmemd_log(ETMEMD_LOG_ERR, "Error opening file\n"); ++ exit(1); ++ } ++ ++ if ((len = sprintf_s(pid_s, PID_STR_MAX_LEN, "%d", pid)) <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "sprintf for pid failed\n"); ++ exit(1); ++ } ++ ++ if ((write(handle, pid_s, len)) != len) { ++ etmemd_log(ETMEMD_LOG_ERR, "Error writing to the file\n"); ++ exit(1); ++ } ++ ++ close(g_fd[1]); ++ if (read(g_fd[0], &val, sizeof(val)) <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "Error reading to the file\n"); ++ exit(1); ++ } ++ ++ if (val == 1) { ++ exit(0); ++ } ++ } ++ return 0; ++} ++ ++static int rpc_deal_child(void) ++{ ++ int val = 1; ++ close(g_fd[0]); ++ if (write(g_fd[1], &val, sizeof(val)) <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "Error writing pipe fd\n"); ++ return -1; ++ } ++ close(g_fd[1]); ++ return 0; ++} ++ + int etmemd_rpc_server(void) + { ++ /* in systemctl mode, parent process need to write child pid */ ++ if (g_use_systemctl) { ++ if (rpc_deal_parent() != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "Error deal by parent process\n"); ++ return -1; ++ } ++ } + if (!etmemd_sock_name_set()) { + etmemd_log(ETMEMD_LOG_ERR, "socket name of rpc must be provided\n"); + return -1; +@@ -661,6 +733,14 @@ int etmemd_rpc_server(void) + return -1; + } + ++ /* in systemctl mode, child process need to notify parent to exit */ ++ if (g_use_systemctl) { ++ if (rpc_deal_child() != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "Error sending message to parent process\n"); ++ return -1; ++ } ++ } ++ + while (!g_exit) { + if (etmemd_rpc_accept(g_sock_fd) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "handle remote call failed once, error(%s)\n", +diff --git a/src/etmemd_src/etmemd_task.c b/src/etmemd_src/etmemd_task.c +index b948c63..01491f7 100644 +--- a/src/etmemd_src/etmemd_task.c ++++ b/src/etmemd_src/etmemd_task.c +@@ -205,7 +205,7 @@ static int get_pid_from_type_name(char *val, char *pid) + char *arg_pid[] = {"/usr/bin/pgrep", "-x", val, NULL}; + FILE *file = NULL; + int ret = -1; +- int pipefd[2]; /* used for pipefd[2] communication to obtain the task PID */ ++ int pipefd[PIPE_FD_LEN]; /* used for pipefd[PIPE_FD_LEN] communication to obtain the task PID */ + + if (pipe(pipefd) == -1) { + return -1; +@@ -269,7 +269,7 @@ static int fill_task_child_pid(struct task *tk, char *pid) + char *arg_pid[] = {"/usr/bin/pgrep", "-P", pid, NULL}; + FILE *file = NULL; + int ret; +- int pipefd[2]; /* used for pipefd[2] communication to obtain the task PID */ ++ int pipefd[PIPE_FD_LEN]; /* used for pipefd[PIPE_FD_LEN] communication to obtain the task PID */ + + if (pipe(pipefd) == -1) { + return -1; +-- +2.27.0 + diff --git a/0026-add-scan-library.patch b/0026-add-scan-library.patch new file mode 100644 index 0000000..61f6ddb --- /dev/null +++ b/0026-add-scan-library.patch @@ -0,0 +1,524 @@ +From dcf4760df185d5e75f522914e160d85d4f3543ce Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Tue, 11 May 2021 15:53:10 +0800 +Subject: [PATCH 26/50] add scan library + +Signed-off-by: Kemeng Shi +--- + CMakeLists.txt | 25 ++++++++++ + inc/etmemd_inc/etmemd.h | 23 +--------- + inc/etmemd_inc/etmemd_exp.h | 42 +++++++++++++++++ + inc/etmemd_inc/etmemd_scan.h | 43 ++--------------- + inc/etmemd_inc/etmemd_scan_exp.h | 71 +++++++++++++++++++++++++++++ + inc/etmemd_inc/etmemd_scan_export.h | 22 +++++++++ + src/etmemd_src/etmemd_common.c | 13 +++++- + src/etmemd_src/etmemd_scan.c | 67 +++++++++++++++++++++++++-- + src/etmemd_src/etmemd_scan.version | 4 ++ + 9 files changed, 244 insertions(+), 66 deletions(-) + create mode 100644 inc/etmemd_inc/etmemd_exp.h + create mode 100644 inc/etmemd_inc/etmemd_scan_exp.h + create mode 100644 inc/etmemd_inc/etmemd_scan_export.h + create mode 100644 src/etmemd_src/etmemd_scan.version + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 9ce4724..6d11da9 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -55,8 +55,13 @@ add_executable(etmemd + add_executable(etmem + ${ETMEM_SRC}) + ++add_library(etmemd_scan SHARED ++ ${ETMEMD_SRC}) ++ + set(EXECUTABLE_OUTPUT_PATH ${BUILD_DIR}/bin) + ++set(LIBRARY_OUTPUT_PATH ${BUILD_DIR}/lib) ++ + include(FindPkgConfig) + pkg_search_module(GLIB2 REQUIRED glib-2.0) + +@@ -67,6 +72,10 @@ target_include_directories(etmemd PRIVATE + target_include_directories(etmem PRIVATE + ${PROJECT_SOURCE_DIR}/inc/etmem_inc) + ++target_include_directories(etmemd_scan PRIVATE ++ ${PROJECT_SOURCE_DIR}/inc/etmemd_inc ++ ${GLIB2_INCLUDE_DIRS}) ++ + target_compile_options(etmemd PRIVATE -fsigned-char -fno-omit-frame-pointer -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wmissing-declarations -fno-strict-aliasing -Werror -Wformat -Wformat-security -D_GNU_SOURCE -fPIE -pie -fPIC -fstack-protector-strong -fno-common -DNDEBUG -O2 -D_FORTIFY_SOURCE=2 -Wall -Werror -Wl,-z,relro,-z,now,-z,noexecstack -Wtrampolines -pthread -Wno-pointer-sign -Wstrict-prototypes -Wold-style-definition -std=gnu99) + + +@@ -97,3 +106,19 @@ if( ${ARCHITECTURE} STREQUAL "aarch64" ) + else() + target_compile_options(etmem PRIVATE -march=core-avx-i -m64) + endif() ++ ++target_compile_options(etmemd_scan PRIVATE -fsigned-char -fno-omit-frame-pointer -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wmissing-declarations -fno-strict-aliasing -Werror -Wformat -Wformat-security -D_GNU_SOURCE -fPIE -pie -fPIC -fstack-protector-strong -fno-common -DNDEBUG -O2 -D_FORTIFY_SOURCE=2 -Wall -Werror -Wl,-z,relro,-z,now,-z,noexecstack -Wtrampolines -pthread -Wno-pointer-sign -Wstrict-prototypes -Wold-style-definition -std=gnu99 -fPIC -shared) ++ ++ ++if(CONFIG_DEBUG STREQUAL "y") ++ target_compile_options(etmemd_scan PRIVATE -g) ++endif() ++ ++set_target_properties(etmemd_scan PROPERTIES LINK_FLAGS "-s -fPIE -pie -fPIC -Wl,-z,relro,-z,now,-z,noexecstack -Wtrampolines -Wl,--version-script=${ETMEMD_SRC_DIR}/etmemd_scan.version") ++target_link_libraries(etmemd_scan PRIVATE pthread dl rt boundscheck numa ${GLIB2_LIBRARIES}) ++ ++if( ${ARCHITECTURE} STREQUAL "aarch64" ) ++ target_compile_options(etmemd_scan PRIVATE -march=armv8-a) ++else() ++ target_compile_options(etmemd_scan PRIVATE -march=core-avx-i -m64) ++endif() +diff --git a/inc/etmemd_inc/etmemd.h b/inc/etmemd_inc/etmemd.h +index 797049e..357ea4a 100644 +--- a/inc/etmemd_inc/etmemd.h ++++ b/inc/etmemd_inc/etmemd.h +@@ -16,34 +16,13 @@ + #ifndef ETMEMD_H + #define ETMEMD_H + +-#include + #include ++#include "etmemd_exp.h" + + #define PTE_SIZE_SHIFT 12 + #define PMD_SIZE_SHIFT 21 + #define PUD_SIZE_SHIFT 30 + +-/* +- * page type specified by size +- * */ +-enum page_type { +- PTE_TYPE = 0, +- PMD_TYPE, +- PUD_TYPE, +- PAGE_TYPE_INVAL, +-}; +- +-/* +- * page struct after scan and parse +- * */ +-struct page_refs { +- uint64_t addr; /* page address */ +- int count; /* page count */ +- enum page_type type; /* page type including PTE/PMD/PUD */ +- +- struct page_refs *next; /* point to next page */ +-}; +- + /* memory grade is the result that judged by policy function after pagerefs come into it, + * every policy fucntion has its own rule to make the choice which page is hot grade or + * the other grades */ +diff --git a/inc/etmemd_inc/etmemd_exp.h b/inc/etmemd_inc/etmemd_exp.h +new file mode 100644 +index 0000000..8c57d9f +--- /dev/null ++++ b/inc/etmemd_inc/etmemd_exp.h +@@ -0,0 +1,42 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: shikemeng ++ * Create: 2021-04-30 ++ * Description: This is a header file of the export data structure definition for page. ++ ******************************************************************************/ ++ ++#ifndef ETMEMD_EXP_H ++#define ETMEMD_EXP_H ++ ++#include ++ ++/* ++ * page type specified by size ++ * */ ++enum page_type { ++ PTE_TYPE = 0, ++ PMD_TYPE, ++ PUD_TYPE, ++ PAGE_TYPE_INVAL, ++}; ++ ++/* ++ * page struct after scan and parse ++ * */ ++struct page_refs { ++ uint64_t addr; /* page address */ ++ int count; /* page count */ ++ enum page_type type; /* page type including PTE/PMD/PUD */ ++ ++ struct page_refs *next; /* point to next page */ ++}; ++ ++#endif +diff --git a/inc/etmemd_inc/etmemd_scan.h b/inc/etmemd_inc/etmemd_scan.h +index ed72e1a..09ad51c 100644 +--- a/inc/etmemd_inc/etmemd_scan.h ++++ b/inc/etmemd_inc/etmemd_scan.h +@@ -19,9 +19,8 @@ + #include + #include "etmemd.h" + #include "etmemd_task.h" ++#include "etmemd_scan_exp.h" + +-#define VMA_PATH_STR_LEN 256 +-#define VMA_MAJOR_MINOR_LEN 8 + #define VMA_SEG_CNT_MAX 6 + #define VMA_PERMS_STR_LEN 5 + #define VMA_ADDR_STR_LEN 17 +@@ -35,15 +34,7 @@ + #define SMAPS_FILE "/smaps" + #define VMFLAG_HEAD "VmFlags" + +-#define SCAN_AS_HUGE O_LARGEFILE +- +-enum { +- VMA_STAT_READ = 0, +- VMA_STAT_WRITE, +- VMA_STAT_EXEC, +- VMA_STAT_MAY_SHARE, +- VMA_STAT_INIT, +-}; ++#define ALL_SCAN_FLAGS (SCAN_AS_HUGE | SCAN_IGN_HOST) + + enum page_idle_type { + PTE_ACCESS = 0, /* 4k page */ +@@ -66,40 +57,12 @@ enum access_type_weight { + WRITE_TYPE_WEIGHT = 3, + }; + +-/* +- * vma struct +- * */ +-struct vma { +- uint64_t start; /* address start */ +- uint64_t end; /* address end */ +- bool stat[VMA_STAT_INIT]; /* vm area permissions */ +- uint64_t offset; /* vm area offset */ +- uint64_t inode; /* vm area inode */ +- char path[VMA_PATH_STR_LEN]; /* path name */ +- char major[VMA_MAJOR_MINOR_LEN]; /* device number major part */ +- char minor[VMA_MAJOR_MINOR_LEN]; /* device number minor part */ +- +- struct vma *next; /* point to next vma */ +-}; +- + struct walk_address { + uint64_t walk_start; /* walk address start */ + uint64_t walk_end; /* walk address end */ + uint64_t last_walk_end; /* last walk address end */ + }; + +-/* +- * vmas struct +- * */ +-struct vmas { +- uint64_t vma_cnt; /* number of vm area */ +- +- struct vma *vma_list; /* vm area list */ +-}; +- +-/* etmemd_free_page_refs need to be called by the handler who called etmemd_do_scan() successfully */ +-void etmemd_free_page_refs(struct page_refs *pf); +- + /* the caller need to judge value returned by etmemd_do_scan(), NULL means fail. */ + struct page_refs *etmemd_do_scan(const struct task_pid *tpid, const struct task *tk); + +@@ -107,7 +70,7 @@ struct page_refs *etmemd_do_scan(const struct task_pid *tpid, const struct task + void free_vmas(struct vmas *vmas); + + struct page_refs **walk_vmas(int fd, struct walk_address *walk_address, struct page_refs **pf, unsigned long *use_rss); +-int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **page_refs, unsigned long *use_rss); ++int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **page_refs, unsigned long *use_rss, int flags); + + int split_vmflags(char ***vmflags_array, char *vmflags); + struct vmas *get_vmas_with_flags(const char *pid, char **vmflags_array, int vmflags_num, bool is_anon_only); +diff --git a/inc/etmemd_inc/etmemd_scan_exp.h b/inc/etmemd_inc/etmemd_scan_exp.h +new file mode 100644 +index 0000000..1fd4379 +--- /dev/null ++++ b/inc/etmemd_inc/etmemd_scan_exp.h +@@ -0,0 +1,71 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: shikemeng ++ * Create: 2021-04-30 ++ * Description: This is a header file of the function declaration for export scan function. ++ ******************************************************************************/ ++ ++#ifndef ETMEMD_SCAN_EXP_H ++#define ETMEMD_SCAN_EXP_H ++ ++#include ++#include ++#include ++ ++#define VMA_PATH_STR_LEN 256 ++#define VMA_MAJOR_MINOR_LEN 8 ++ ++#define SCAN_AS_HUGE 0100000000 /* treat normal vm page as vm hugepage */ ++#define SCAN_IGN_HOST 0200000000 /* ignore host access when scan vm */ ++ ++enum { ++ VMA_STAT_READ = 0, ++ VMA_STAT_WRITE, ++ VMA_STAT_EXEC, ++ VMA_STAT_MAY_SHARE, ++ VMA_STAT_INIT, ++}; ++ ++/* ++ * vma struct ++ * */ ++struct vma { ++ uint64_t start; /* address start */ ++ uint64_t end; /* address end */ ++ bool stat[VMA_STAT_INIT]; /* vm area permissions */ ++ uint64_t offset; /* vm area offset */ ++ uint64_t inode; /* vm area inode */ ++ char path[VMA_PATH_STR_LEN]; /* path name */ ++ char major[VMA_MAJOR_MINOR_LEN]; /* device number major part */ ++ char minor[VMA_MAJOR_MINOR_LEN]; /* device number minor part */ ++ ++ struct vma *next; /* point to next vma */ ++}; ++ ++/* ++ * vmas struct ++ * */ ++struct vmas { ++ uint64_t vma_cnt; /* number of vm area */ ++ ++ struct vma *vma_list; /* vm area list */ ++}; ++ ++int etmemd_scan_init(void); ++void etmemd_scan_exit(void); ++ ++struct vmas *etmemd_get_vmas(const char *pid, char **vmflags_array, int vmflags_num, bool is_anon_only); ++void etmemd_free_vmas(struct vmas *vmas); ++ ++int etmemd_get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **page_refs, int flags); ++void etmemd_free_page_refs(struct page_refs *page_refs); ++ ++#endif +diff --git a/inc/etmemd_inc/etmemd_scan_export.h b/inc/etmemd_inc/etmemd_scan_export.h +new file mode 100644 +index 0000000..7ddc097 +--- /dev/null ++++ b/inc/etmemd_inc/etmemd_scan_export.h +@@ -0,0 +1,22 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved. ++ * etmem is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Author: shikemeng ++ * Create: 2021-4-30 ++ * Description: This is a header file of the export scan library. ++ ******************************************************************************/ ++ ++#ifndef ETMEMD_SCAN_EXPORT_H ++#define ETMEMD_SCAN_EXPORT_H ++ ++#include "etmemd_exp.h" ++#include "etmemd_scan_exp.h" ++ ++#endif +diff --git a/src/etmemd_src/etmemd_common.c b/src/etmemd_src/etmemd_common.c +index 4b9c4cb..59933c4 100644 +--- a/src/etmemd_src/etmemd_common.c ++++ b/src/etmemd_src/etmemd_common.c +@@ -24,12 +24,18 @@ + #include + #include + #include ++#include ++#include + + #include "securec.h" + #include "etmemd_common.h" + #include "etmemd_rpc.h" + #include "etmemd_log.h" + ++#define IDLE_SCAN_MAGIC 0X66 ++#define IDLE_SCAN_ADD_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x0, unsigned int) ++#define IDLE_SCAN_REMOVE_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x1, unsigned int) ++ + static void usage(void) + { + printf("\nusage of etmemd:\n" +@@ -228,11 +234,16 @@ FILE *etmemd_get_proc_file(const char *pid, const char *file, int flags, const c + return NULL; + } + +- fd = open(file_name, flags); ++ fd = open(file_name, 0); + if (fd < 0) { + etmemd_log(ETMEMD_LOG_ERR, "open file %s fail\n", file_name); + goto free_file_name; + } ++ if (flags != 0 && ioctl(fd, IDLE_SCAN_ADD_FLAGS, &flags) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "set idle flags for %s fail with %s\n", pid, strerror(errno)); ++ close(fd); ++ goto free_file_name; ++ } + fp = fdopen(fd, mode); + + free_file_name: +diff --git a/src/etmemd_src/etmemd_scan.c b/src/etmemd_src/etmemd_scan.c +index fb4dd33..ba0cf5e 100644 +--- a/src/etmemd_src/etmemd_scan.c ++++ b/src/etmemd_src/etmemd_scan.c +@@ -35,6 +35,8 @@ + #define VMFLAG_MAX_LEN 100 + #define VMFLAG_MAX_NUM 30 + ++static bool g_exp_scan_inited = false; ++ + static const enum page_type g_page_type_by_idle_kind[] = { + PTE_TYPE, + PMD_TYPE, +@@ -403,6 +405,25 @@ struct vmas *get_vmas(const char *pid) + return get_vmas_with_flags(pid, NULL, 0, true); + } + ++struct vmas *etmemd_get_vmas(const char *pid, char *vmflags_array[], int vmflags_num, bool is_anon_only) ++{ ++ int i; ++ ++ if (pid == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "etmemd_get_vmas pid param is NULL\n"); ++ return NULL; ++ } ++ ++ for (i = 0; i < vmflags_num; i++) { ++ if (vmflags_array[i] == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "etmemd_get_vmas vmflags_array[%d] is NULL\n", i); ++ return NULL; ++ } ++ } ++ ++ return get_vmas_with_flags(pid, vmflags_array, vmflags_num, is_anon_only); ++} ++ + static u_int64_t get_address_from_buf(const unsigned char *buf, u_int64_t index) + { + u_int64_t address; +@@ -633,7 +654,7 @@ struct page_refs **walk_vmas(int fd, + * this parameter is used only in the dynamic engine to calculate the swap-in rate. + * In other policies, NULL can be directly transmitted. + * */ +-int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **page_refs, unsigned long *use_rss) ++int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **page_refs, unsigned long *use_rss, int flags) + { + u_int64_t i; + FILE *scan_fp = NULL; +@@ -642,7 +663,7 @@ int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **p + struct page_refs **tmp_page_refs = NULL; + struct walk_address walk_address = {0, 0, 0}; + +- scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, 0, "r"); ++ scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, flags, "r"); + if (scan_fp == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "open %s file fail\n", IDLE_SCAN_FILE); + return -1; +@@ -683,6 +704,21 @@ int get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **p + return 0; + } + ++int etmemd_get_page_refs(const struct vmas *vmas, const char *pid, struct page_refs **page_refs, int flags) ++{ ++ if (!g_exp_scan_inited) { ++ etmemd_log(ETMEMD_LOG_ERR, "scan module is not inited before etmemd_get_page_refs\n"); ++ return -1; ++ } ++ ++ if (vmas == NULL || pid == NULL || page_refs == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "NULL param is found in etmemd_get_page_refs\n"); ++ return -1; ++ } ++ ++ return get_page_refs(vmas, pid, page_refs, NULL, flags & ALL_SCAN_FLAGS); ++} ++ + void etmemd_free_page_refs(struct page_refs *pf) + { + struct page_refs *tmp_pf = NULL; +@@ -721,7 +757,7 @@ struct page_refs *etmemd_do_scan(const struct task_pid *tpid, const struct task + + /* loop for scanning idle_pages to get result of memory access. */ + for (i = 0; i < tk->eng->proj->loop; i++) { +- ret = get_page_refs(vmas, pid, &page_refs, NULL); ++ ret = get_page_refs(vmas, pid, &page_refs, NULL, 0); + if (ret != 0) { + etmemd_log(ETMEMD_LOG_ERR, "scan operation failed\n"); + /* free page_refs nodes already exist */ +@@ -737,6 +773,11 @@ struct page_refs *etmemd_do_scan(const struct task_pid *tpid, const struct task + return page_refs; + } + ++void etmemd_free_vmas(struct vmas *vmas) ++{ ++ free_vmas(vmas); ++} ++ + void clean_page_refs_unexpected(void *arg) + { + struct page_refs **pf = (struct page_refs **)arg; +@@ -773,3 +814,23 @@ struct page_refs *add_page_refs_into_memory_grade(struct page_refs *page_refs, s + /* return the next page_refs of the one that passed in */ + return tmp; + } ++ ++int etmemd_scan_init(void) ++{ ++ if (g_exp_scan_inited) { ++ etmemd_log(ETMEMD_LOG_ERR, "scan module already inited\n"); ++ return -1; ++ } ++ ++ if (init_g_page_size() == -1) { ++ return -1; ++ } ++ ++ g_exp_scan_inited = true; ++ return 0; ++} ++ ++void etmemd_scan_exit(void) ++{ ++ g_exp_scan_inited = false; ++} +diff --git a/src/etmemd_src/etmemd_scan.version b/src/etmemd_src/etmemd_scan.version +new file mode 100644 +index 0000000..576c96f +--- /dev/null ++++ b/src/etmemd_src/etmemd_scan.version +@@ -0,0 +1,4 @@ ++libetmemd_scan { ++ global: etmemd_scan_init; etmemd_scan_exit; etmemd_get_vmas; etmemd_free_vmas; etmemd_get_page_refs; etmemd_free_page_refs; ++ local:*; ++}; +-- +2.27.0 + diff --git a/0027-add-ign_host-to-ignore-host-access-when-scan-vm.patch b/0027-add-ign_host-to-ignore-host-access-when-scan-vm.patch new file mode 100644 index 0000000..67938ba --- /dev/null +++ b/0027-add-ign_host-to-ignore-host-access-when-scan-vm.patch @@ -0,0 +1,72 @@ +From 104406ad127feeafbf5c8d618c608285ff23cd78 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Tue, 11 May 2021 16:08:39 +0800 +Subject: [PATCH 27/50] add ign_host to ignore host access when scan vm + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 25 ++++++++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 47a3608..9a2ab04 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -98,6 +98,7 @@ struct cslide_task_params { + char **vmflags_array; + int vmflags_num; + }; ++ int scan_flags; + }; + + struct vma_pf { +@@ -1285,13 +1286,14 @@ static int cslide_scan_vmas(struct cslide_pid_params *params) + struct walk_address walk_address; + uint64_t i; + int fd; ++ struct cslide_task_params *task_params = params->task_params; + + if (snprintf_s(pid, PID_STR_MAX_LEN, PID_STR_MAX_LEN - 1, "%u", params->pid) <= 0) { + etmemd_log(ETMEMD_LOG_ERR, "snpintf pid %u fail\n", params->pid); + return -1; + } + +- scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, SCAN_AS_HUGE, "r"); ++ scan_fp = etmemd_get_proc_file(pid, IDLE_SCAN_FILE, task_params->scan_flags, "r"); + if (scan_fp == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "open %s file for pid %u fail\n", IDLE_SCAN_FILE, params->pid); + return -1; +@@ -1922,9 +1924,30 @@ static int fill_task_vm_flags(void *obj, void *val) + return 0; + } + ++static int fill_task_scan_flags(void *obj, void *val) ++{ ++ struct cslide_task_params *params = (struct cslide_task_params *)obj; ++ char *ign_host = (char *)val; ++ int ret = 0; ++ ++ params->scan_flags |= SCAN_AS_HUGE; ++ ++ if (strcmp(ign_host, "yes") == 0) { ++ params->scan_flags |= SCAN_IGN_HOST; ++ } else if (strcmp(ign_host, "no") != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "ign_host : not support %s\n", ign_host); ++ etmemd_log(ETMEMD_LOG_ERR, "ign_host : only support yes/no\n"); ++ return -1; ++ } ++ ++ free(val); ++ return ret; ++} ++ + static struct config_item g_cslide_task_config_items[] = { + {"vm_flags", STR_VAL, fill_task_vm_flags, false}, + {"anon_only", STR_VAL, fill_task_anon_only, false}, ++ {"ign_host", STR_VAL, fill_task_scan_flags, false}, + }; + + static int cslide_fill_task(GKeyFile *config, struct task *tk) +-- +2.27.0 + diff --git a/0028-openlog-with-same-ident.patch b/0028-openlog-with-same-ident.patch new file mode 100644 index 0000000..08da55c --- /dev/null +++ b/0028-openlog-with-same-ident.patch @@ -0,0 +1,41 @@ +From 4c33e102cd7745a4b2c2186414e0f2338e763916 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Tue, 11 May 2021 16:09:26 +0800 +Subject: [PATCH 28/50] openlog with same ident + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_log.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/etmemd_src/etmemd_log.c b/src/etmemd_src/etmemd_log.c +index fc49db8..5d7dece 100644 +--- a/src/etmemd_src/etmemd_log.c ++++ b/src/etmemd_src/etmemd_log.c +@@ -58,19 +58,19 @@ void etmemd_log(enum log_level log_level, const char *format, ...) + + switch (log_level) { + case ETMEMD_LOG_DEBUG: +- openlog("[etmemd_debug] ", LOG_PID, LOG_USER); ++ openlog("[etmemd] ", LOG_PID, LOG_USER); + vsyslog(LOG_DEBUG, format, args_in); + break; + case ETMEMD_LOG_INFO: +- openlog("[etmemd_info] ", LOG_PID, LOG_USER); ++ openlog("[etmemd] ", LOG_PID, LOG_USER); + vsyslog(LOG_INFO, format, args_in); + break; + case ETMEMD_LOG_WARN: +- openlog("[etmemd_warning] ", LOG_PID, LOG_USER); ++ openlog("[etmemd] ", LOG_PID, LOG_USER); + vsyslog(LOG_WARNING, format, args_in); + break; + case ETMEMD_LOG_ERR: +- openlog("[etmemd_error] ", LOG_PID, LOG_USER); ++ openlog("[etmemd] ", LOG_PID, LOG_USER); + vsyslog(LOG_ERR, format, args_in); + break; + default: +-- +2.27.0 + diff --git a/0029-accept-advise.patch b/0029-accept-advise.patch new file mode 100644 index 0000000..3936a85 --- /dev/null +++ b/0029-accept-advise.patch @@ -0,0 +1,139 @@ +From fee91c2853f346d5222bf818930182b7b05b0e9f Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Tue, 11 May 2021 22:44:06 +0800 +Subject: [PATCH 29/50] accept advise + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_common.c | 2 +- + src/etmemd_src/etmemd_cslide.c | 2 +- + src/etmemd_src/etmemd_log.c | 6 ++---- + src/etmemd_src/etmemd_scan.c | 23 ++++++++++++++++++++++- + 4 files changed, 26 insertions(+), 7 deletions(-) + +diff --git a/src/etmemd_src/etmemd_common.c b/src/etmemd_src/etmemd_common.c +index 59933c4..e1cb1dd 100644 +--- a/src/etmemd_src/etmemd_common.c ++++ b/src/etmemd_src/etmemd_common.c +@@ -32,7 +32,7 @@ + #include "etmemd_rpc.h" + #include "etmemd_log.h" + +-#define IDLE_SCAN_MAGIC 0X66 ++#define IDLE_SCAN_MAGIC 0x66 + #define IDLE_SCAN_ADD_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x0, unsigned int) + #define IDLE_SCAN_REMOVE_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x1, unsigned int) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 9a2ab04..6f609b8 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -1937,7 +1937,7 @@ static int fill_task_scan_flags(void *obj, void *val) + } else if (strcmp(ign_host, "no") != 0) { + etmemd_log(ETMEMD_LOG_ERR, "ign_host : not support %s\n", ign_host); + etmemd_log(ETMEMD_LOG_ERR, "ign_host : only support yes/no\n"); +- return -1; ++ ret = -1; + } + + free(val); +diff --git a/src/etmemd_src/etmemd_log.c b/src/etmemd_src/etmemd_log.c +index 5d7dece..0ffcc20 100644 +--- a/src/etmemd_src/etmemd_log.c ++++ b/src/etmemd_src/etmemd_log.c +@@ -56,26 +56,24 @@ void etmemd_log(enum log_level log_level, const char *format, ...) + + va_start(args_in, format); + ++ openlog("[etmemd] ", LOG_PID, LOG_USER); + switch (log_level) { + case ETMEMD_LOG_DEBUG: +- openlog("[etmemd] ", LOG_PID, LOG_USER); + vsyslog(LOG_DEBUG, format, args_in); + break; + case ETMEMD_LOG_INFO: +- openlog("[etmemd] ", LOG_PID, LOG_USER); + vsyslog(LOG_INFO, format, args_in); + break; + case ETMEMD_LOG_WARN: +- openlog("[etmemd] ", LOG_PID, LOG_USER); + vsyslog(LOG_WARNING, format, args_in); + break; + case ETMEMD_LOG_ERR: +- openlog("[etmemd] ", LOG_PID, LOG_USER); + vsyslog(LOG_ERR, format, args_in); + break; + default: + va_end(args_in); + printf("log_level is invalid, please check!\n"); ++ closelog(); + return; + } + +diff --git a/src/etmemd_src/etmemd_scan.c b/src/etmemd_src/etmemd_scan.c +index ba0cf5e..c287c48 100644 +--- a/src/etmemd_src/etmemd_scan.c ++++ b/src/etmemd_src/etmemd_scan.c +@@ -34,6 +34,7 @@ + #define PMD_IDLE_PTES_PARAMETER 512 + #define VMFLAG_MAX_LEN 100 + #define VMFLAG_MAX_NUM 30 ++#define VMFLAG_VALID_LEN 2 + + static bool g_exp_scan_inited = false; + +@@ -272,6 +273,7 @@ static bool is_vma_with_vmflags(FILE *fp, char *vmflags_array[], int vmflags_num + char parse_line[FILE_LINE_MAX_LEN]; + size_t len; + int i; ++ char *flags_start = NULL; + + len = strlen(VMFLAG_HEAD); + while (fgets(parse_line, FILE_LINE_MAX_LEN - 1, fp) != NULL) { +@@ -283,9 +285,10 @@ static bool is_vma_with_vmflags(FILE *fp, char *vmflags_array[], int vmflags_num + continue; + } + ++ flags_start = strstr(parse_line, ":"); + /* check any flag in flags is set */ + for (i = 0; i < vmflags_num; i++) { +- if (strstr(parse_line, vmflags_array[i]) == NULL) { ++ if (strstr(flags_start + 1, vmflags_array[i]) == NULL) { + return false; + } + } +@@ -405,6 +408,20 @@ struct vmas *get_vmas(const char *pid) + return get_vmas_with_flags(pid, NULL, 0, true); + } + ++static bool is_flag_valid(char *flag) ++{ ++ if (strstr(flag, " ") != NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "flag %s include space\n", flag); ++ return false; ++ } ++ if (strlen(flag) != VMFLAG_VALID_LEN) { ++ etmemd_log(ETMEMD_LOG_ERR, "flag %s len is not 2\n", flag); ++ return false; ++ } ++ ++ return true; ++} ++ + struct vmas *etmemd_get_vmas(const char *pid, char *vmflags_array[], int vmflags_num, bool is_anon_only) + { + int i; +@@ -419,6 +436,10 @@ struct vmas *etmemd_get_vmas(const char *pid, char *vmflags_array[], int vmflags + etmemd_log(ETMEMD_LOG_ERR, "etmemd_get_vmas vmflags_array[%d] is NULL\n", i); + return NULL; + } ++ if (!is_flag_valid(vmflags_array[i])) { ++ etmemd_log(ETMEMD_LOG_ERR, "etmemd_get_vmas flag %s invalid\n", vmflags_array[i]); ++ return NULL; ++ } + } + + return get_vmas_with_flags(pid, vmflags_array, vmflags_num, is_anon_only); +-- +2.27.0 + diff --git a/0030-notify-rpc-success-with-finish-tag.patch b/0030-notify-rpc-success-with-finish-tag.patch new file mode 100644 index 0000000..f8c4afa --- /dev/null +++ b/0030-notify-rpc-success-with-finish-tag.patch @@ -0,0 +1,157 @@ +From 21795f23fa1532edffb636de90789749bf7dae04 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Tue, 11 May 2021 16:35:55 +0800 +Subject: [PATCH 30/50] notify rpc success with finish tag + +Signed-off-by: Kemeng Shi +--- + src/etmem_src/etmem_rpc.c | 39 +++++++++++++++++++++---------------- + src/etmemd_src/etmemd_rpc.c | 25 ++++++++++++++++-------- + 2 files changed, 39 insertions(+), 25 deletions(-) + +diff --git a/src/etmem_src/etmem_rpc.c b/src/etmem_src/etmem_rpc.c +index 48a4a96..2c70cf8 100644 +--- a/src/etmem_src/etmem_rpc.c ++++ b/src/etmem_src/etmem_rpc.c +@@ -31,6 +31,9 @@ + #define ETMEM_RPC_SEND_BUF_LEN 512 + #define ETMEM_RPC_CONN_TIMEOUT 10 + ++#define SUCCESS_CHAR (0xff) ++#define FAIL_CHAR (0xfe) ++ + static int etmem_client_conn(const struct mem_proj *proj, int sockfd) + { + struct sockaddr_un svr_addr; +@@ -144,14 +147,6 @@ EXIT: + return ret; + } + +-static bool etmem_recv_find_fail_keyword(const char *recv_msg) +-{ +- if (strstr(recv_msg, "error") != NULL) { +- return true; +- } +- return false; +-} +- + static int etmem_client_recv(int sockfd) + { + ssize_t recv_size; +@@ -159,6 +154,7 @@ static int etmem_client_recv(int sockfd) + char *recv_msg = NULL; + uint8_t *recv_buf = NULL; + size_t recv_len = ETMEM_RPC_RECV_BUF_LEN; ++ bool done = false; + + recv_buf = (uint8_t *)calloc(recv_len, sizeof(uint8_t)); + if (recv_buf == NULL) { +@@ -166,27 +162,36 @@ static int etmem_client_recv(int sockfd) + return -1; + } + +- while (true) { ++ while (!done) { + recv_size = recv(sockfd, recv_buf, recv_len - 1, 0); + if (recv_size < 0) { + perror("recv failed:"); + goto EXIT; + } + if (recv_size == 0) { +- if (errno == EAGAIN || errno == EWOULDBLOCK) { +- printf("recv timeout:\n"); +- } +- ret = 0; ++ printf("connection closed by peer\n"); + goto EXIT; + } + + recv_msg = (char *)recv_buf; + recv_msg[recv_size] = '\0'; +- printf("%s\n", recv_msg); +- if (etmem_recv_find_fail_keyword(recv_msg)) { +- printf("error occurs when getting response from etmemd server\n"); +- goto EXIT; ++ ++ // check and erease finish flag ++ switch (recv_msg[recv_size - 1]) { ++ case (char)SUCCESS_CHAR: ++ ret = 0; ++ done = true; ++ recv_msg[recv_size - 1] = '\0'; ++ break; ++ case (char)FAIL_CHAR: ++ done = true; ++ recv_msg[recv_size - 1] = '\n'; ++ break; ++ default: ++ break; + } ++ ++ printf("%s", recv_msg); + } + + EXIT: +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index ba5971c..208f6b5 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -35,6 +35,9 @@ + #define RPC_CLIENT_MAX 1 + #define RPC_BUFF_LEN_MAX 512 + ++#define SUCCESS_CHAR (0xff) ++#define FAIL_CHAR (0Xfe) ++ + static bool g_exit = true; + static char *g_sock_name = NULL; + static int g_sock_fd; +@@ -58,7 +61,6 @@ struct server_rpc_parser g_rpc_parser[] = { + }; + + struct rpc_resp_msg g_resp_msg_arr[] = { +- {OPT_SUCCESS, "success"}, + {OPT_INVAL, "error: invalid parameters"}, + {OPT_PRO_EXISTED, "error: project has been existed"}, + {OPT_PRO_NOEXIST, "error: project is not exist"}, +@@ -533,10 +535,7 @@ static void etmemd_rpc_send_response_msg(int sock_fd, enum opt_result result) + { + int i = 0; + ssize_t ret = -1; +- +- if (result == OPT_SUCCESS) { +- return; +- } ++ char finish_tag; + + while (g_resp_msg_arr[i].msg != NULL) { + if (result != g_resp_msg_arr[i].result) { +@@ -545,12 +544,22 @@ static void etmemd_rpc_send_response_msg(int sock_fd, enum opt_result result) + } + + ret = send(sock_fd, g_resp_msg_arr[i].msg, strlen(g_resp_msg_arr[i].msg), 0); ++ if (ret < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "send response to client fail, error(%s)\n", ++ strerror(errno)); ++ } + break; + } + +- if (ret < 0) { +- etmemd_log(ETMEMD_LOG_ERR, "send response to client fail, error(%s)\n", +- strerror(errno)); ++ // notify result with finish tag ++ if (result == OPT_SUCCESS) { ++ finish_tag = SUCCESS_CHAR; ++ } else { ++ finish_tag = FAIL_CHAR; ++ } ++ ret = send(sock_fd, &finish_tag, 1, 0); ++ if (ret <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "send finish tag fail\n"); + } + return; + } +-- +2.27.0 + diff --git a/0031-remove-node_watermark.patch b/0031-remove-node_watermark.patch new file mode 100644 index 0000000..66fa08f --- /dev/null +++ b/0031-remove-node_watermark.patch @@ -0,0 +1,131 @@ +From 57861ad98668370ef2b8de094ba2b5bfed4f9bac Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Wed, 12 May 2021 15:40:17 +0800 +Subject: [PATCH 31/50] remove node_watermark + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 79 ---------------------------------- + 1 file changed, 79 deletions(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 6f609b8..745dbcc 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -143,7 +143,6 @@ struct cslide_params_factory { + struct cslide_eng_params { + struct sys_mem mem; + struct node_map node_map; +- int node_watermark; + int hot_threshold; + int hot_reserve; // in MB + int mig_quota; // in MB +@@ -1463,65 +1462,6 @@ static int cslide_do_migrate(struct cslide_eng_params *eng_params) + return 0; + } + +-static bool is_node_empty(struct node_mem *mem) +-{ +- return mem->huge_free == mem->huge_total; +-} +- +-static bool is_all_cold_node_empty(struct cslide_eng_params *eng_params) +-{ +- struct sys_mem *mem = &eng_params->mem; +- struct node_pair *pair = NULL; +- int i; +- +- for (i = 0; i < eng_params->node_map.cur_num; i++) { +- pair = &eng_params->node_map.pair[i]; +- if (!is_node_empty(&mem->node_mem[pair->cold_node])) { +- return false; +- } +- } +- return true; +-} +- +-static inline bool is_busy(int node_watermark, long long total, long long free) +-{ +- return free * TO_PCT / total < node_watermark; +-} +- +-static bool is_node_busy(int node_watermark, struct node_mem *mem) +-{ +- return is_busy(node_watermark, mem->huge_total, mem->huge_free); +-} +- +-static bool is_any_hot_node_busy(struct cslide_eng_params *eng_params) +-{ +- struct sys_mem *mem = &eng_params->mem; +- struct node_pair *pair = NULL; +- int node_watermark = eng_params->node_watermark; +- int i; +- +- for (i = 0; i < eng_params->node_map.cur_num; i++) { +- pair = &eng_params->node_map.pair[i]; +- if (is_node_busy(node_watermark, &mem->node_mem[pair->hot_node])) { +- return true; +- } +- } +- +- return false; +-} +- +-static bool need_migrate(struct cslide_eng_params *eng_params) +-{ +- if (!is_all_cold_node_empty(eng_params)) { +- return true; +- } +- if (is_any_hot_node_busy(eng_params)) { +- return true; +- } +- +- return false; +-} +- + static void init_host_pages_info(struct cslide_eng_params *eng_params) + { + int n; +@@ -1692,11 +1632,6 @@ static void *cslide_main(void *arg) + goto next; + } + +- if (!need_migrate(eng_params)) { +- etmemd_log(ETMEMD_LOG_DEBUG, "no need to migrate\n"); +- goto next; +- } +- + if (cslide_do_migrate(eng_params) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "cslide_do_migrate fail\n"); + goto next; +@@ -2055,19 +1990,6 @@ err: + return ret; + } + +-static int fill_migrate_watermark(void *obj, void *val) +-{ +- struct cslide_eng_params *params = (struct cslide_eng_params *)obj; +- int wm = parse_to_int(val); +- +- if (wm < MIN_WM || wm > MAX_WM) { +- etmemd_log(ETMEMD_LOG_ERR, "migrate watermark %d invalid\n", wm); +- return -1; +- } +- params->node_watermark = wm; +- return 0; +-} +- + static int fill_hot_threshold(void *obj, void *val) + { + struct cslide_eng_params *params = (struct cslide_eng_params *)obj; +@@ -2112,7 +2034,6 @@ static int fill_mig_quota(void *obj, void *val) + + static struct config_item cslide_eng_config_items[] = { + {"node_pair", STR_VAL, fill_node_pair, false}, +- {"node_watermark", INT_VAL, fill_migrate_watermark, false}, + {"hot_threshold", INT_VAL, fill_hot_threshold, false}, + {"node_mig_quota", INT_VAL, fill_mig_quota, false}, + {"node_hot_reserve", INT_VAL, fill_hot_reserve, false}, +-- +2.27.0 + diff --git a/0032-print-all-log-to-stdout.patch b/0032-print-all-log-to-stdout.patch new file mode 100644 index 0000000..4b28277 --- /dev/null +++ b/0032-print-all-log-to-stdout.patch @@ -0,0 +1,80 @@ +From 3412ce69e8b61ad6d38f3d792930e8f2bafe6f00 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Wed, 12 May 2021 19:50:43 +0800 +Subject: [PATCH 32/50] print all log to stdout + +Signed-off-by: Kemeng Shi +--- + src/etmem_src/etmem.c | 2 +- + src/etmem_src/etmem_project.c | 2 +- + src/etmem_src/etmem_rpc.c | 7 ++++--- + 3 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/src/etmem_src/etmem.c b/src/etmem_src/etmem.c +index 7f04ad1..aadde74 100644 +--- a/src/etmem_src/etmem.c ++++ b/src/etmem_src/etmem.c +@@ -29,7 +29,7 @@ SLIST_HEAD(etmem_obj_list, etmem_obj) g_etmem_objs; + + static void usage(void) + { +- fprintf(stderr, ++ fprintf(stdout, + "\nUsage:\n" + " etmem OBJECT COMMAND\n" + " etmem help\n" +diff --git a/src/etmem_src/etmem_project.c b/src/etmem_src/etmem_project.c +index ef2d8fe..2caaff5 100644 +--- a/src/etmem_src/etmem_project.c ++++ b/src/etmem_src/etmem_project.c +@@ -25,7 +25,7 @@ + + static void project_help(void) + { +- fprintf(stderr, ++ fprintf(stdout, + "\nUsage:\n" + " etmem project start [options]\n" + " etmem project stop [options]\n" +diff --git a/src/etmem_src/etmem_rpc.c b/src/etmem_src/etmem_rpc.c +index 2c70cf8..76a8cf4 100644 +--- a/src/etmem_src/etmem_rpc.c ++++ b/src/etmem_src/etmem_rpc.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include "securec.h" + #include "etmem_rpc.h" + +@@ -71,7 +72,7 @@ static int etmem_client_conn(const struct mem_proj *proj, int sockfd) + + if (connect(sockfd, (struct sockaddr *)&svr_addr, + offsetof(struct sockaddr_un, sun_path) + strlen(proj->sock_name) + 1) < 0) { +- perror("etmem connect to server failed:"); ++ printf("etmem connect to server failed: %s\n", strerror(errno)); + return errno; + } + +@@ -137,7 +138,7 @@ static int etmem_client_send(const struct mem_proj *proj, int sockfd) + } + + if (send(sockfd, reg_cmd, reg_cmd_len, 0) < 0) { +- perror("send failed:"); ++ printf("send failed: %s\n", strerror(errno)); + goto EXIT; + } + ret = 0; +@@ -165,7 +166,7 @@ static int etmem_client_recv(int sockfd) + while (!done) { + recv_size = recv(sockfd, recv_buf, recv_len - 1, 0); + if (recv_size < 0) { +- perror("recv failed:"); ++ printf("recv failed: %s\n", strerror(errno)); + goto EXIT; + } + if (recv_size == 0) { +-- +2.27.0 + diff --git a/0033-accept-review-advise.patch b/0033-accept-review-advise.patch new file mode 100644 index 0000000..a89fd4f --- /dev/null +++ b/0033-accept-review-advise.patch @@ -0,0 +1,49 @@ +From 509a5306e685b18f03eea91d84bf3aa70b8a5c2e Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 13 May 2021 14:20:29 +0800 +Subject: [PATCH 33/50] accept review advise + +Signed-off-by: Kemeng Shi +--- + src/etmem_src/etmem_rpc.c | 2 +- + src/etmemd_src/etmemd_rpc.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/etmem_src/etmem_rpc.c b/src/etmem_src/etmem_rpc.c +index 76a8cf4..384ead1 100644 +--- a/src/etmem_src/etmem_rpc.c ++++ b/src/etmem_src/etmem_rpc.c +@@ -177,7 +177,7 @@ static int etmem_client_recv(int sockfd) + recv_msg = (char *)recv_buf; + recv_msg[recv_size] = '\0'; + +- // check and erease finish flag ++ // check and erase finish flag + switch (recv_msg[recv_size - 1]) { + case (char)SUCCESS_CHAR: + ret = 0; +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index 208f6b5..969d4af 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -546,7 +546,7 @@ static void etmemd_rpc_send_response_msg(int sock_fd, enum opt_result result) + ret = send(sock_fd, g_resp_msg_arr[i].msg, strlen(g_resp_msg_arr[i].msg), 0); + if (ret < 0) { + etmemd_log(ETMEMD_LOG_ERR, "send response to client fail, error(%s)\n", +- strerror(errno)); ++ strerror(errno)); + } + break; + } +@@ -557,7 +557,7 @@ static void etmemd_rpc_send_response_msg(int sock_fd, enum opt_result result) + } else { + finish_tag = FAIL_CHAR; + } +- ret = send(sock_fd, &finish_tag, 1, 0); ++ ret = send(sock_fd, &finish_tag, sizeof(finish_tag), 0); + if (ret <= 0) { + etmemd_log(ETMEMD_LOG_ERR, "send finish tag fail\n"); + } +-- +2.27.0 + diff --git a/0034-fix-open-swap_pages-failure.patch b/0034-fix-open-swap_pages-failure.patch new file mode 100644 index 0000000..026da69 --- /dev/null +++ b/0034-fix-open-swap_pages-failure.patch @@ -0,0 +1,48 @@ +From bcbd8d433b5a0e64d202a781599a691183388024 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Sun, 16 May 2021 16:46:45 +0800 +Subject: [PATCH 34/50] fix open swap_pages failure + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_common.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/src/etmemd_src/etmemd_common.c b/src/etmemd_src/etmemd_common.c +index 07c9e7a..29aa52a 100644 +--- a/src/etmemd_src/etmemd_common.c ++++ b/src/etmemd_src/etmemd_common.c +@@ -239,17 +239,26 @@ FILE *etmemd_get_proc_file(const char *pid, const char *file, int flags, const c + return NULL; + } + +- fd = open(file_name, 0); +- if (fd < 0) { ++ fp = fopen(file_name, mode); ++ if (fp == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "open file %s fail\n", file_name); + goto free_file_name; + } ++ ++ fd = fileno(fp); ++ if (fd < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get fd of file %s fail\n", file_name); ++ fclose(fp); ++ fp = NULL; ++ goto free_file_name; ++ } ++ + if (flags != 0 && ioctl(fd, IDLE_SCAN_ADD_FLAGS, &flags) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "set idle flags for %s fail with %s\n", pid, strerror(errno)); +- close(fd); ++ fclose(fp); ++ fp = NULL; + goto free_file_name; + } +- fp = fdopen(fd, mode); + + free_file_name: + free(file_name); +-- +2.27.0 + diff --git a/0035-give-the-correct-example-of-config-file.patch b/0035-give-the-correct-example-of-config-file.patch new file mode 100644 index 0000000..da5e444 --- /dev/null +++ b/0035-give-the-correct-example-of-config-file.patch @@ -0,0 +1,85 @@ +From d560b00961e95e7eda3840a8189d226b0cbf08d5 Mon Sep 17 00:00:00 2001 +From: louhongxiang +Date: Sat, 15 May 2021 17:29:40 +0800 +Subject: [PATCH 35/50] give the correct example of config file + +--- + conf/example_conf.yaml | 68 ++++++++++++++++++++++++++++++++++-------- + 1 file changed, 56 insertions(+), 12 deletions(-) + +diff --git a/conf/example_conf.yaml b/conf/example_conf.yaml +index 485c35a..de612f6 100644 +--- a/conf/example_conf.yaml ++++ b/conf/example_conf.yaml +@@ -1,12 +1,56 @@ +-options: +-loop : 3 +-interval : 1 +-sleep: 2 +- +-policies: +- type : pid/name +- value : 123456/mysql +- max_threads: 3 +- engine :slide +- param: +- T : 3 ++[project] ++name=test ++loop=1 ++interval=1 ++sleep=1 ++ ++#slide ++[engine] ++name=slide ++project=test ++ ++[task] ++project=test ++engine=slide ++name=background_slide ++type=name ++value=mysql ++T=1 ++max_threads=1 ++ ++#cslide ++[engine] ++name=cslide ++project=test ++node_pair=2,0;3,1 ++hot_threshold=1 ++node_mig_quota=1024 ++node_hot_reserve=1024 ++ ++[task] ++project=test ++engine=cslide ++name=background_cslide ++type=pid ++name=23456 ++vm_flags=ht ++anon_only=no ++ign_host=no ++ ++#thirdparty ++[engine] ++name=thirdparty ++project=test ++eng_name=my_engine ++libname=/usr/lib/etmem_fetch/my_engine.so ++ops_name=my_engine_ops ++engine_private_key=engine_private_value ++ ++[task] ++project=test ++engine=my_engine ++name=backgroud_third ++type=pid ++value=12345 ++task_private_key=task_private_value ++ +-- +2.27.0 + diff --git a/0036-check-if-start_task-is-NULL-before-call-it.patch b/0036-check-if-start_task-is-NULL-before-call-it.patch new file mode 100644 index 0000000..f176250 --- /dev/null +++ b/0036-check-if-start_task-is-NULL-before-call-it.patch @@ -0,0 +1,26 @@ +From 8a66153b5d2094fae65e08418ac3752d868175dc Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Mon, 24 May 2021 20:08:38 +0800 +Subject: [PATCH 36/50] check if start_task is NULL before call it + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_project.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index 3b12296..2e69dd6 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -279,7 +279,7 @@ enum opt_result etmemd_project_add_task(GKeyFile *config) + goto remove_task; + } + +- if (proj->start && eng->ops->start_task(eng, tk) != 0) { ++ if (proj->start && eng->ops->start_task != NULL && eng->ops->start_task(eng, tk) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "start added task %s fail\n", tk->name); + goto clear_task; + } +-- +2.27.0 + diff --git a/0037-correct-max_threads-when-max_threads-is-0.patch b/0037-correct-max_threads-when-max_threads-is-0.patch new file mode 100644 index 0000000..7d2d760 --- /dev/null +++ b/0037-correct-max_threads-when-max_threads-is-0.patch @@ -0,0 +1,26 @@ +From 77d80edcb65316d95f8f09810613ee857dc7f8f9 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Mon, 24 May 2021 20:24:18 +0800 +Subject: [PATCH 37/50] correct max_threads when max_threads is 0 + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_task.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/etmemd_src/etmemd_task.c b/src/etmemd_src/etmemd_task.c +index 01491f7..5aa693b 100644 +--- a/src/etmemd_src/etmemd_task.c ++++ b/src/etmemd_src/etmemd_task.c +@@ -444,7 +444,7 @@ static int fill_task_threads(void *obj, void *val) + int max_threads = parse_to_int(val); + int core; + +- if (max_threads < 0) { ++ if (max_threads <= 0) { + etmemd_log(ETMEMD_LOG_WARN, + "Thread count is abnormal, set the default minimum of current thread count to 1\n"); + max_threads = 1; +-- +2.27.0 + diff --git a/0038-fix-etmem-help-return-error.patch b/0038-fix-etmem-help-return-error.patch new file mode 100644 index 0000000..aeaeba9 --- /dev/null +++ b/0038-fix-etmem-help-return-error.patch @@ -0,0 +1,25 @@ +From d99225f7e64d824b18c95fb475191ea50861169f Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Mon, 24 May 2021 21:17:47 +0800 +Subject: [PATCH 38/50] fix etmem help return error + +Signed-off-by: Kemeng Shi +--- + src/etmem_src/etmem.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/etmem_src/etmem.c b/src/etmem_src/etmem.c +index aadde74..76ea8d2 100644 +--- a/src/etmem_src/etmem.c ++++ b/src/etmem_src/etmem.c +@@ -127,6 +127,7 @@ int main(int argc, char *argv[]) + if (conf.obj != NULL && strcmp(conf.obj, "help") == 0 && + argc == 2) { /* 2 is for param num of "etmem help" */ + err = 0; ++ goto out; + } + err = -EINVAL; + goto out; +-- +2.27.0 + diff --git a/0039-check-if-eng_mgt_func-is-NULL-before-use-it.patch b/0039-check-if-eng_mgt_func-is-NULL-before-use-it.patch new file mode 100644 index 0000000..94f217c --- /dev/null +++ b/0039-check-if-eng_mgt_func-is-NULL-before-use-it.patch @@ -0,0 +1,30 @@ +From 10accbfc9c4d0a7658a333d94f5c3d0f31aeb6e5 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Wed, 26 May 2021 09:15:32 +0800 +Subject: [PATCH 39/50] check if eng_mgt_func is NULL before use it + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_project.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index 2e69dd6..decae76 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -732,6 +732,12 @@ enum opt_result etmemd_project_mgt_engine(const char *project_name, const char * + return OPT_TASK_NOEXIST; + } + } ++ ++ if (eng->ops->eng_mgt_func == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "engine %s does not support eng_mgt_func\n", eng->name); ++ return OPT_INVAL; ++ } ++ + if (eng->ops->eng_mgt_func(eng, tk, cmd, sock_fd) != 0) { + return OPT_INVAL; + } +-- +2.27.0 + diff --git a/0040-make-code-clean-for-etmem.patch b/0040-make-code-clean-for-etmem.patch new file mode 100644 index 0000000..8d17700 --- /dev/null +++ b/0040-make-code-clean-for-etmem.patch @@ -0,0 +1,302 @@ +From 01e8f7ea6c15c12991026a1838ca0573bbf9b910 Mon Sep 17 00:00:00 2001 +From: HukunaMatata +Date: Wed, 26 May 2021 09:45:27 +0800 +Subject: [PATCH 40/50] make code clean for etmem. + +--- + inc/etmemd_inc/etmemd_common.h | 9 ------ + inc/etmemd_inc/etmemd_task_exp.h | 2 +- + src/etmem_src/etmem.c | 2 -- + src/etmem_src/etmem_engine.c | 10 ++----- + src/etmemd_src/etmemd_common.c | 44 ------------------------------ + src/etmemd_src/etmemd_cslide.c | 28 ++++++++++++------- + src/etmemd_src/etmemd_rpc.c | 9 ++++++ + src/etmemd_src/etmemd_scan.c | 1 - + src/etmemd_src/etmemd_thirdparty.c | 7 +++++ + 9 files changed, 38 insertions(+), 74 deletions(-) + +diff --git a/inc/etmemd_inc/etmemd_common.h b/inc/etmemd_inc/etmemd_common.h +index e228476..4127ccf 100644 +--- a/inc/etmemd_inc/etmemd_common.h ++++ b/inc/etmemd_inc/etmemd_common.h +@@ -54,15 +54,6 @@ FILE *etmemd_get_proc_file(const char *pid, const char *file, int flags, const c + + int get_keyword_and_value(const char *str, char *key, char *val); + +-/* function: get the line which has effective content only from the file +- * +- * in: FILE *file - the file to read +- * +- * out: char * - the string with effective content +- * NULL - end of file. +- * */ +-char *skip_blank_line(FILE *file); +- + int dprintf_all(int fd, const char *format, ...); + + #endif +diff --git a/inc/etmemd_inc/etmemd_task_exp.h b/inc/etmemd_inc/etmemd_task_exp.h +index b62f382..33d505a 100644 +--- a/inc/etmemd_inc/etmemd_task_exp.h ++++ b/inc/etmemd_inc/etmemd_task_exp.h +@@ -28,7 +28,7 @@ struct task { + char *type; + char *value; + char *name; +- uint64_t max_threads; ++ int max_threads; + + struct task_pid *pids; + struct engine *eng; +diff --git a/src/etmem_src/etmem.c b/src/etmem_src/etmem.c +index 76ea8d2..f243a75 100644 +--- a/src/etmem_src/etmem.c ++++ b/src/etmem_src/etmem.c +@@ -23,8 +23,6 @@ + #include "etmem_project.h" + #include "etmem_engine.h" + +-#define CMD_POSITION 1 +- + SLIST_HEAD(etmem_obj_list, etmem_obj) g_etmem_objs; + + static void usage(void) +diff --git a/src/etmem_src/etmem_engine.c b/src/etmem_src/etmem_engine.c +index bafcfe6..675c38f 100644 +--- a/src/etmem_src/etmem_engine.c ++++ b/src/etmem_src/etmem_engine.c +@@ -39,11 +39,11 @@ static void engine_help(void) + " 5. eng_cmd is supported by engine own.\n"); + } + +-static int engine_parse_cmd(struct etmem_conf *conf, struct mem_proj *proj) ++static void engine_parse_cmd(struct etmem_conf *conf, struct mem_proj *proj) + { + proj->eng_cmd = conf->argv[0]; + proj->cmd = ETMEM_CMD_ENGINE; +- return 0; ++ return; + } + + static int engine_parse_args(struct etmem_conf *conf, struct mem_proj *proj) +@@ -126,11 +126,7 @@ static int engine_do_cmd(struct etmem_conf *conf) + return ret; + } + +- ret = engine_parse_cmd(conf, &proj); +- if (ret != 0) { +- printf("engine_parse_cmd fail\n"); +- return -1; +- } ++ engine_parse_cmd(conf, &proj); + + ret = engine_parse_args(conf, &proj); + if (ret != 0) { +diff --git a/src/etmemd_src/etmemd_common.c b/src/etmemd_src/etmemd_common.c +index 29aa52a..8aad0eb 100644 +--- a/src/etmemd_src/etmemd_common.c ++++ b/src/etmemd_src/etmemd_common.c +@@ -34,7 +34,6 @@ + + #define IDLE_SCAN_MAGIC 0x66 + #define IDLE_SCAN_ADD_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x0, unsigned int) +-#define IDLE_SCAN_REMOVE_FLAGS _IOW(IDLE_SCAN_MAGIC, 0x1, unsigned int) + + static void usage(void) + { +@@ -360,49 +359,6 @@ int get_keyword_and_value(const char *str, char *key, char *val) + return 0; + } + +-static char *skip_colon_space_and_blank_line(char *str) +-{ +- size_t len; +- +- len = strlen(str); +- while (len-- > 0) { +- if (is_valid_char_for_value(" :\n\t", str[len])) { +- str[len] = '\0'; +- continue; +- } +- +- break; +- } +- +- if (strlen(str) == 0) { +- return ""; +- } +- +- while (is_valid_char_for_value(" \t", *str)) { +- str++; +- } +- +- return str; +-} +- +-char *skip_blank_line(FILE *file) +-{ +- static char line[FILE_LINE_MAX_LEN] = {}; +- char *get_line = NULL; +- +- while (fgets(line, FILE_LINE_MAX_LEN, file) != NULL) { +- get_line = skip_colon_space_and_blank_line(line); +- if (strcmp(get_line, "") != 0) { +- break; +- } +- /* in case the last line is an empty line, +- * make the get_line equals to NULL before next loop begins */ +- get_line = NULL; +- } +- +- return get_line; +-} +- + static int write_all(int fd, const char *buf) + { + ssize_t rest = strlen(buf); +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 745dbcc..a77b7bb 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -33,15 +33,10 @@ + + #define HUGE_1M_SIZE (1 << 20) + #define HUGE_2M_SIZE (2 << 20) +-#define HUGE_1G_SIZE (1 << 30) + #define BYTE_TO_KB(s) ((s) >> 10) + #define KB_TO_BYTE(s) ((s) << 10) + #define HUGE_2M_TO_KB(s) ((s) << 11) + +-#define TO_PCT 100 +-#define MAX_WM 100 +-#define MIN_WM 0 +- + #define BATCHSIZE (1 << 16) + + #define factory_foreach_working_pid_params(iter, factory) \ +@@ -104,7 +99,6 @@ struct cslide_task_params { + struct vma_pf { + struct vma *vma; + struct page_refs *page_refs; +- struct vma_pf *next; + }; + + struct node_pages_info { +@@ -366,7 +360,7 @@ static void npf_setup_tail(struct node_page_refs *npf) + } + } + +-static long long move_npf_to_list(struct node_page_refs *npf, struct page_refs **list, long long size) ++static void move_npf_to_list(struct node_page_refs *npf, struct page_refs **list, long long size) + { + struct page_refs *t = NULL; + struct page_refs *iter = NULL; +@@ -394,7 +388,7 @@ static long long move_npf_to_list(struct node_page_refs *npf, struct page_refs * + } + + npf->size -= moved_size; +- return moved_size; ++ return; + } + + static int init_count_page_refs(struct count_page_refs *cpf, int node_num) +@@ -1702,9 +1696,23 @@ static void cslide_stop_task(struct engine *eng, struct task *tk) + + static char *get_time_stamp(time_t *t) + { +- char *ts = asctime(localtime(t)); +- size_t len = strlen(ts); ++ struct tm *lt = NULL; ++ char *ts = NULL; ++ size_t len; ++ ++ lt = localtime(t); ++ if (lt == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get local time fail\n"); ++ return NULL; ++ } ++ ++ ts = asctime(localtime(t)); ++ if (ts == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "get asctime fail\n"); ++ return NULL; ++ } + ++ len = strlen(ts); + if (ts[len - 1] == '\n') { + ts[len - 1] = '\0'; + } +diff --git a/src/etmemd_src/etmemd_rpc.c b/src/etmemd_src/etmemd_rpc.c +index 969d4af..6b23059 100644 +--- a/src/etmemd_src/etmemd_rpc.c ++++ b/src/etmemd_src/etmemd_rpc.c +@@ -169,12 +169,18 @@ static enum opt_result handle_obj_cmd(char *file_name, enum cmd_type type) + { + GKeyFile *config = NULL; + enum opt_result ret; ++ char resolve_path[PATH_MAX] = {0}; + + if (file_name == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "file name is not set for obj cmd\n"); + return OPT_INVAL; + } + ++ if (realpath(file_name, resolve_path) == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "config file is not a real path(%s)\n", strerror(errno)); ++ return OPT_INVAL; ++ } ++ + config = g_key_file_new(); + if (config == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "get empty config file fail\n"); +@@ -678,14 +684,17 @@ static int rpc_deal_parent(void) + + if ((len = sprintf_s(pid_s, PID_STR_MAX_LEN, "%d", pid)) <= 0) { + etmemd_log(ETMEMD_LOG_ERR, "sprintf for pid failed\n"); ++ close(handle); + exit(1); + } + + if ((write(handle, pid_s, len)) != len) { + etmemd_log(ETMEMD_LOG_ERR, "Error writing to the file\n"); ++ close(handle); + exit(1); + } + ++ close(handle); + close(g_fd[1]); + if (read(g_fd[0], &val, sizeof(val)) <= 0) { + etmemd_log(ETMEMD_LOG_ERR, "Error reading to the file\n"); +diff --git a/src/etmemd_src/etmemd_scan.c b/src/etmemd_src/etmemd_scan.c +index c287c48..1cafaed 100644 +--- a/src/etmemd_src/etmemd_scan.c ++++ b/src/etmemd_src/etmemd_scan.c +@@ -32,7 +32,6 @@ + #define PUD_SIZE_SHIFT 30 + #define HEXADECIMAL_RADIX 16 + #define PMD_IDLE_PTES_PARAMETER 512 +-#define VMFLAG_MAX_LEN 100 + #define VMFLAG_MAX_NUM 30 + #define VMFLAG_VALID_LEN 2 + +diff --git a/src/etmemd_src/etmemd_thirdparty.c b/src/etmemd_src/etmemd_thirdparty.c +index 53d4b8e..8d1b50e 100644 +--- a/src/etmemd_src/etmemd_thirdparty.c ++++ b/src/etmemd_src/etmemd_thirdparty.c +@@ -83,6 +83,13 @@ static int set_engine_ops(struct engine *eng, struct thirdparty_params *params) + void *handler = NULL; + struct engine_ops *ops = NULL; + char *err = NULL; ++ char resolve_path[PATH_MAX] = {0}; ++ ++ if (realpath(params->libname, resolve_path) == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "file of thirdparty libname %s is not a real path(%s)\n", ++ params->libname, strerror(errno)); ++ return -1; ++ } + + handler = dlopen(params->libname, RTLD_NOW | RTLD_LOCAL); + err = dlerror(); +-- +2.27.0 + diff --git a/0041-return-error-if-migrate-failed-and-clean-code.patch b/0041-return-error-if-migrate-failed-and-clean-code.patch new file mode 100644 index 0000000..aaac650 --- /dev/null +++ b/0041-return-error-if-migrate-failed-and-clean-code.patch @@ -0,0 +1,64 @@ +From 8945313183ecfd752c4d8fbd5d8e5e464bd9ed37 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Wed, 26 May 2021 19:57:09 +0800 +Subject: [PATCH 41/50] return error if migrate failed and clean code + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 14 ++++++++++---- + src/etmemd_src/etmemd_scan.c | 3 --- + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index 745dbcc..3a30d6b 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -1445,21 +1445,27 @@ static int cslide_do_migrate(struct cslide_eng_params *eng_params) + struct cslide_pid_params *iter = NULL; + struct node_pair *pair = NULL; + int bind_node, i; ++ int ret = 0; + + factory_foreach_working_pid_params(iter, &eng_params->factory) { + for (i = 0; i < eng_params->node_map.cur_num; i++) { + pair = &eng_params->node_map.pair[i]; + bind_node = pair->hot_node < pair->cold_node ? pair->hot_node : pair->cold_node; + if (numa_run_on_node(bind_node) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "fail to run on node %d to migrate memory\n", bind_node); ++ etmemd_log(ETMEMD_LOG_INFO, "fail to run on node %d to migrate memory\n", bind_node); ++ } ++ ret = migrate_single_task(iter->pid, &iter->memory_grade[i], pair->hot_node, pair->cold_node); ++ if (ret != 0) { ++ goto exit; + } +- migrate_single_task(iter->pid, &iter->memory_grade[i], pair->hot_node, pair->cold_node); + } + } ++ ++exit: + if (numa_run_on_node(-1) != 0) { +- etmemd_log(ETMEMD_LOG_ERR, "fail to run on all node after migrate memory\n"); ++ etmemd_log(ETMEMD_LOG_INFO, "fail to run on all node after migrate memory\n"); + } +- return 0; ++ return ret; + } + + static void init_host_pages_info(struct cslide_eng_params *eng_params) +diff --git a/src/etmemd_src/etmemd_scan.c b/src/etmemd_src/etmemd_scan.c +index c287c48..ed17d2b 100644 +--- a/src/etmemd_src/etmemd_scan.c ++++ b/src/etmemd_src/etmemd_scan.c +@@ -27,9 +27,6 @@ + #include "etmemd_log.h" + #include "securec.h" + +-#define PTE_SIZE_SHIFT 12 +-#define PMD_SIZE_SHIFT 21 +-#define PUD_SIZE_SHIFT 30 + #define HEXADECIMAL_RADIX 16 + #define PMD_IDLE_PTES_PARAMETER 512 + #define VMFLAG_MAX_NUM 30 +-- +2.27.0 + diff --git a/0042-etmemd-fix-memleak-and-clean-code.patch b/0042-etmemd-fix-memleak-and-clean-code.patch new file mode 100644 index 0000000..ff3a224 --- /dev/null +++ b/0042-etmemd-fix-memleak-and-clean-code.patch @@ -0,0 +1,59 @@ +From bc6ed8fe0b2691b92f0d508d73e1b903aee5fd63 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Thu, 27 May 2021 14:42:55 +0800 +Subject: [PATCH 42/50] etmemd: fix memleak and clean code + +1.detach cslide main thread to release resource when exit +2.clean code + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_cslide.c | 6 +++++- + src/etmemd_src/etmemd_task.c | 7 ++++++- + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/etmemd_src/etmemd_cslide.c b/src/etmemd_src/etmemd_cslide.c +index d1dd06c..ad3eff8 100644 +--- a/src/etmemd_src/etmemd_cslide.c ++++ b/src/etmemd_src/etmemd_cslide.c +@@ -1606,6 +1606,10 @@ static void *cslide_main(void *arg) + struct cslide_eng_params *eng_params = (struct cslide_eng_params *)arg; + struct sys_mem *mem = NULL; + ++ // only invalid pthread id or deatch more than once will cause error ++ // so no need to check return value of pthread_detach ++ (void)pthread_detach(pthread_self()); ++ + while (true) { + factory_update_pid_params(&eng_params->factory); + if (eng_params->finish) { +@@ -1712,7 +1716,7 @@ static char *get_time_stamp(time_t *t) + return NULL; + } + +- ts = asctime(localtime(t)); ++ ts = asctime(lt); + if (ts == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "get asctime fail\n"); + return NULL; +diff --git a/src/etmemd_src/etmemd_task.c b/src/etmemd_src/etmemd_task.c +index 5aa693b..618245e 100644 +--- a/src/etmemd_src/etmemd_task.c ++++ b/src/etmemd_src/etmemd_task.c +@@ -58,7 +58,12 @@ static int get_pid_through_pipe(char *arg_pid[], const int *pipefd) + return -1; + } + +- execve(arg_pid[0], arg_pid, NULL); ++ if (execve(arg_pid[0], arg_pid, NULL) == -1) { ++ etmemd_log(ETMEMD_LOG_ERR, "execve %s fail with %s.\n", arg_pid[0], strerror(errno)); ++ close(pipefd[1]); ++ return -1; ++ } ++ + if (fflush(stdout) != 0) { + etmemd_log(ETMEMD_LOG_ERR, "fflush execve stdout fail.\n"); + close(pipefd[1]); +-- +2.27.0 + diff --git a/0043-update-README.md.patch b/0043-update-README.md.patch new file mode 100644 index 0000000..5b60157 --- /dev/null +++ b/0043-update-README.md.patch @@ -0,0 +1,575 @@ +From a70963f9e9d030a08b6b716c8cbd9826c8ba25bc Mon Sep 17 00:00:00 2001 +From: shikemeng +Date: Tue, 10 Aug 2021 02:22:02 +0000 +Subject: [PATCH 43/50] =?UTF-8?q?update=20README.md.=20=E6=9B=B4=E6=96=B0?= + =?UTF-8?q?=E4=BA=8C=E8=BF=9B=E5=88=B6=E5=90=AF=E5=8A=A8=EF=BC=8C=E9=85=8D?= + =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6=E8=AF=B4=E6=98=8E=EF=BC=8C=E5=B7=A5?= + =?UTF-8?q?=E7=A8=8B=E5=88=9B=E5=BB=BA=EF=BC=8C=E5=88=A0=E9=99=A4=EF=BC=8C?= + =?UTF-8?q?=E5=90=AF=E5=8A=A8=EF=BC=8C=E5=81=9C=E6=AD=A2=EF=BC=8C=E6=9F=A5?= + =?UTF-8?q?=E8=AF=A2=E7=9A=84=E7=AB=A0=E8=8A=82=E3=80=82=20=E6=96=B0?= + =?UTF-8?q?=E5=A2=9Eetmem=E6=94=AF=E6=8C=81=E9=9A=8F=E7=B3=BB=E7=BB=9F?= + =?UTF-8?q?=E5=90=AF=E5=8A=A8=EF=BC=8Cetmem=E6=94=AF=E6=8C=81=E7=AC=AC?= + =?UTF-8?q?=E4=B8=89=E6=96=B9=E5=86=85=E5=AD=98=E6=89=A9=E5=B1=95=E7=AD=96?= + =?UTF-8?q?=E7=95=A5=EF=BC=8Cetmem=E6=94=AF=E6=8C=81=E4=BD=BF=E7=94=A8AEP?= + =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=86=85=E5=AD=98=E6=89=A9=E5=B1=95=E7=9A=84?= + =?UTF-8?q?=E7=AB=A0=E8=8A=82=E3=80=82?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + README.md | 457 +++++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 366 insertions(+), 91 deletions(-) + +diff --git a/README.md b/README.md +index 3e2a50a..93631a1 100644 +--- a/README.md ++++ b/README.md +@@ -43,18 +43,22 @@ $ etmemd -l 0 -s etmemd_socket + + options: + +--l|--log-level Log level +--s|--socket Socket name to listen to +--h|--help Show this message ++-l|\-\-log-level Log level ++ ++-s|\-\-socket Socket name to listen to ++ ++-h|\-\-help Show this message ++ ++-m|\-\-mode-systemctl mode used to start(systemctl) + + #### 命令行参数说明 + + | 参数 | 参数含义 | 是否必须 | 是否有参数 | 参数范围 | 示例说明 | + | --------------- | ---------------------------------- | -------- | ---------- | --------------------- | ------------------------------------------------------------ | +-| -l或--log-level | etmemd日志级别 | 否 | 是 | 0~3 | 0:debug级别 1:info级别 2:warning级别 3:error级别 只有大于等于配置的级别才会打印到/var/log/message文件中 | +-| -s或--socket | etmemd监听的名称,用于与客户端交互 | 是 | 是 | 107个字符之内的字符串 | 指定服务端监听的名称 | +-| -h或--help | 帮助信息 | 否 | 否 | NA | 执行时带有此参数会打印后退出 | +- ++| -l或\-\-log-level | etmemd日志级别 | 否 | 是 | 0~3 | 0:debug级别 1:info级别 2:warning级别 3:error级别 只有大于等于配置的级别才会打印到/var/log/message文件中 | ++| -s或\-\-socket | etmemd监听的名称,用于与客户端交互 | 是 | 是 | 107个字符之内的字符串 | 指定服务端监听的名称 | ++| -h或\-\-help | 帮助信息 | 否 | 否 | NA | 执行时带有此参数会打印后退出 | ++| -m或\-\-mode-systemctl| etmemd作为service被拉起时,命令中可以使用此参数来支持fork模式启动| 否| 否| NA| NA| + ### etmem配置文件 + + 在运行etmem进程之前,需要管理员预先规划哪些进程需要做内存扩展,将进程信息配置到etmem配置文件中,并配置内存扫描的周期、扫描次数、内存冷热阈值等信息。 +@@ -62,158 +66,429 @@ options: + 配置文件的示例文件在源码包中,放置在源码根目录的conf/example_conf.yaml,建议在使用时放置在/etc/etmem/目录下,示例内容为: + + ``` +-options: +- loop : 3 +- interval : 1 +- sleep: 2 +- policies: +- type : pid/name +- value : 123456/mysql +- max_threads: 3 +- engine : slide +- param: +- T: 3 ++[project] ++name=test ++loop=1 ++interval=1 ++sleep=1 ++ ++#slide引擎示例 ++[engine] ++name=slide ++project=test ++ ++[task] ++project=test ++engine=slide ++name=background_slide ++type=name ++value=mysql ++T=1 ++max_threads=1 ++ ++#cslide引擎示例 ++[engine] ++name=cslide ++project=test ++node_pair=2,0;3,1 ++hot_threshold=1 ++node_mig_quota=1024 ++node_hot_reserve=1024 ++ ++[task] ++project=test ++engine=cslide ++name=background_cslide ++type=pid ++name=23456 ++vm_flags=ht ++anon_only=no ++ign_host=no ++ ++#thirdparty引擎示例 ++[engine] ++name=thirdparty ++project=test ++eng_name=my_engine ++libname=/usr/lib/etmem_fetch/my_engine.so ++ops_name=my_engine_ops ++engine_private_key=engine_private_value ++ ++[task] ++project=test ++engine=my_engine ++name=backgroud_third ++type=pid ++value=12345 ++task_private_key=task_private_value + ``` + + 配置文件各字段说明: + +-| **置项** | **配置项含义** | **是否必须** | **是否有参数** | **参数范围** | **示例说明** | +-| ----------- | ------------------------------------------------------------ | ------------ | -------------- | ------------------------- | ------------------------------------------------------------ | +-| options | project公用配置段起始标识 | 是 | 否 | NA | 每个配置文件有且仅有一个此字段,并且文件以此字段开始 | +-| loop | 内存扫描的循环次数 | 是 | 是 | 1~120 | loop:3 //扫描3次 | +-| interval | 每次内存扫描的时间间隔 | 是 | 是 | 1~1200 | interval:5 //每次扫描之间间隔5s | +-| sleep | 每个内存扫描+操作的大周期之间时间间隔 | 是 | 是 | 1~1200 | sleep:10 //每次大周期之间间隔10s | +-| policies | project中各task任务配置段起始标识 | 是 | 否 | NA | 一个project中可以配置多个task,每个task以policies:开头 | +-| type | 目标进程识别的方式 | 是 | 是 | pid/name | pid代表通过进程号识别,name代表通过进程名称识别 | +-| value | 目标进程识别的具体字段 | 是 | 是 | 实际的进程号/进程名称 | 与type字段配合使用,指定目标进程的进程号或进程名称,由使用者保证配置的正确及唯一性 | +-| max_threads | etmemd内部线程池最大线程数,每个线程处理一个进程/子进程的内存扫描+操作任务 | 否 | 是 | 1~2 * core数 + 1,默认为1 | 对外部无表象,控制etmemd服务端内部处理线程个数,当目标进程有多个子进程时,配置越大,并发执行的个数也多,但占用资源也越多 | +-| engine | 扫描引擎类型 | 是 | 是 | slide | 声明使用slide引擎进行冷热内存识别 | +-| param | 扫描引擎私有参数配置起始标识 | 是 | 否 | NA | 引擎私有参数配置段以此标识起始,每个task对应一种引擎,每个引擎对应一个param及其字段 | +-| T | slide引擎的水线配置 | 是 | 否 | 1~3 * loop | 水线阈值,大于等于此值的内存会被识别为热内存,反之为冷内存 | +- +-### etmem工程创建/删除/查询 ++| 配置项 | 配置项含义 | 是否必须 | 是否有参数 | 参数范围 | 示例说明 | ++|-----------|---------------------|------|-------|------------|-----------------------------------------------------------------| ++| [project] | project公用配置段起始标识 | 否 | 否 | NA | project参数的开头标识,表示下面的参数直到另外的[xxx]或文件结尾为止的范围内均为project section的参数 | ++| name | project的名字 | 是 | 是 | 64个字以内的字符串 | 用来标识project,engine和task在配置时需要指定要挂载到的project | ++| loop | 内存扫描的循环次数 | 是 | 是 | 1~10 | loop=3 //扫描3次 | ++| interval | 每次内存扫描的时间间隔 | 是 | 是 | 1~1200 | interval=5 //每次扫描之间间隔5s | ++| sleep | 每个内存扫描+操作的大周期之间时间间隔 | 是 | 是 | 1~1200 | sleep=10 //每次大周期之间间隔10s | ++| [engine] | engine公用配置段起始标识 | 否 | 否 | NA | engine参数的开头标识,表示下面的参数直到另外的[xxx]或文件结尾为止的范围内均为engine section的参数 | ++| project | 声明所在的project | 是 | 是 | 64个字以内的字符串 | 已经存在名字为test的project,则可以写为project=test | ++| engine | 声明所在的engine | 是 | 是 | slide/cslide/thridparty | 声明使用的是slide或cslide或thirdparty策略 | ++| node_pair | cslide engine的配置项,声明系统中AEP和DRAM的node pair | engine为cslide时必须配置 | 是 | 成对配置AEP和DRAM的node号,AEP和DRAM之间用逗号隔开,没对pair之间用分号隔开 | node_pair=2,0;3,1 | ++| hot_threshold | cslide engine的配置项,声明内存冷热水线的阈值 | engine为cslide时必须配置 | 是 | >= 0的整数 | hot_threshold=3 //访问次数小于3的内存会被识别为冷内存 | ++|node_mig_quota|cslide engine的配置项,流控,声明每次DRAM和AEP互相迁移时单向最大流量|engine为cslide时必须配置|是|>= 0的整数|node_mig_quota=1024 //单位为MB,AEP到DRAM或DRAM到AEP搬迁一次最大1024M| ++|node_hot_reserve|cslide engine的配置项,声明DRAM中热内存的预留空间大小|engine为cslide时必须配置|是|>= 0的整数|node_hot_reserve=1024 //单位为MB,当所有虚拟机热内存大于此配置值时,热内存也会迁移到AEP中| ++|eng_name|thirdparty engine的配置项,声明engine自己的名字,供task挂载|engine为thirdparty时必须配置|是|64个字以内的字符串|eng_name=my_engine //对此第三方策略engine挂载task时,task中写明engine=my_engine| ++|libname|thirdparty engine的配置项,声明第三方策略的动态库的地址,绝对地址|engine为thirdparty时必须配置|是|64个字以内的字符串|libname=/user/lib/etmem_fetch/code_test/my_engine.so| ++|ops_name|thirdparty engine的配置项,声明第三方策略的动态库中操作符号的名字|engine为thirdparty时必须配置|是|64个字以内的字符串|ops_name=my_engine_ops //第三方策略实现接口的结构体的名字| ++|engine_private_key|thirdparty engine的配置项,预留给第三方策略自己解析私有参数的配置项,选配|否|否|根据第三方策略私有参数自行限制|根据第三方策略私有engine参数自行配置| ++| [task] | task公用配置段起始标识 | 否 | 否 | NA | task参数的开头标识,表示下面的参数直到另外的[xxx]或文件结尾为止的范围内均为task section的参数 | ++| project | 声明所挂的project | 是 | 是 | 64个字以内的字符串 | 已经存在名字为test的project,则可以写为project=test | ++| engine | 声明所挂的engine | 是 | 是 | 64个字以内的字符串 | 所要挂载的engine的名字 | ++| name | task的名字 | 是 | 是 | 64个字以内的字符串 | name=background1 //声明task的名字是backgound1 | ++| type | 目标进程识别的方式 | 是 | 是 | pid/name | pid代表通过进程号识别,name代表通过进程名称识别 | ++| value | 目标进程识别的具体字段 | 是 | 是 | 实际的进程号/进程名称 | 与type字段配合使用,指定目标进程的进程号或进程名称,由使用者保证配置的正确及唯一性 | ++| T | engine为slide的task配置项,声明内存冷热水线的阈值 | engine为slide时必须配置 | 是 | 0~loop * 3 | T=3 //访问次数小于3的内存会被识别为冷内存 | ++| max_threads | engine为slide的task配置项,etmemd内部线程池最大线程数,每个线程处理一个进程/子进程的内存扫描+操作任务 | 否 | 是 | 1~2 * core数 + 1,默认为1 | 对外部无表象,控制etmemd服务端内部处理线程个数,当目标进程有多个子进程时,配置越大,并发执行的个数也多,但占用资源也越多 | ++| vm_flags | engine为cslide的task配置项,通过指定flag扫描的vma,不配置此项时扫描则不会区分 | engine为cslide时必须配置 | 是 | 当前只支持ht | vm_flags=ht //扫描flags为ht(大页)的vma内存 | ++| anon_only | engine为cslide的task配置项,标识是否只扫描匿名页 | 否 | 是 | yes/no | anon_only=no //配置为yes时只扫描匿名页,配置为no时非匿名页也会扫描 | ++| ign_host | engine为cslide的task配置项,标识是否忽略host上的页表扫描信息 | 否 | 是 | yes/no | ign_host=no //yes为忽略,no为不忽略 | ++| task_private_key | engine为thirdparty的task配置项,预留给第三方策略的task解析私有参数的配置项,选配 | 否 | 否 | 根据第三方策略私有参数自行限制 | 根据第三方策略私有task参数自行配置 | ++ ++ ++ ++### etmem project/engine/task对象的创建和删除 + + #### 场景描述 + +-1)管理员创建etmem工程(一个工程可包含多个etmem任务) +- +-2)管理员查询已有的etmem工程 ++1)管理员创建etmem的project/engine/task(一个工程可包含多个etmem engine,一个engine可以包含多个任务) + +-3)管理员删除已有的etmem工程(删除工程前,会自动先停止该工程中的所有任务) ++2)管理员删除已有的etmem project/engine/task(删除工程前,会自动先停止该工程中的所有任务) + + #### 使用方法 + +-通过etmem二进制执行工程创建/删除/查询操作,前提是服务端已经成功运行,并且配置文件(e.g. /etc/etmem/example_conf.yaml)内容正确。 ++运行etmem二进制,通过第二个参数指定为obj,来进行创建或删除动作,对project/engine/task则是通过配置文件中配置的内容来进行识别和区分。前提是etmem配置文件已配置正确,etmemd进程已启动。 + +-添加工程: ++添加对象: + +-etmem project add -n test -f /etc/etmem/example_conf.yaml -s etmemd_socket ++etmem obj add -f /etc/example_config.yaml -s etmemd_socket + +-删除工程: ++删除对象: + +-etmem project del -n test -s etmemd_socket +- +-查询工程: +- +-etmem project show -s etmemd_socket ++etmem obj del -f /etc/example_config.yaml -s etmemd_socket + + 打印帮助: + +-etmem project help ++etmem obj help + + #### 帮助信息 + + Usage: +- etmem project add [options] +- etmem project del [options] +- etmem project show +- etmem project help + +- Options: +- -f|--file Add configuration file +- -n|--name Add project name +- -s|--sock Socket name to connect ++etmem obj add [options] + +- Notes: +- \1. Project name and socket name must be given when execute add or del option. +- \2. Configuration file must be given when execute add option. +- \3. Socket name must be given when execute show option. ++etmem obj del [options] + +-#### 命令行参数说明 ++etmem obj help + +-add命令: ++Options: + +-| 参数 | 参数含义 | 是否必须 | 是否有参数 | 示例说明 | +-| ------------ | ------------------------------------------------------------ | -------- | ---------- | -------------------------------------------------------- | +-| -n或--name | 指定project名称 | 是 | 是 | project名称,与配置文件一一对应 | +-| -f或--file | 指定project的配置文件 | 是 | 是 | 需要指定路径名称 | +-| -s或--socket | 与etmemd服务端通信的socket名称,需要与etmemd启动时指定的保持一致 | 是 | 是 | 必须配置,在有多个etmemd时,由管理员选择与哪个etmemd通信 | ++-f|\-\-file Add configuration file + +-del命令: ++-s|\-\-socket Socket name to connect + +-| 参数 | 参数含义 | 是否必须 | 是否有参数 | 示例说明 | +-| ------------ | ------------------------------------------------------------ | -------- | ---------- | -------------------------------------------------------- | +-| -n或--name | 指定project名称 | 是 | 是 | project名称,与配置文件一一对应 | +-| -s或--socket | 与etmemd服务端通信的socket名称,需要与etmemd启动时指定的保持一致 | 是 | 是 | 必须配置,在有多个etmemd时,由管理员选择与哪个etmemd通信 | ++Notes: ++ ++1. Configuration file must be given. ++ ++#### 命令行参数说明 + +-show命令: + + | 参数 | 参数含义 | 是否必须 | 是否有参数 | 示例说明 | + | ------------ | ------------------------------------------------------------ | -------- | ---------- | -------------------------------------------------------- | +-| -s或--socket | 与etmemd服务端通信的socket名称,需要与etmemd启动时指定的保持一致 | 是 | 是 | 必须配置,在有多个etmemd时,由管理员选择与哪个etmemd通信 | ++| -f或\-\-file | 指定对象的配置文件 | add,del子命令必须包含 | 是 | 需要指定路径名称 | ++| -s或\-\-socket | 与etmemd服务端通信的socket名称,需要与etmemd启动时指定的保持一致 | add,del子命令必须包含 | 是 | 必须配置,在有多个etmemd时,由管理员选择与哪个etmemd通信 | + +-### etmem任务启动/停止 ++### etmem任务启动/停止/查询 + + #### 场景描述 + +-在已经通过etmem project add添加工程之后,在还未调用etmem project del删除工程之前,可以对etmem的工程进行启动和停止。 ++在已经通过etmem obj add添加工程之后,在还未调用etmem obj del删除工程之前,可以对etmem的工程进行启动和停止。 + + 1)管理员启动已添加的工程 + + 2)管理员停止已启动的工程 + +-在管理员调用project del删除工程时,如果工程已经启动,则会自动停止。 ++在管理员调用obj del删除工程时,如果工程已经启动,则会自动停止。 + + #### 使用方法 + +-通过etmem二进制执行任务启动/停止操作,前提是服务端已经成功运行,配置文件(e.g. /etc/etmem/example_conf.yaml)内容正确,且etmem工程已经创建。 ++对于已经添加成功的工程,可以通过etmem project的命令来控制工程的启动和停止,命令示例如下: + + 启动工程 + +-etmem migrate start -n test -s etmemd_socket ++etmem project start -n test -s etmemd_socket + + 停止工程 + +-etmem migrate stop -n test -s etmemd_socket ++etmem project stop -n test -s etmemd_socket ++ ++查询工程 ++ ++etmem project show -n test -s etmemd_socket + + 打印帮助 + +-etmem migrate help ++etmem project help + + #### 帮助信息 + + Usage: +- etmem migrate start [options] +- etmem migrate stop [options] +- etmem migrate help + +- Options: +- -n|--name Add project name +- -s|--sock Socket name to connect ++etmem project start [options] ++ ++etmem project stop [options] ++ ++etmem project show [options] ++ ++etmem project help ++ ++Options: ++ ++-n|\-\-name Add project name ++ ++-s|\-\-socket Socket name to connect ++ ++Notes: + +- Notes: +- Project name and socket name must be given when execute start or stop option. ++1. Project name and socket name must be given when execute add or del option. ++ ++2. Socket name must be given when execute show option. + + #### 命令行参数说明 + + | 参数 | 参数含义 | 是否必须 | 是否有参数 | 示例说明 | + | ------------ | ------------------------------------------------------------ | -------- | ---------- | -------------------------------------------------------- | +-| -n或--name | 指定project名称 | 是 | 是 | project名称,与配置文件一一对应 | +-| -s或--socket | 与etmemd服务端通信的socket名称,需要与etmemd启动时指定的保持一致 | 是 | 是 | 必须配置,在有多个etmemd时,由管理员选择与哪个etmemd通信 | ++| -n或\-\-name | 指定project名称 | start,stop,show子命令必须包含 | 是 | project名称,与配置文件一一对应 | ++| -s或\-\-socket | 与etmemd服务端通信的socket名称,需要与etmemd启动时指定的保持一致 | start,stop,show子命令必须包含 | 是 | 必须配置,在有多个etmemd时,由管理员选择与哪个etmemd通信 | ++ ++### etmem支持随系统自启动 ++ ++#### 场景描述 ++ ++etmemd支持由用户配置systemd配置文件后,以fork模式作为systemd服务被拉起运行 ++ ++#### 使用方法 ++ ++编写service配置文件,来启动etmemd,必须使用-m参数来指定此模式,例如 ++ ++etmemd -l 0 -s etmemd_socket -m ++ ++#### 帮助信息 ++ ++options: ++ ++-l|\-\-log-level Log level ++ ++-s|\-\-socket Socket name to listen to ++ ++-m|\-\-mode-systemctl mode used to start(systemctl) ++ ++-h|\-\-help Show this message ++ ++#### 命令行参数说明 ++| 参数 | 参数含义 | 是否必须 | 是否有参数 | 参数范围 | 实例说明 | ++|----------------|------------|------|-------|------|-----------| ++| -l或\-\-log-level | etmemd日志级别 | 否 | 是 | 0~3 | 0:debug级别;1:info级别;2:warning级别;3:error级别;只有大于等于配置的级别才会打印到/var/log/message文件中| ++| -s或\-\-socket |etmemd监听的名称,用于与客户端交互 | 是 | 是| 107个字符之内的字符串| 指定服务端监听的名称| ++|-m或\-\-mode-systemctl | etmemd作为service被拉起时,命令中需要指定此参数来支持 | 否 | 否 | NA | NA | ++| -h或\-\-help | 帮助信息 | 否 |否 |NA |执行时带有此参数会打印后退出| ++ ++ ++ ++ ++### etmem支持第三方内存扩展策略 ++ ++#### 场景描述 ++ ++etmem支持用户注册第三方内存扩展策略,同时提供扫描模块动态库,运行时通过第三方策略淘汰算法淘汰内存。 ++ ++用户使用etmem所提供的扫描模块动态库并实现对接etmem所需要的结构体中的接口 ++ ++#### 使用方法 ++ ++用户使用自己实现的第三方扩展淘汰策略,主要需要按下面步骤进行实现和操作: ++ ++1. 按需调用扫描模块提供的扫描接口, ++ ++2. 按照etmem头文件中提供的函数模板来实现各个接口,最终封装成结构体 ++ ++3. 编译出第三方扩展淘汰策略的动态库 ++ ++4. 在配置文件中按要求声明类型为thirdparty的engine ++ ++5. 将动态库的名称和接口结构体的名称按要求填入配置文件中task对应的字段 ++ ++其他操作步骤与使用etmem的其他engine类似 ++ ++接口结构体模板 ++ ++struct engine_ops { ++ ++/* 针对引擎私有参数的解析,如果有,需要实现,否则置NULL */ ++ ++int (*fill_eng_params)(GKeyFile *config, struct engine *eng); ++ ++/* 针对引擎私有参数的清理,如果有,需要实现,否则置NULL */ ++ ++void (*clear_eng_params)(struct engine *eng); ++ ++/* 针对任务私有参数的解析,如果有,需要实现,否则置NULL */ ++ ++int (*fill_task_params)(GKeyFile *config, struct task *task); ++ ++/* 针对任务私有参数的清理,如果有,需要实现,否则置NULL */ ++ ++void (*clear_task_params)(struct task *tk); ++ ++/* 启动任务的接口 */ ++ ++int (*start_task)(struct engine *eng, struct task *tk); ++ ++/* 停止任务的接口 */ ++ ++void (*stop_task)(struct engine *eng, struct task *tk); ++ ++/* 填充pid相关私有参数 */ ++ ++int (*alloc_pid_params)(struct engine *eng, struct task_pid **tk_pid); ++ ++/* 销毁pid相关私有参数 */ ++ ++void (*free_pid_params)(struct engine *eng, struct task_pid **tk_pid); ++ ++/* 第三方策略自身所需要的私有命令支持,如果没有,置为NULL */ ++ ++int (*eng_mgt_func)(struct engine *eng, struct task *tk, char *cmd, int fd); ++ ++}; ++ ++配置文件示例如下所示,具体含义请参考配置文件说明章节: ++ ++#thirdparty ++ ++[engine] ++ ++name=thirdparty ++ ++project=test ++ ++eng_name=my_engine ++ ++libname=/user/lib/etmem_fetch/code_test/my_engine.so ++ ++ops_name=my_engine_ops ++ ++engine_private_key=engine_private_value ++ ++[task] ++ ++project=test ++ ++engine=my_engine ++ ++name=background1 ++ ++type=pid ++ ++value=1798245 ++ ++task_private_key=task_private_value ++ ++ **注意** : ++ ++用户需使用etmem所提供的扫描模块动态库并实现对接etmem所需要的结构体中的接口 ++ ++eng_mgt_func接口中的fd不能写入0xff和0xfe字 ++ ++支持在一个工程内添加多个不同的第三方策略动态库,以配置文件中的eng_name来区分 ++ ++### etmem支持使用AEP进行内存扩展 ++ ++#### 场景描述 ++ ++使用etmem组件包,使能内存分级扩展至AEP的通路。 ++ ++在节点内对虚拟机的大页进行扫描,并通过cslide引擎进行策略淘汰,将冷内存搬迁至AEP中 ++ ++#### 使用方法 ++ ++使用cslide引擎进行内存扩展,参数示例如下,具体参数含义请参考配置文件说明章节 ++ ++#cslide ++ ++[engine] ++ ++name=cslide ++ ++project=test ++ ++node_pair=2,0;3,1 ++ ++hot_threshold=1 ++ ++node_mig_quota=1024 ++ ++node_hot_reserve=1024 ++ ++[task] ++ ++project=test ++ ++engine=cslide ++ ++name=background1 ++ ++type=pid ++ ++value=1823197 ++ ++vm_flags=ht ++ ++anon_only=no ++ ++ign_host=no ++ ++ **注意** :禁止并发扫描同一个进程 ++ ++同时,此cslide策略支持私有的命令 ++ ++ ++- showtaskpages ++- showhostpages ++ ++针对使用此策略引擎的engine和engine所有的task,可以通过这两个命令分别查看task相关的页面访问情况和虚拟机的host上系统大页的使用情况。 ++ ++示例命令如下: ++ ++etmem engine showtaskpages <-t task_name> -n proj_name -e cslide -s etmemd_socket ++ ++etmem engine showhostpages -n proj_name -e cslide -s etmemd_socket ++ ++ **注意** :showtaskpages和showhostpages仅支持引擎使用cslide的场景 ++ ++#### 命令行参数说明 ++| 参数 | 参数含义 | 是否必须 | 是否有参数 | 实例说明 | ++|----|------|------|-------|------| ++|-n或\-\-proj_name| 指定project的名字| 是| 是| 指定已经存在,所需要执行的project的名字| ++|-s或\-\-socket| 与etmemd服务端通信的socket名称,需要与etmemd启动时指定的保持一致| 是| 是| 必须配置,在有多个etmemd时,由管理员选择与哪个etmemd通信| ++|-e或\-\-engine| 指定执行的引擎的名字| 是| 是| 指定已经存在的,所需要执行的引擎的名字| ++|-t或\-\-task_name| 指定执行的任务的名字| 否| 是| 指定已经存在的,所需要执行的任务的名字| + + ## 参与贡献 + + 1. Fork本仓库 + 2. 新建个人分支 + 3. 提交代码 +-4. 新建Pull Request ++4. 新建Pull Request +\ No newline at end of file +-- +2.27.0 + diff --git a/0044-etmem-cleancode.patch b/0044-etmem-cleancode.patch new file mode 100644 index 0000000..8cbfdcb --- /dev/null +++ b/0044-etmem-cleancode.patch @@ -0,0 +1,55 @@ +From 85a0e330d50c1546805c68cd621d1d85b5d08489 Mon Sep 17 00:00:00 2001 +From: Kemeng Shi +Date: Tue, 10 Aug 2021 11:13:06 +0800 +Subject: [PATCH 44/50] etmem: cleancode + +1. group_name for task_of_group and engine_of_group is defined as const, so add const +to group_name in function definition +2. pagesize in init_g_page_size is assigned with a value following init_g_page_size +assigned with initial value -1. Remove redundant initialization. + +Signed-off-by: Kemeng Shi +--- + src/etmemd_src/etmemd_project.c | 5 +++-- + src/etmemd_src/etmemd_scan.c | 2 +- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index decae76..53ef567 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -130,7 +130,8 @@ static enum opt_result project_of_group(GKeyFile *config, const char *group_name + return OPT_SUCCESS; + } + +-static enum opt_result engine_of_group(GKeyFile *config, char *group_name, struct project *proj, struct engine **eng) ++static enum opt_result engine_of_group(GKeyFile *config, const char *group_name, ++ struct project *proj, struct engine **eng) + { + char *eng_name = NULL; + enum opt_result ret; +@@ -154,7 +155,7 @@ static enum opt_result engine_of_group(GKeyFile *config, char *group_name, struc + return OPT_SUCCESS; + } + +-static enum opt_result task_of_group(GKeyFile *config, char *group_name, ++static enum opt_result task_of_group(GKeyFile *config, const char *group_name, + struct project *proj, struct engine *eng, struct task **tk) + { + char *task_name = NULL; +diff --git a/src/etmemd_src/etmemd_scan.c b/src/etmemd_src/etmemd_scan.c +index 3238668..0fb4fe6 100644 +--- a/src/etmemd_src/etmemd_scan.c ++++ b/src/etmemd_src/etmemd_scan.c +@@ -70,7 +70,7 @@ static unsigned int get_page_shift(long pagesize) + int init_g_page_size(void) + { + unsigned int page_shift; +- long pagesize = -1; ++ long pagesize; + + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize == -1) { +-- +2.27.0 + diff --git a/0045-add-dram_percent-to-etmem.patch b/0045-add-dram_percent-to-etmem.patch new file mode 100644 index 0000000..a7cad10 --- /dev/null +++ b/0045-add-dram_percent-to-etmem.patch @@ -0,0 +1,520 @@ +From 6ef46195753a4f383e931b7267cebedc40e756c5 Mon Sep 17 00:00:00 2001 +From: liubo +Date: Wed, 18 Aug 2021 10:22:50 +0800 +Subject: [PATCH 45/50] add dram_percent to etmem + +--- + inc/etmemd_inc/etmemd_common.h | 9 ++++ + inc/etmemd_inc/etmemd_exp.h | 5 ++ + inc/etmemd_inc/etmemd_migrate.h | 3 +- + inc/etmemd_inc/etmemd_scan.h | 5 +- + inc/etmemd_inc/etmemd_slide.h | 1 + + src/etmemd_src/etmemd_common.c | 94 +++++++++++++++++++++++++++++++++ + src/etmemd_src/etmemd_migrate.c | 46 ++++++++++++++++ + src/etmemd_src/etmemd_scan.c | 70 ++++++++++++++++++++++++ + src/etmemd_src/etmemd_slide.c | 83 +++++++++++++++++++++++++---- + 9 files changed, 304 insertions(+), 12 deletions(-) + +diff --git a/inc/etmemd_inc/etmemd_common.h b/inc/etmemd_inc/etmemd_common.h +index 4127ccf..8d18f8a 100644 +--- a/inc/etmemd_inc/etmemd_common.h ++++ b/inc/etmemd_inc/etmemd_common.h +@@ -20,10 +20,16 @@ + #include + + #define PROC_PATH "/proc/" ++#define STATUS_FILE "/status" ++#define SWAPIN "SwapIN" ++#define VMRSS "VmRSS" ++#define VMSWAP "VmSwap" + #define FILE_LINE_MAX_LEN 1024 + #define KEY_VALUE_MAX_LEN 64 + #define DECIMAL_RADIX 10 + #define ETMEMD_MAX_PARAMETER_NUM 6 ++#define BYTE_TO_KB(s) ((s) >> 10) ++#define KB_TO_BYTE(s) ((s) << 10) + + #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + +@@ -48,11 +54,14 @@ int etmemd_parse_cmdline(int argc, char *argv[], bool *is_help); + bool check_str_format(char endptr); + int get_int_value(const char *val, int *value); + int get_unsigned_int_value(const char *val, unsigned int *value); ++int get_unsigned_long_value(const char *val, unsigned long *value); + void etmemd_safe_free(void **ptr); + + FILE *etmemd_get_proc_file(const char *pid, const char *file, int flags, const char *mode); + + int get_keyword_and_value(const char *str, char *key, char *val); ++unsigned long get_pagesize(void); ++int get_mem_from_proc_file(const char *pid, const char *file_name, unsigned long *data, const char *cmpstr); + + int dprintf_all(int fd, const char *format, ...); + +diff --git a/inc/etmemd_inc/etmemd_exp.h b/inc/etmemd_inc/etmemd_exp.h +index 8c57d9f..48a0018 100644 +--- a/inc/etmemd_inc/etmemd_exp.h ++++ b/inc/etmemd_inc/etmemd_exp.h +@@ -39,4 +39,9 @@ struct page_refs { + struct page_refs *next; /* point to next page */ + }; + ++struct page_sort { ++ struct page_refs **page_refs_sort; ++ struct page_refs **page_refs; ++ int loop; ++}; + #endif +diff --git a/inc/etmemd_inc/etmemd_migrate.h b/inc/etmemd_inc/etmemd_migrate.h +index db61c69..ef20bde 100644 +--- a/inc/etmemd_inc/etmemd_migrate.h ++++ b/inc/etmemd_inc/etmemd_migrate.h +@@ -17,6 +17,7 @@ + #define ETMEMD_MIGRATE_H + + #include "etmemd.h" ++#include "etmemd_task.h" + + #define COLD_PAGE "/swap_pages" + +@@ -26,5 +27,5 @@ + #define SWAP_ADDR_LEN 20 + + int etmemd_grade_migrate(const char* pid, const struct memory_grade *memory_grade); +- ++unsigned long check_should_migrate(const struct task_pid *tk_pid); + #endif +diff --git a/inc/etmemd_inc/etmemd_scan.h b/inc/etmemd_inc/etmemd_scan.h +index 09ad51c..9e5bcc4 100644 +--- a/inc/etmemd_inc/etmemd_scan.h ++++ b/inc/etmemd_inc/etmemd_scan.h +@@ -77,9 +77,12 @@ struct vmas *get_vmas_with_flags(const char *pid, char **vmflags_array, int vmfl + struct vmas *get_vmas(const char *pid); + + void clean_page_refs_unexpected(void *arg); +- + void clean_memory_grade_unexpected(void *arg); + ++void clean_page_sort_unexpected(void *arg); ++struct page_sort *alloc_page_sort(const struct task_pid *tk_pid); ++struct page_sort *sort_page_refs(struct page_refs **page_refs, const struct task_pid *tk_pid); ++ + struct page_refs *add_page_refs_into_memory_grade(struct page_refs *page_refs, struct page_refs **list); + int init_g_page_size(void); + int page_type_to_size(enum page_type type); +diff --git a/inc/etmemd_inc/etmemd_slide.h b/inc/etmemd_inc/etmemd_slide.h +index af48be7..93de502 100644 +--- a/inc/etmemd_inc/etmemd_slide.h ++++ b/inc/etmemd_inc/etmemd_slide.h +@@ -22,6 +22,7 @@ + struct slide_params { + struct task_executor *executor; + int t; /* watermark */ ++ uint8_t dram_percent; + }; + + int fill_engine_type_slide(struct engine *eng, GKeyFile *config); +diff --git a/src/etmemd_src/etmemd_common.c b/src/etmemd_src/etmemd_common.c +index 8aad0eb..4595499 100644 +--- a/src/etmemd_src/etmemd_common.c ++++ b/src/etmemd_src/etmemd_common.c +@@ -195,6 +195,19 @@ int get_unsigned_int_value(const char *val, unsigned int *value) + return 0; + } + ++int get_unsigned_long_value(const char *val, unsigned long *value) ++{ ++ char *pos = NULL; ++ ++ errno = 0; ++ *value = strtoul(val, &pos, DECIMAL_RADIX); ++ if (check_str_format(pos[0])) { ++ etmemd_log(ETMEMD_LOG_ERR, "invalid value, must be type of unsigned long.\n"); ++ return -1; ++ } ++ ++ return 0; ++} + void etmemd_safe_free(void **ptr) + { + if (ptr == NULL || *ptr == NULL) { +@@ -205,6 +218,36 @@ void etmemd_safe_free(void **ptr) + *ptr = NULL; + } + ++static int get_status_num(char *getline, char *value, size_t value_len) ++{ ++ size_t len = strlen(getline); ++ int start_cp_index = 0; ++ int end_cp_index = 0; ++ size_t i; ++ ++ for (i = 0; i < len; i++) { ++ if (isdigit(getline[i])) { ++ start_cp_index = i; ++ end_cp_index = start_cp_index; ++ break; ++ } ++ } ++ ++ for (; i < len; i++) { ++ if (!isdigit(getline[i])) { ++ end_cp_index = i - 1; ++ break; ++ } ++ } ++ ++ if (strncpy_s(value, value_len, getline + start_cp_index, end_cp_index - start_cp_index + 1) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "strncpy_s for result failed.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ + static char *etmemd_get_proc_file_str(const char *pid, const char *file) + { + char *file_name = NULL; +@@ -398,3 +441,54 @@ int dprintf_all(int fd, const char *format, ...) + va_end(args_in); + return 0; + } ++ ++int get_mem_from_proc_file(const char *pid, const char *file_name, unsigned long *data, const char *cmpstr) ++{ ++ FILE *file = NULL; ++ char value[KEY_VALUE_MAX_LEN] = {}; ++ char get_line[FILE_LINE_MAX_LEN] = {}; ++ unsigned long val; ++ int ret = -1; ++ ++ file = etmemd_get_proc_file(pid, file_name, 0, "r"); ++ if (file == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "cannot open %s for pid %s\n", file_name, pid); ++ return ret; ++ } ++ ++ while (fgets(get_line, FILE_LINE_MAX_LEN - 1, file) != NULL) { ++ if (strstr(get_line, cmpstr) == NULL) { ++ continue; ++ } ++ ++ if (get_status_num(get_line, value, KEY_VALUE_MAX_LEN) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get mem from /proc/%s/%s fail\n", pid, file_name); ++ break; ++ } ++ ++ if (get_unsigned_long_value(value, &val) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get value with strtoul fail.\n"); ++ break; ++ } ++ ++ *data = val; ++ ret = 0; ++ break; ++ } ++ ++ fclose(file); ++ return ret; ++} ++ ++unsigned long get_pagesize(void) ++{ ++ long pagesize; ++ ++ pagesize = sysconf(_SC_PAGESIZE); ++ if (pagesize == -1) { ++ etmemd_log(ETMEMD_LOG_ERR, "get pageszie fail,error: %d\n", errno); ++ return -1; ++ } ++ ++ return (unsigned long)pagesize; ++} +diff --git a/src/etmemd_src/etmemd_migrate.c b/src/etmemd_src/etmemd_migrate.c +index 2f29f31..639d570 100644 +--- a/src/etmemd_src/etmemd_migrate.c ++++ b/src/etmemd_src/etmemd_migrate.c +@@ -20,6 +20,7 @@ + #include "etmemd.h" + #include "etmemd_migrate.h" + #include "etmemd_common.h" ++#include "etmemd_slide.h" + #include "etmemd_log.h" + + static char *get_swap_string(struct page_refs **page_refs, int batchsize) +@@ -113,3 +114,48 @@ int etmemd_grade_migrate(const char *pid, const struct memory_grade *memory_grad + return ret; + } + ++unsigned long check_should_migrate(const struct task_pid *tk_pid) ++{ ++ int ret = -1; ++ unsigned long vm_rss; ++ unsigned long vm_swap; ++ unsigned long vm_cmp; ++ unsigned long need_to_swap_page_num; ++ char pid_str[PID_STR_MAX_LEN] = {0}; ++ unsigned long pagesize; ++ struct slide_params *slide_params = NULL; ++ ++ if (snprintf_s(pid_str, PID_STR_MAX_LEN, PID_STR_MAX_LEN - 1, "%u", tk_pid->pid) <= 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "snprintf pid fail %u", tk_pid->pid); ++ return 0; ++ } ++ ++ ret = get_mem_from_proc_file(pid_str, STATUS_FILE, &vm_rss, VMRSS); ++ if (ret != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get vmrss %s fail", pid_str); ++ return 0; ++ } ++ ++ ret = get_mem_from_proc_file(pid_str, STATUS_FILE, &vm_swap, VMSWAP); ++ if (ret != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "get swapout %s fail", pid_str); ++ return 0; ++ } ++ ++ slide_params = (struct slide_params *)tk_pid->tk->params; ++ if (slide_params == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "slide params is null"); ++ return 0; ++ } ++ ++ vm_cmp = (vm_rss + vm_swap) / 100 * slide_params->dram_percent; ++ if (vm_cmp > vm_rss) { ++ etmemd_log(ETMEMD_LOG_DEBUG, "migrate too much, stop migrate this time\n"); ++ return 0; ++ } ++ ++ pagesize = get_pagesize(); ++ need_to_swap_page_num = KB_TO_BYTE(vm_rss - vm_cmp) / pagesize; ++ ++ return need_to_swap_page_num; ++} +diff --git a/src/etmemd_src/etmemd_scan.c b/src/etmemd_src/etmemd_scan.c +index 0fb4fe6..fec6373 100644 +--- a/src/etmemd_src/etmemd_scan.c ++++ b/src/etmemd_src/etmemd_scan.c +@@ -24,6 +24,7 @@ + #include "etmemd_project.h" + #include "etmemd_engine.h" + #include "etmemd_common.h" ++#include "etmemd_slide.h" + #include "etmemd_log.h" + #include "securec.h" + +@@ -819,6 +820,46 @@ void clean_memory_grade_unexpected(void *arg) + return; + } + ++void clean_page_sort_unexpected(void *arg) ++{ ++ struct page_sort **msg = (struct page_sort **)arg; ++ ++ if (*msg == NULL) { ++ return; ++ } ++ ++ for (int i = 0; i < (*msg)->loop + 1; i++) { ++ clean_page_refs_unexpected(&((*msg)->page_refs_sort)[i]); ++ } ++ ++ free(*msg); ++ *msg = NULL; ++ ++ return; ++} ++ ++struct page_sort *alloc_page_sort(const struct task_pid *tpid) ++{ ++ struct page_sort *page_sort = NULL; ++ ++ page_sort = (struct page_sort *)calloc(1, sizeof(struct page_sort)); ++ if (page_sort == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "calloc page sort failed.\n"); ++ return NULL; ++ } ++ ++ page_sort->loop = tpid->tk->eng->proj->loop; ++ ++ page_sort->page_refs_sort = (struct page_refs **)calloc((tpid->tk->eng->proj->loop + 1), sizeof(struct page_refs *)); ++ if (page_sort->page_refs_sort == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "calloc page refs sort failed.\n"); ++ free(page_sort); ++ return NULL; ++ } ++ ++ return page_sort; ++} ++ + struct page_refs *add_page_refs_into_memory_grade(struct page_refs *page_refs, struct page_refs **list) + { + struct page_refs *tmp = NULL; +@@ -851,3 +892,32 @@ void etmemd_scan_exit(void) + { + g_exp_scan_inited = false; + } ++ ++/* Move the colder pages by sorting page refs. ++ * Use original page_refs if dram_percent is not set. ++ * But, use the sorting result of page_refs, if dram_percent is set to (0, 100] */ ++struct page_sort *sort_page_refs(struct page_refs **page_refs, const struct task_pid *tpid) ++{ ++ struct slide_params *slide_params = NULL; ++ struct page_sort *page_sort = NULL; ++ struct page_refs *page_next = NULL; ++ ++ page_sort = alloc_page_sort(tpid); ++ if (page_sort == NULL) ++ return NULL; ++ ++ slide_params = (struct slide_params *)tpid->tk->params; ++ if (slide_params == NULL || slide_params->dram_percent == 0) { ++ page_sort->page_refs = page_refs; ++ return page_sort; ++ } ++ ++ while (*page_refs != NULL) { ++ page_next = (*page_refs)->next; ++ (*page_refs)->next = (page_sort->page_refs_sort[(*page_refs)->count]); ++ (page_sort->page_refs_sort[(*page_refs)->count]) = *page_refs; ++ *page_refs = page_next; ++ } ++ ++ return page_sort; ++} +diff --git a/src/etmemd_src/etmemd_slide.c b/src/etmemd_src/etmemd_slide.c +index 96d3dcc..a024178 100644 +--- a/src/etmemd_src/etmemd_slide.c ++++ b/src/etmemd_src/etmemd_slide.c +@@ -28,12 +28,15 @@ + #include "etmemd_pool_adapter.h" + #include "etmemd_file.h" + +-static struct memory_grade *slide_policy_interface(struct page_refs **page_refs, void *params) ++static struct memory_grade *slide_policy_interface(struct page_sort **page_sort, const struct task_pid *tpid) + { +- struct slide_params *slide_params = (struct slide_params *)params; ++ struct slide_params *slide_params = (struct slide_params *)(tpid->tk->params); ++ struct page_refs **page_refs = NULL; + struct memory_grade *memory_grade = NULL; ++ unsigned long need_2_swap_num; ++ volatile uint64_t count = 0; + +- if (params == NULL) { ++ if (slide_params == NULL) { + etmemd_log(ETMEMD_LOG_ERR, "cannot get params for slide\n"); + return NULL; + } +@@ -44,14 +47,41 @@ static struct memory_grade *slide_policy_interface(struct page_refs **page_refs, + return NULL; + } + +- while (*page_refs != NULL) { +- if ((*page_refs)->count >= slide_params->t) { +- *page_refs = add_page_refs_into_memory_grade(*page_refs, &memory_grade->hot_pages); +- continue; ++ if (slide_params->dram_percent == 0) { ++ page_refs = (*page_sort)->page_refs; ++ ++ while (*page_refs != NULL) { ++ if ((*page_refs)->count >= slide_params->t) { ++ *page_refs = add_page_refs_into_memory_grade(*page_refs, &memory_grade->hot_pages); ++ continue; ++ } ++ *page_refs = add_page_refs_into_memory_grade(*page_refs, &memory_grade->cold_pages); ++ } ++ ++ return memory_grade; ++ } ++ ++ need_2_swap_num = check_should_migrate(tpid); ++ if (need_2_swap_num == 0) ++ goto count_out; ++ ++ for (int i = 0; i < tpid->tk->eng->proj->loop + 1; i++) { ++ page_refs = &((*page_sort)->page_refs_sort[i]); ++ ++ while (*page_refs != NULL) { ++ if ((*page_refs)->count >= slide_params->t) { ++ *page_refs = add_page_refs_into_memory_grade(*page_refs, &memory_grade->hot_pages); ++ goto count_out; ++ } ++ ++ *page_refs = add_page_refs_into_memory_grade(*page_refs, &memory_grade->cold_pages); ++ count++; ++ if (count >= need_2_swap_num) ++ goto count_out; + } +- *page_refs = add_page_refs_into_memory_grade(*page_refs, &memory_grade->cold_pages); + } + ++count_out: + return memory_grade; + } + +@@ -80,17 +110,32 @@ static void *slide_executor(void *arg) + struct task_pid *tk_pid = (struct task_pid *)arg; + struct page_refs *page_refs = NULL; + struct memory_grade *memory_grade = NULL; ++ struct page_sort *page_sort = NULL; + + /* register cleanup function in case of unexpected cancellation detected, + * and register for memory_grade first, because it needs to clean after page_refs is cleaned */ + pthread_cleanup_push(clean_memory_grade_unexpected, &memory_grade); + pthread_cleanup_push(clean_page_refs_unexpected, &page_refs); ++ pthread_cleanup_push(clean_page_sort_unexpected, &page_sort); + + page_refs = etmemd_do_scan(tk_pid, tk_pid->tk); +- if (page_refs != NULL) { +- memory_grade = slide_policy_interface(&page_refs, tk_pid->tk->params); ++ if (page_refs == NULL) { ++ etmemd_log(ETMEMD_LOG_WARN, "pid %u cannot get page refs\n", tk_pid->pid); ++ goto scan_out; + } + ++ page_sort = sort_page_refs(&page_refs, tk_pid); ++ if (page_sort == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "failed to alloc memory for page sort.", tk_pid->pid); ++ goto scan_out; ++ } ++ ++ memory_grade = slide_policy_interface(&page_sort, tk_pid); ++ ++scan_out: ++ /* clean up page_sort linked array */ ++ pthread_cleanup_pop(1); ++ + /* no need to use page_refs any longer. + * pop the cleanup function with parameter 1, because the items in page_refs list will be moved + * into the at least on list of memory_grade after polidy function called if no problems happened, +@@ -131,8 +176,26 @@ static int fill_task_threshold(void *obj, void *val) + return 0; + } + ++static int fill_task_dram_percent(void *obj, void *val) ++{ ++ struct slide_params *params = (struct slide_params *)obj; ++ int value = parse_to_int(val); ++ ++ if (value <= 0 || value > 100) { ++ etmemd_log(ETMEMD_LOG_WARN, ++ "dram_percent %d is abnormal, the reasonable range is (0, 100],\ ++ cancle the dram_percent parameter of current task\n", value); ++ value = 0; ++ } ++ ++ params->dram_percent = value; ++ ++ return 0; ++} ++ + static struct config_item g_slide_task_config_items[] = { + {"T", INT_VAL, fill_task_threshold, false}, ++ {"dram_percent", INT_VAL, fill_task_dram_percent, true}, + }; + + static int slide_fill_task(GKeyFile *config, struct task *tk) +-- +2.27.0 + diff --git a/0046-Fix-memory-leak-in-slide-engine.patch b/0046-Fix-memory-leak-in-slide-engine.patch new file mode 100644 index 0000000..5b920f5 --- /dev/null +++ b/0046-Fix-memory-leak-in-slide-engine.patch @@ -0,0 +1,52 @@ +From 10883d861456fe5daf7e664c0311abed754da8fd Mon Sep 17 00:00:00 2001 +From: liubo +Date: Mon, 27 Sep 2021 15:58:11 +0800 +Subject: [PATCH 46/50] Fix memory leak in slide engine, remove project show + cmd error msg. + +If a process has multiple subprocess, release the task_pid resource of +the subprocess corresponding to the task when project stops. + +Remove project show error message if show cmd is executed successfully. + +Signed-off-by: liubo +--- + src/etmemd_src/etmemd_project.c | 7 ++++--- + src/etmemd_src/etmemd_slide.c | 1 + + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/etmemd_src/etmemd_project.c b/src/etmemd_src/etmemd_project.c +index 53ef567..f7f1885 100644 +--- a/src/etmemd_src/etmemd_project.c ++++ b/src/etmemd_src/etmemd_project.c +@@ -611,11 +611,12 @@ enum opt_result etmemd_project_show(const char *project_name, int sock_fd) + + if (!exists) { + if (project_name == NULL) { +- etmemd_log(ETMEMD_LOG_ERR, "no project exists\n"); ++ etmemd_log(ETMEMD_LOG_DEBUG, "no project exists\n"); ++ dprintf_all(sock_fd, "no project exists\n\n"); + } else { +- etmemd_log(ETMEMD_LOG_ERR, "project: project %s is not existed\n\n", project_name); ++ etmemd_log(ETMEMD_LOG_DEBUG, "project: project %s is not existed\n\n", project_name); ++ dprintf_all(sock_fd, "project: project %s is not existed\n\n", project_name); + } +- return OPT_PRO_NOEXIST; + } + + return OPT_SUCCESS; +diff --git a/src/etmemd_src/etmemd_slide.c b/src/etmemd_src/etmemd_slide.c +index a024178..45db00a 100644 +--- a/src/etmemd_src/etmemd_slide.c ++++ b/src/etmemd_src/etmemd_slide.c +@@ -227,6 +227,7 @@ free_params: + + static void slide_clear_task(struct task *tk) + { ++ etmemd_free_task_pids(tk); + free(tk->params); + tk->params = NULL; + } +-- +2.27.0 + diff --git a/etmem.spec b/etmem.spec index 8c76da7..b7bb4de 100644 --- a/etmem.spec +++ b/etmem.spec @@ -9,6 +9,52 @@ Source0: etmem-%{version}.tar.gz Patch0: 0001-fix-64K-pagesize-scan-problem.patch Patch1: 0002-change-aarch64-march-to-armv8-a.patch +Patch2: 0003-update-README.md.patch +Patch3: 0004-add-cslide-for-etmem.patch +Patch4: 0005-fix-code-check-problems.patch +Patch5: 0006-remove-unused-share-vmas-merge.patch +Patch6: 0007-fix-error-when-open-idle_pages-failed.patch +Patch7: 0008-fix-memleak.patch +Patch8: 0009-fix-some-bugs-that-occur-when-execute-obj-add-or-del.patch +Patch9: 0010-clean-code.patch +Patch10: 0011-wait-for-next-period-when-error-occurs-in-this-perio.patch +Patch11: 0012-add-recursive-in-etmemd_get_task_pids.patch +Patch12: 0013-check-permission-according-cmd-to-be-executed.patch +Patch13: 0014-stat-pages-info-early-only-replace-cold-mem-in-hot-nodes.patch +Patch14: 0015-limit-mig_quota-hot_reserve-to-0-INT_MAX.patch +Patch15: 0016-add-some-dfx-info.patch +Patch16: 0017-do-not-stop-the-process-when-failed-to-delete-any-obj.patch +Patch17: 0018-fix-code-check-warnning.patch +Patch18: 0019-accept-review-advise.patch +Patch19: 0020-revert-socket-permission-check.patch +Patch20: 0021-add-thirdpart-engine.patch +Patch21: 0022-export-symbols-for-user-defined-thirdparty-engine.patch +Patch22: 0023-accept-review-advise.patch +Patch23: 0024-correct-etmemd-name.patch +Patch24: 0025-add-support-for-systemctl-mode-to-start-etmem.patch +Patch25: 0026-add-scan-library.patch +Patch26: 0027-add-ign_host-to-ignore-host-access-when-scan-vm.patch +Patch27: 0028-openlog-with-same-ident.patch +Patch28: 0029-accept-advise.patch +Patch29: 0030-notify-rpc-success-with-finish-tag.patch +Patch30: 0031-remove-node_watermark.patch +Patch31: 0032-print-all-log-to-stdout.patch +Patch32: 0033-accept-review-advise.patch +Patch33: 0034-fix-open-swap_pages-failure.patch +Patch34: 0035-give-the-correct-example-of-config-file.patch +Patch35: 0036-check-if-start_task-is-NULL-before-call-it.patch +Patch36: 0037-correct-max_threads-when-max_threads-is-0.patch +Patch37: 0038-fix-etmem-help-return-error.patch +Patch38: 0039-check-if-eng_mgt_func-is-NULL-before-use-it.patch +Patch39: 0040-make-code-clean-for-etmem.patch +Patch40: 0041-return-error-if-migrate-failed-and-clean-code.patch +Patch41: 0042-etmemd-fix-memleak-and-clean-code.patch +Patch42: 0043-update-README.md.patch +Patch43: 0044-etmem-cleancode.patch +Patch44: 0045-add-dram_percent-to-etmem.patch +Patch45: 0046-Fix-memory-leak-in-slide-engine.patch + + #Dependency BuildRequires: cmake gcc gcc-c++ BuildRequires: libboundscheck