From c6bc9fb6829ae0c90009a0a33eb7408f35810f75 Mon Sep 17 00:00:00 2001 From: YangXin <245051644@qq.com> Date: Thu, 30 Sep 2021 22:57:41 +0800 Subject: [PATCH 1/4] Update etmem. Signed-off-by: YangXin <245051644@qq.com> (cherry picked from commit 6d9f6d7f6ba64f91014ff4455f0891286821c647) --- 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 -- Gitee From 6f0dfc66db3690bbe388b2a9c865913a3ed33117 Mon Sep 17 00:00:00 2001 From: YangXin <245051644@qq.com> Date: Thu, 30 Sep 2021 23:35:50 +0800 Subject: [PATCH 2/4] Add new features memRouter and userswap to etmem. Signed-off-by: YangXin <245051644@qq.com> (cherry picked from commit b1689d83a7dd404ab776ecfbd7a1c8ea0c801a16) --- ...-the-files-to-sub-directory-of-etmem.patch | 335 ++ ...ures-memRouter-and-userswap-to-etmem.patch | 3286 +++++++++++++++++ etmem.spec | 3 +- 3 files changed, 3623 insertions(+), 1 deletion(-) create mode 100644 0047-move-all-the-files-to-sub-directory-of-etmem.patch create mode 100644 0048-Commit-new-features-memRouter-and-userswap-to-etmem.patch diff --git a/0047-move-all-the-files-to-sub-directory-of-etmem.patch b/0047-move-all-the-files-to-sub-directory-of-etmem.patch new file mode 100644 index 0000000..f010a7d --- /dev/null +++ b/0047-move-all-the-files-to-sub-directory-of-etmem.patch @@ -0,0 +1,335 @@ +From b89f142798ebb23ad58ad3a0d1fe34f74e7801a6 Mon Sep 17 00:00:00 2001 +From: louhongxiang +Date: Thu, 30 Sep 2021 14:15:50 +0800 +Subject: [PATCH 47/50] move all the files to sub directory of etmem. + +--- + CMakeLists.txt => etmem/CMakeLists.txt | 0 + {conf => etmem/conf}/example_conf.yaml | 0 + {inc => etmem/inc}/etmem_inc/etmem.h | 0 + {inc => etmem/inc}/etmem_inc/etmem_common.h | 0 + {inc => etmem/inc}/etmem_inc/etmem_engine.h | 0 + {inc => etmem/inc}/etmem_inc/etmem_obj.h | 0 + {inc => etmem/inc}/etmem_inc/etmem_project.h | 0 + {inc => etmem/inc}/etmem_inc/etmem_rpc.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_common.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_cslide.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_engine.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_engine_exp.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_exp.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_file.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_log.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_migrate.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_pool_adapter.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_project.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_project_exp.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_rpc.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_scan.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_scan_exp.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_scan_export.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_slide.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_task.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_task_exp.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_thirdparty.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_thirdparty_export.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_threadpool.h | 0 + {inc => etmem/inc}/etmemd_inc/etmemd_threadtimer.h | 0 + {src => etmem/src}/etmem_src/etmem.c | 0 + {src => etmem/src}/etmem_src/etmem_common.c | 0 + {src => etmem/src}/etmem_src/etmem_engine.c | 0 + {src => etmem/src}/etmem_src/etmem_obj.c | 0 + {src => etmem/src}/etmem_src/etmem_project.c | 0 + {src => etmem/src}/etmem_src/etmem_rpc.c | 0 + {src => etmem/src}/etmemd_src/etmemd.c | 0 + {src => etmem/src}/etmemd_src/etmemd_common.c | 0 + {src => etmem/src}/etmemd_src/etmemd_cslide.c | 0 + {src => etmem/src}/etmemd_src/etmemd_engine.c | 0 + {src => etmem/src}/etmemd_src/etmemd_file.c | 0 + {src => etmem/src}/etmemd_src/etmemd_log.c | 0 + {src => etmem/src}/etmemd_src/etmemd_migrate.c | 0 + {src => etmem/src}/etmemd_src/etmemd_pool_adapter.c | 0 + {src => etmem/src}/etmemd_src/etmemd_project.c | 0 + {src => etmem/src}/etmemd_src/etmemd_rpc.c | 0 + {src => etmem/src}/etmemd_src/etmemd_scan.c | 0 + {src => etmem/src}/etmemd_src/etmemd_scan.version | 0 + {src => etmem/src}/etmemd_src/etmemd_slide.c | 0 + {src => etmem/src}/etmemd_src/etmemd_task.c | 0 + {src => etmem/src}/etmemd_src/etmemd_thirdparty.c | 0 + {src => etmem/src}/etmemd_src/etmemd_threadpool.c | 0 + {src => etmem/src}/etmemd_src/etmemd_threadtimer.c | 0 + 56 files changed, 0 insertions(+), 0 deletions(-) + rename CMakeLists.txt => etmem/CMakeLists.txt (100%) + rename {conf => etmem/conf}/example_conf.yaml (100%) + rename {inc => etmem/inc}/etmem_inc/etmem.h (100%) + rename {inc => etmem/inc}/etmem_inc/etmem_common.h (100%) + rename {inc => etmem/inc}/etmem_inc/etmem_engine.h (100%) + rename {inc => etmem/inc}/etmem_inc/etmem_obj.h (100%) + rename {inc => etmem/inc}/etmem_inc/etmem_project.h (100%) + rename {inc => etmem/inc}/etmem_inc/etmem_rpc.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_common.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_cslide.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_engine.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_engine_exp.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_exp.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_file.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_log.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_migrate.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_pool_adapter.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_project.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_project_exp.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_rpc.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_scan.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_scan_exp.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_scan_export.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_slide.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_task.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_task_exp.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_thirdparty.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_thirdparty_export.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_threadpool.h (100%) + rename {inc => etmem/inc}/etmemd_inc/etmemd_threadtimer.h (100%) + rename {src => etmem/src}/etmem_src/etmem.c (100%) + rename {src => etmem/src}/etmem_src/etmem_common.c (100%) + rename {src => etmem/src}/etmem_src/etmem_engine.c (100%) + rename {src => etmem/src}/etmem_src/etmem_obj.c (100%) + rename {src => etmem/src}/etmem_src/etmem_project.c (100%) + rename {src => etmem/src}/etmem_src/etmem_rpc.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_common.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_cslide.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_engine.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_file.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_log.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_migrate.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_pool_adapter.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_project.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_rpc.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_scan.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_scan.version (100%) + rename {src => etmem/src}/etmemd_src/etmemd_slide.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_task.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_thirdparty.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_threadpool.c (100%) + rename {src => etmem/src}/etmemd_src/etmemd_threadtimer.c (100%) + +diff --git a/CMakeLists.txt b/etmem/CMakeLists.txt +similarity index 100% +rename from CMakeLists.txt +rename to etmem/CMakeLists.txt +diff --git a/conf/example_conf.yaml b/etmem/conf/example_conf.yaml +similarity index 100% +rename from conf/example_conf.yaml +rename to etmem/conf/example_conf.yaml +diff --git a/inc/etmem_inc/etmem.h b/etmem/inc/etmem_inc/etmem.h +similarity index 100% +rename from inc/etmem_inc/etmem.h +rename to etmem/inc/etmem_inc/etmem.h +diff --git a/inc/etmem_inc/etmem_common.h b/etmem/inc/etmem_inc/etmem_common.h +similarity index 100% +rename from inc/etmem_inc/etmem_common.h +rename to etmem/inc/etmem_inc/etmem_common.h +diff --git a/inc/etmem_inc/etmem_engine.h b/etmem/inc/etmem_inc/etmem_engine.h +similarity index 100% +rename from inc/etmem_inc/etmem_engine.h +rename to etmem/inc/etmem_inc/etmem_engine.h +diff --git a/inc/etmem_inc/etmem_obj.h b/etmem/inc/etmem_inc/etmem_obj.h +similarity index 100% +rename from inc/etmem_inc/etmem_obj.h +rename to etmem/inc/etmem_inc/etmem_obj.h +diff --git a/inc/etmem_inc/etmem_project.h b/etmem/inc/etmem_inc/etmem_project.h +similarity index 100% +rename from inc/etmem_inc/etmem_project.h +rename to etmem/inc/etmem_inc/etmem_project.h +diff --git a/inc/etmem_inc/etmem_rpc.h b/etmem/inc/etmem_inc/etmem_rpc.h +similarity index 100% +rename from inc/etmem_inc/etmem_rpc.h +rename to etmem/inc/etmem_inc/etmem_rpc.h +diff --git a/inc/etmemd_inc/etmemd.h b/etmem/inc/etmemd_inc/etmemd.h +similarity index 100% +rename from inc/etmemd_inc/etmemd.h +rename to etmem/inc/etmemd_inc/etmemd.h +diff --git a/inc/etmemd_inc/etmemd_common.h b/etmem/inc/etmemd_inc/etmemd_common.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_common.h +rename to etmem/inc/etmemd_inc/etmemd_common.h +diff --git a/inc/etmemd_inc/etmemd_cslide.h b/etmem/inc/etmemd_inc/etmemd_cslide.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_cslide.h +rename to etmem/inc/etmemd_inc/etmemd_cslide.h +diff --git a/inc/etmemd_inc/etmemd_engine.h b/etmem/inc/etmemd_inc/etmemd_engine.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_engine.h +rename to etmem/inc/etmemd_inc/etmemd_engine.h +diff --git a/inc/etmemd_inc/etmemd_engine_exp.h b/etmem/inc/etmemd_inc/etmemd_engine_exp.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_engine_exp.h +rename to etmem/inc/etmemd_inc/etmemd_engine_exp.h +diff --git a/inc/etmemd_inc/etmemd_exp.h b/etmem/inc/etmemd_inc/etmemd_exp.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_exp.h +rename to etmem/inc/etmemd_inc/etmemd_exp.h +diff --git a/inc/etmemd_inc/etmemd_file.h b/etmem/inc/etmemd_inc/etmemd_file.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_file.h +rename to etmem/inc/etmemd_inc/etmemd_file.h +diff --git a/inc/etmemd_inc/etmemd_log.h b/etmem/inc/etmemd_inc/etmemd_log.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_log.h +rename to etmem/inc/etmemd_inc/etmemd_log.h +diff --git a/inc/etmemd_inc/etmemd_migrate.h b/etmem/inc/etmemd_inc/etmemd_migrate.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_migrate.h +rename to etmem/inc/etmemd_inc/etmemd_migrate.h +diff --git a/inc/etmemd_inc/etmemd_pool_adapter.h b/etmem/inc/etmemd_inc/etmemd_pool_adapter.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_pool_adapter.h +rename to etmem/inc/etmemd_inc/etmemd_pool_adapter.h +diff --git a/inc/etmemd_inc/etmemd_project.h b/etmem/inc/etmemd_inc/etmemd_project.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_project.h +rename to etmem/inc/etmemd_inc/etmemd_project.h +diff --git a/inc/etmemd_inc/etmemd_project_exp.h b/etmem/inc/etmemd_inc/etmemd_project_exp.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_project_exp.h +rename to etmem/inc/etmemd_inc/etmemd_project_exp.h +diff --git a/inc/etmemd_inc/etmemd_rpc.h b/etmem/inc/etmemd_inc/etmemd_rpc.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_rpc.h +rename to etmem/inc/etmemd_inc/etmemd_rpc.h +diff --git a/inc/etmemd_inc/etmemd_scan.h b/etmem/inc/etmemd_inc/etmemd_scan.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_scan.h +rename to etmem/inc/etmemd_inc/etmemd_scan.h +diff --git a/inc/etmemd_inc/etmemd_scan_exp.h b/etmem/inc/etmemd_inc/etmemd_scan_exp.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_scan_exp.h +rename to etmem/inc/etmemd_inc/etmemd_scan_exp.h +diff --git a/inc/etmemd_inc/etmemd_scan_export.h b/etmem/inc/etmemd_inc/etmemd_scan_export.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_scan_export.h +rename to etmem/inc/etmemd_inc/etmemd_scan_export.h +diff --git a/inc/etmemd_inc/etmemd_slide.h b/etmem/inc/etmemd_inc/etmemd_slide.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_slide.h +rename to etmem/inc/etmemd_inc/etmemd_slide.h +diff --git a/inc/etmemd_inc/etmemd_task.h b/etmem/inc/etmemd_inc/etmemd_task.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_task.h +rename to etmem/inc/etmemd_inc/etmemd_task.h +diff --git a/inc/etmemd_inc/etmemd_task_exp.h b/etmem/inc/etmemd_inc/etmemd_task_exp.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_task_exp.h +rename to etmem/inc/etmemd_inc/etmemd_task_exp.h +diff --git a/inc/etmemd_inc/etmemd_thirdparty.h b/etmem/inc/etmemd_inc/etmemd_thirdparty.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_thirdparty.h +rename to etmem/inc/etmemd_inc/etmemd_thirdparty.h +diff --git a/inc/etmemd_inc/etmemd_thirdparty_export.h b/etmem/inc/etmemd_inc/etmemd_thirdparty_export.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_thirdparty_export.h +rename to etmem/inc/etmemd_inc/etmemd_thirdparty_export.h +diff --git a/inc/etmemd_inc/etmemd_threadpool.h b/etmem/inc/etmemd_inc/etmemd_threadpool.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_threadpool.h +rename to etmem/inc/etmemd_inc/etmemd_threadpool.h +diff --git a/inc/etmemd_inc/etmemd_threadtimer.h b/etmem/inc/etmemd_inc/etmemd_threadtimer.h +similarity index 100% +rename from inc/etmemd_inc/etmemd_threadtimer.h +rename to etmem/inc/etmemd_inc/etmemd_threadtimer.h +diff --git a/src/etmem_src/etmem.c b/etmem/src/etmem_src/etmem.c +similarity index 100% +rename from src/etmem_src/etmem.c +rename to etmem/src/etmem_src/etmem.c +diff --git a/src/etmem_src/etmem_common.c b/etmem/src/etmem_src/etmem_common.c +similarity index 100% +rename from src/etmem_src/etmem_common.c +rename to etmem/src/etmem_src/etmem_common.c +diff --git a/src/etmem_src/etmem_engine.c b/etmem/src/etmem_src/etmem_engine.c +similarity index 100% +rename from src/etmem_src/etmem_engine.c +rename to etmem/src/etmem_src/etmem_engine.c +diff --git a/src/etmem_src/etmem_obj.c b/etmem/src/etmem_src/etmem_obj.c +similarity index 100% +rename from src/etmem_src/etmem_obj.c +rename to etmem/src/etmem_src/etmem_obj.c +diff --git a/src/etmem_src/etmem_project.c b/etmem/src/etmem_src/etmem_project.c +similarity index 100% +rename from src/etmem_src/etmem_project.c +rename to etmem/src/etmem_src/etmem_project.c +diff --git a/src/etmem_src/etmem_rpc.c b/etmem/src/etmem_src/etmem_rpc.c +similarity index 100% +rename from src/etmem_src/etmem_rpc.c +rename to etmem/src/etmem_src/etmem_rpc.c +diff --git a/src/etmemd_src/etmemd.c b/etmem/src/etmemd_src/etmemd.c +similarity index 100% +rename from src/etmemd_src/etmemd.c +rename to etmem/src/etmemd_src/etmemd.c +diff --git a/src/etmemd_src/etmemd_common.c b/etmem/src/etmemd_src/etmemd_common.c +similarity index 100% +rename from src/etmemd_src/etmemd_common.c +rename to etmem/src/etmemd_src/etmemd_common.c +diff --git a/src/etmemd_src/etmemd_cslide.c b/etmem/src/etmemd_src/etmemd_cslide.c +similarity index 100% +rename from src/etmemd_src/etmemd_cslide.c +rename to etmem/src/etmemd_src/etmemd_cslide.c +diff --git a/src/etmemd_src/etmemd_engine.c b/etmem/src/etmemd_src/etmemd_engine.c +similarity index 100% +rename from src/etmemd_src/etmemd_engine.c +rename to etmem/src/etmemd_src/etmemd_engine.c +diff --git a/src/etmemd_src/etmemd_file.c b/etmem/src/etmemd_src/etmemd_file.c +similarity index 100% +rename from src/etmemd_src/etmemd_file.c +rename to etmem/src/etmemd_src/etmemd_file.c +diff --git a/src/etmemd_src/etmemd_log.c b/etmem/src/etmemd_src/etmemd_log.c +similarity index 100% +rename from src/etmemd_src/etmemd_log.c +rename to etmem/src/etmemd_src/etmemd_log.c +diff --git a/src/etmemd_src/etmemd_migrate.c b/etmem/src/etmemd_src/etmemd_migrate.c +similarity index 100% +rename from src/etmemd_src/etmemd_migrate.c +rename to etmem/src/etmemd_src/etmemd_migrate.c +diff --git a/src/etmemd_src/etmemd_pool_adapter.c b/etmem/src/etmemd_src/etmemd_pool_adapter.c +similarity index 100% +rename from src/etmemd_src/etmemd_pool_adapter.c +rename to etmem/src/etmemd_src/etmemd_pool_adapter.c +diff --git a/src/etmemd_src/etmemd_project.c b/etmem/src/etmemd_src/etmemd_project.c +similarity index 100% +rename from src/etmemd_src/etmemd_project.c +rename to etmem/src/etmemd_src/etmemd_project.c +diff --git a/src/etmemd_src/etmemd_rpc.c b/etmem/src/etmemd_src/etmemd_rpc.c +similarity index 100% +rename from src/etmemd_src/etmemd_rpc.c +rename to etmem/src/etmemd_src/etmemd_rpc.c +diff --git a/src/etmemd_src/etmemd_scan.c b/etmem/src/etmemd_src/etmemd_scan.c +similarity index 100% +rename from src/etmemd_src/etmemd_scan.c +rename to etmem/src/etmemd_src/etmemd_scan.c +diff --git a/src/etmemd_src/etmemd_scan.version b/etmem/src/etmemd_src/etmemd_scan.version +similarity index 100% +rename from src/etmemd_src/etmemd_scan.version +rename to etmem/src/etmemd_src/etmemd_scan.version +diff --git a/src/etmemd_src/etmemd_slide.c b/etmem/src/etmemd_src/etmemd_slide.c +similarity index 100% +rename from src/etmemd_src/etmemd_slide.c +rename to etmem/src/etmemd_src/etmemd_slide.c +diff --git a/src/etmemd_src/etmemd_task.c b/etmem/src/etmemd_src/etmemd_task.c +similarity index 100% +rename from src/etmemd_src/etmemd_task.c +rename to etmem/src/etmemd_src/etmemd_task.c +diff --git a/src/etmemd_src/etmemd_thirdparty.c b/etmem/src/etmemd_src/etmemd_thirdparty.c +similarity index 100% +rename from src/etmemd_src/etmemd_thirdparty.c +rename to etmem/src/etmemd_src/etmemd_thirdparty.c +diff --git a/src/etmemd_src/etmemd_threadpool.c b/etmem/src/etmemd_src/etmemd_threadpool.c +similarity index 100% +rename from src/etmemd_src/etmemd_threadpool.c +rename to etmem/src/etmemd_src/etmemd_threadpool.c +diff --git a/src/etmemd_src/etmemd_threadtimer.c b/etmem/src/etmemd_src/etmemd_threadtimer.c +similarity index 100% +rename from src/etmemd_src/etmemd_threadtimer.c +rename to etmem/src/etmemd_src/etmemd_threadtimer.c +-- +2.27.0 + diff --git a/0048-Commit-new-features-memRouter-and-userswap-to-etmem.patch b/0048-Commit-new-features-memRouter-and-userswap-to-etmem.patch new file mode 100644 index 0000000..c09c539 --- /dev/null +++ b/0048-Commit-new-features-memRouter-and-userswap-to-etmem.patch @@ -0,0 +1,3286 @@ +From 3d4006defc9ac08581b1cbc7fb5c0ad06473273c Mon Sep 17 00:00:00 2001 +From: Yangxin <245051644@qq.com> +Date: Thu, 30 Sep 2021 17:40:21 +0800 +Subject: [PATCH 48/50] Commit new features memRouter and userswap to etmem. + +Signed-off-by: Yangxin <245051644@qq.com> +--- + memRouter/CMakeLists.txt | 74 +++ + memRouter/README.md | 90 +++ + memRouter/include/memdcd_cmd.h | 21 + + memRouter/include/memdcd_daemon.h | 23 + + memRouter/include/memdcd_log.h | 34 + + memRouter/include/memdcd_message.h | 75 +++ + memRouter/include/memdcd_migrate.h | 21 + + memRouter/include/memdcd_policy.h | 42 ++ + memRouter/include/memdcd_policy_threshold.h | 22 + + memRouter/include/memdcd_process.h | 41 ++ + memRouter/src/memdcd.c | 143 +++++ + memRouter/src/memdcd_cmd.c | 93 +++ + memRouter/src/memdcd_daemon.c | 257 ++++++++ + memRouter/src/memdcd_log.c | 80 +++ + memRouter/src/memdcd_migrate.c | 150 +++++ + memRouter/src/memdcd_policy.c | 132 ++++ + memRouter/src/memdcd_policy_threshold.c | 209 ++++++ + memRouter/src/memdcd_process.c | 345 ++++++++++ + userswap/CMakeLists.txt | 36 ++ + userswap/License/LICENSE | 127 ++++ + userswap/README.md | 7 + + userswap/configure.sh | 4 + + userswap/include/uswap_api.h | 69 ++ + userswap/include/uswap_log.h | 30 + + userswap/include/uswap_server.h | 40 ++ + userswap/src/lib_uswap.c | 663 ++++++++++++++++++++ + userswap/src/uswap_log.c | 81 +++ + userswap/src/uswap_server.c | 138 ++++ + 28 files changed, 3047 insertions(+) + create mode 100644 memRouter/CMakeLists.txt + create mode 100644 memRouter/README.md + create mode 100644 memRouter/include/memdcd_cmd.h + create mode 100644 memRouter/include/memdcd_daemon.h + create mode 100644 memRouter/include/memdcd_log.h + create mode 100644 memRouter/include/memdcd_message.h + create mode 100644 memRouter/include/memdcd_migrate.h + create mode 100644 memRouter/include/memdcd_policy.h + create mode 100644 memRouter/include/memdcd_policy_threshold.h + create mode 100644 memRouter/include/memdcd_process.h + create mode 100644 memRouter/src/memdcd.c + create mode 100644 memRouter/src/memdcd_cmd.c + create mode 100644 memRouter/src/memdcd_daemon.c + create mode 100644 memRouter/src/memdcd_log.c + create mode 100644 memRouter/src/memdcd_migrate.c + create mode 100644 memRouter/src/memdcd_policy.c + create mode 100644 memRouter/src/memdcd_policy_threshold.c + create mode 100644 memRouter/src/memdcd_process.c + create mode 100644 userswap/CMakeLists.txt + create mode 100644 userswap/License/LICENSE + create mode 100644 userswap/README.md + create mode 100644 userswap/configure.sh + create mode 100644 userswap/include/uswap_api.h + create mode 100644 userswap/include/uswap_log.h + create mode 100644 userswap/include/uswap_server.h + create mode 100644 userswap/src/lib_uswap.c + create mode 100644 userswap/src/uswap_log.c + create mode 100644 userswap/src/uswap_server.c + +diff --git a/memRouter/CMakeLists.txt b/memRouter/CMakeLists.txt +new file mode 100644 +index 0000000..1e55115 +--- /dev/null ++++ b/memRouter/CMakeLists.txt +@@ -0,0 +1,74 @@ ++# /****************************************************************************** ++# * Copyright (c) Huawei Technologies Co., Ltd. 2020-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: YangXin ++# * Create: 2020-09-08 ++# * Description: CMakefileList for memRouter to compile ++# ******************************************************************************/ ++ ++cmake_minimum_required (VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) ++project(memdcd C) ++ ++set(CMAKE_C_STANDARD 99) ++ ++set(LOCAL_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) ++ ++IF(CMAKE_BUILD_TYPE STREQUAL Test) ++ IF(COVERAGE_ENABLE) ++ MESSAGE(STATUS "Enable coverage compile option") ++ SET(COVERAGE_OPTION "${COVERAGE_OPTION} -fprofile-arcs -ftest-coverage") ++ ENDIF(COVERAGE_ENABLE) ++ IF(ASAN_ENABLE) ++ MESSAGE(STATUS "Enable asan compile option") ++ SET(ASAN_OPTIONS "${ASAN_OPTION} -fsanitize=address -fsanitize-recover=address") ++ ENDIF(ASAN_ENABLE) ++ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_DEBUG} ${COVERAGE_OPTION} ${ASAN_OPTIONS}") ++ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_DEBUG} ${COVERAGE_OPTION} ${ASAN_OPTIONS}") ++ add_subdirectory(test) ++ENDIF() ++ ++set(CMAKE_POSITION_INDEPENDENT_CODE ON) ++ ++set(SRC_DIR ${PROJECT_SOURCE_DIR}/src) ++set(INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) ++set(BUILD_DIR ${PROJECT_SOURCE_DIR}/build) ++ ++set(MEMROUTER_SRC ++ ${SRC_DIR}/memdcd.c ++ ${SRC_DIR}/memdcd_policy.c ++ ${SRC_DIR}/memdcd_policy_threshold.c ++ ${SRC_DIR}/memdcd_migrate.c ++ ${SRC_DIR}/memdcd_process.c ++ ${SRC_DIR}/memdcd_daemon.c ++ ${SRC_DIR}/memdcd_cmd.c ++ ${SRC_DIR}/memdcd_log.c ++ ) ++ ++add_executable(memdcd ${MEMROUTER_SRC}) ++ ++target_include_directories(memdcd PRIVATE ++ ${INCLUDE_DIR}/) ++ ++add_definitions(-D_GNU_SOURCE -DNDEBUG -D_FORTIFY_SOURCE=2) ++target_compile_options(memdcd PRIVATE -fsigned-char --param ssp-buffer-size=4 -fno-omit-frame-pointer -Wall -Wextra ++-Wno-missing-field-initializers -Wmissing-declarations -fno-strict-aliasing ++-Wformat -Wformat-security -fPIE -pie -fPIC -ftrapv ++-Wno-error=deprecated-declarations -fstack-protector-all -fno-common -O2 -Wall -Wl,-z,relro,-z,now,-z,noexecstack -Wtrampolines -pthread -Wstrict-prototypes -Wl,--no-whole-archive -Wold-style-definition -std=gnu99 -Wno-error=unused-result -Wno-error=strict-prototypes -Wno-error=old-style-definition -Wno-error=missing-declarations -Wno-error=format-overflow -I${INCLUDE_DIR}) ++ ++if(CONFIG_DEBUG STREQUAL "y") ++ target_compile_options(memdcd PRIVATE -g) ++endif() ++ ++target_link_libraries(memdcd PRIVATE pthread dl rt numa json-c cap -s) ++ ++install(TARGETS memdcd ++ PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE ++ RUNTIME DESTINATION /usr/bin ++ ) +diff --git a/memRouter/README.md b/memRouter/README.md +new file mode 100644 +index 0000000..4350a4c +--- /dev/null ++++ b/memRouter/README.md +@@ -0,0 +1,90 @@ ++# memRouter ++ ++## 介绍 ++ ++随着CPU算力的发展,尤其是ARM核成本的降低,内存成本和内存容量成为约束业务成本和性能的核心痛点,因此如何节省内存成本,如何扩大内存容量成为存储迫切要解决的问题。 ++ ++memRouter内存分级扩展,根据用户选择内存迁移策略对内存进行分级,分发到不同级别的介质上,降低dram的使用量,来达到内存容量扩展的目的。 ++ ++## 编译方法 ++ ++1. 下载memRouter源码 ++``` ++git clone https://gitee.com/openeuler/etmem.git ++``` ++2. 编译和运行依赖 ++ ++ memRouter的编译和运行依赖于libcap-devel、json-c-devel、numactl-devel软件包 ++ ++3. 编译 ++``` ++cd memRouter ++mkdir build ++cd build ++cmake .. ++make ++``` ++ ++## 使用说明 ++ ++### 启动memdcd进程 ++ ++#### 使用方法 ++ ++通过运行memdcd二进制运行服务端进程,例如: ++``` ++memdcd -p xx.json ++``` ++策略配置文件的权限需为600,属主需为当前memRouter启动者 ++#### 命令行参数说明 ++ ++| 参数 | 参数含义 | 是否必须 | 是否有参数 | 参数范围 | 示例说明 | ++| --------------- | ---------------------------------- | -------- | ---------- | --------------------- | ------------------------------------------------------------ | ++| -p或--policy | memRouter日志级别 | 是 | 是 | 有效地址 | memdcd所采用的页面分级策略 ++| -s或--socket | memRouter监听的名称,用于与客户端交互 | 否 | 是 | 107个字符之内的字符串 | 指定服务端监听的unix socket名称 | ++| -l或--log | 帮助信息 | 否 | 是 | LOG_INFO/LOG_DEBUG | LOG_INFO: info级别 LOG_DEBUG: debug级别出 | ++| -t或--timeout | 帮助信息 | 否 | 是 | 0-4294967295 | 收集进程页面信息的时长限制 | ++| -h或--help | 帮助信息 | 否 | 否 | NA | 执行时带有此参数会打印后退出 | ++ ++### 配置文件 ++目前仅支持阈值策略 ++ ++#### 阈值策略配置文件 ++``` ++{ ++ "type": "mig_policy_threshold", ++ "policy": { ++ "unit": "KB", ++ "threshold": 20 ++ } ++} ++``` ++ ++| **配置项** | **配置项含义** | **是否必须** | **是否有参数** | **参数范围** | **示例说明** | ++| ----------- | ------------------------------------------------------------ | ------------ | -------------- | ------------------------- | ------------------------------------------------------------ | ++| type | 采取的分级策略 | 是 | 是 | 暂时支支持mig_policy_threshold | "type": "mig_policy_threshold" | ++| policy | 采取的策略 | 是 | 是 | NA | NA | ++| unit | 采用的单位 | 是 | 是 | KB/MB/GB | "unit": "KB"以KB作为单位 | ++| threshold | 被监控进程的内存阈值 | 是 | 是 | 0~INT32_MAX | "threshold": 20 //限制配监控进程内存上限20KB | ++ ++ ++#### 所需etmemd配置文件: ++各字段含义参见[etmemd](https://gitee.com/openeuler/etmem/blob/master/README.md) ++``` ++options: ++ loop : ${loop} ++ interval : ${interval} ++ sleep: ${sleep} ++ policies: ++ type : pid/name ++ value : ${pid}/${name} ++ max_threads: ${max_threads} ++ engine : memdcd ++``` ++ ++## 参与贡献 ++ ++1. Fork本仓库 ++2. 新建个人分支 ++3. 提交代码 ++4. 新建Pull Request +diff --git a/memRouter/include/memdcd_cmd.h b/memRouter/include/memdcd_cmd.h +new file mode 100644 +index 0000000..757d50c +--- /dev/null ++++ b/memRouter/include/memdcd_cmd.h +@@ -0,0 +1,21 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2021-02-26 ++ * Description: handle receive buffer. ++ ******************************************************************************/ ++#ifndef MEMDCD_CMD_H ++#define MEMDCD_CMD_H ++ ++int handle_recv_buffer(const void *buf, int msg_len); ++ ++#endif // MEMDCD_H ++ +diff --git a/memRouter/include/memdcd_daemon.h b/memRouter/include/memdcd_daemon.h +new file mode 100644 +index 0000000..fa2b641 +--- /dev/null ++++ b/memRouter/include/memdcd_daemon.h +@@ -0,0 +1,23 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2021-02-26 ++ * Description: init memdcd daemon. ++ ******************************************************************************/ ++#ifndef MEMDCD_DAEMON_H ++#define MEMDCD_DAEMON_H ++ ++#define MAX_MESSAGE_LENGTH 40960 ++ ++void *memdcd_daemon_start(const char *sock_path); ++ ++#endif ++ +diff --git a/memRouter/include/memdcd_log.h b/memRouter/include/memdcd_log.h +new file mode 100644 +index 0000000..b29b412 +--- /dev/null ++++ b/memRouter/include/memdcd_log.h +@@ -0,0 +1,34 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2020-10-30 ++ * Description: print log. ++ ******************************************************************************/ ++#ifndef MEMDCD_LOG_H__ ++#define MEMDCD_LOG_H__ ++ ++ ++#define ERROR_STR_MAX_LEN 256 ++ ++enum _log_level { ++ _LOG_ERROR = 0, ++ _LOG_WARN, ++ _LOG_INFO, ++ _LOG_DEBUG, ++}; ++ ++ ++int init_log_level(const char *log_level_str); ++int set_log_level(const int level); ++void memdcd_log(const int level, const char *, ...); ++ ++#endif ++ +diff --git a/memRouter/include/memdcd_message.h b/memRouter/include/memdcd_message.h +new file mode 100644 +index 0000000..9663ef2 +--- /dev/null ++++ b/memRouter/include/memdcd_message.h +@@ -0,0 +1,75 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2021-02-26 ++ * Description: data structure used in interprocess communication. ++ ******************************************************************************/ ++#ifndef MEMDCD_MESSAGE_H ++#define MEMDCD_MESSAGE_H ++#include ++ ++enum memdcd_cmd_type { ++ MEMDCD_CMD_MEM, ++ MEMDCD_CMD_NODE, ++ MEMDCD_CMD_POLICY, ++}; ++ ++enum SwapType { ++ SWAP_TYPE_VMA_ADDR = 0xFFFFFF01, ++ SWAP_TYPE_MAX ++}; ++ ++#define MAX_VMA_NUM 512 ++struct vma_addr { ++ uint64_t start_addr; ++ uint64_t vma_len; ++}; ++ ++struct vma_addr_with_count { ++ struct vma_addr vma; ++ int count; ++}; ++ ++struct swap_vma { ++ enum SwapType type; ++ uint64_t length; ++ struct vma_addr vma_addrs[MAX_VMA_NUM]; ++}; ++ ++enum MEMDCD_MESSAGE_STATUS { ++ MEMDCD_SEND_START, ++ MEMDCD_SEND_PROCESS, ++ MEMDCD_SEND_END, ++}; ++ ++struct swap_vma_with_count { ++ enum SwapType type; ++ uint64_t length; ++ uint64_t total_length; ++ enum MEMDCD_MESSAGE_STATUS status; ++ struct vma_addr_with_count vma_addrs[MAX_VMA_NUM]; ++}; ++ ++struct memory_message { ++ int pid; ++ uint32_t enable_uswap; ++ struct swap_vma_with_count vma; ++}; ++ ++struct memdcd_message { ++ enum memdcd_cmd_type cmd_type; ++ union { ++ struct memory_message memory_msg; ++ }; ++}; ++ ++#endif ++ +diff --git a/memRouter/include/memdcd_migrate.h b/memRouter/include/memdcd_migrate.h +new file mode 100644 +index 0000000..22598e2 +--- /dev/null ++++ b/memRouter/include/memdcd_migrate.h +@@ -0,0 +1,21 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * etmem/memRouter 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: zhangxuzhou ++ * Create: 2020-09-18 ++ * Description: engines migrating memory pages ++ ******************************************************************************/ ++#ifndef MEMDCD_CONNECT_H ++#define MEMDCD_CONNECT_H ++#include "memdcd_process.h" ++ ++int send_to_userswap(int pid, const struct migrate_page_list *pages); ++ ++#endif /* MEMDCD_CONNECT_H */ +diff --git a/memRouter/include/memdcd_policy.h b/memRouter/include/memdcd_policy.h +new file mode 100644 +index 0000000..47c40f5 +--- /dev/null ++++ b/memRouter/include/memdcd_policy.h +@@ -0,0 +1,42 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * etmem/memRouter 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: zhangxuzhou ++ * Create: 2020-09-08 ++ * Description: init policy ++ ******************************************************************************/ ++ ++#ifndef MEMDCD_POLICY_H ++#define MEMDCD_POLICY_H ++#include "memdcd_process.h" ++ ++enum mem_policy_type { ++ POL_TYPE_THRESHOLD, ++ POL_TYPE_MAX, ++}; ++ ++struct mem_policy { ++ enum mem_policy_type type; ++ void *private; ++ struct memdcd_policy_opt *opt; ++}; ++ ++struct memdcd_policy_opt { ++ int (*init)(struct mem_policy *policy, const char *path); ++ int (*parse)(const struct mem_policy *policy, int pid, struct migrate_page_list *page_list, ++ struct migrate_page_list **pages_to_numa, struct migrate_page_list **pages_to_swap); ++ int (*destroy)(struct mem_policy *policy); ++}; ++ ++struct mem_policy *get_policy(void); ++int init_mem_policy(char *path); ++ ++#endif /* MEMDCD_POLICY_H */ ++ +diff --git a/memRouter/include/memdcd_policy_threshold.h b/memRouter/include/memdcd_policy_threshold.h +new file mode 100644 +index 0000000..f75d3e7 +--- /dev/null ++++ b/memRouter/include/memdcd_policy_threshold.h +@@ -0,0 +1,22 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2021-02-26 ++ * Description: head file of threshold policy ++ ******************************************************************************/ ++#ifndef MEMDCD_POLICY_THRESHOLD_H ++#define MEMDCD_POLICY_THRESHOLD_H ++#include "memdcd_policy.h" ++ ++struct memdcd_policy_opt *get_threshold_policy(void); ++ ++#endif ++ +diff --git a/memRouter/include/memdcd_process.h b/memRouter/include/memdcd_process.h +new file mode 100644 +index 0000000..eaa86f8 +--- /dev/null ++++ b/memRouter/include/memdcd_process.h +@@ -0,0 +1,41 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2021-02-26 ++ * Description: process received pages ++ ******************************************************************************/ ++#ifndef MEMDCD_PROCESS_H ++#define MEMDCD_PROCESS_H ++ ++#include ++#include "memdcd_message.h" ++ ++#define DEFAULT_COLLECT_PAGE_TIMEOUT 3 ++ ++struct migrate_page { ++ uint64_t addr; ++ uint64_t length; ++ int visit_count; ++ ++ int numanode; ++}; ++ ++struct migrate_page_list { ++ uint64_t length; ++ struct migrate_page pages[]; ++}; ++ ++void init_collect_pages_timeout(time_t timeout); ++int migrate_process_get_pages(int pid, const struct swap_vma_with_count *vma); ++void migrate_process_exit(void); ++ ++#endif /* MEMDCD_MIGRATE_H */ ++ +diff --git a/memRouter/src/memdcd.c b/memRouter/src/memdcd.c +new file mode 100644 +index 0000000..70f9f7b +--- /dev/null ++++ b/memRouter/src/memdcd.c +@@ -0,0 +1,143 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * etmem/memRouter 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: zhangxuzhou ++ * Create: 2020-09-08 ++ * Description: main function of memdcd. ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "memdcd_policy.h" ++#include "memdcd_daemon.h" ++#include "memdcd_log.h" ++ ++#define DEFAULT_SOCK_PATH "@_memdcd.server" ++#define REQUIRE_CAP_MAX 1 ++#define TIMEOUT_VALID_LEN 10 ++ ++static void usage(void) ++{ ++ printf("Usage: memdcd -p|--policy [options]\n"); ++ printf(" -p --policy specify policy config file\n"); ++ printf(" -s --socket specify socket path. default: %s\n", DEFAULT_SOCK_PATH); ++ printf(" -l --log LOG_INFO|LOG_DEBUG set log level to print. default: LOG_INFO\n"); ++ printf(" -t --timeout set timeout for collect pages by second.\n"); ++ printf(" set 0 to disable timeout. default: %d\n", DEFAULT_COLLECT_PAGE_TIMEOUT); ++ printf(" -h --help show this help info\n"); ++} ++ ++static int check_permission(void) ++{ ++ cap_t cap = NULL; ++ cap_flag_value_t cap_flag_value = CAP_CLEAR; ++ cap_value_t cap_val = 0; ++ const char *req_cap[REQUIRE_CAP_MAX] = { ++ "cap_sys_nice" ++ }; ++ ++ cap = cap_get_proc(); ++ if (cap == NULL) { ++ memdcd_log(_LOG_ERROR, "Get capability error."); ++ return -1; ++ } ++ for (int i = 0; i < REQUIRE_CAP_MAX; i++) { ++ cap_from_name(req_cap[i], &cap_val); ++ cap_get_flag(cap, cap_val, CAP_EFFECTIVE, &cap_flag_value); ++ if (cap_flag_value != CAP_SET) { ++ memdcd_log(_LOG_ERROR, "Not sufficient capacity: %s.", req_cap[i]); ++ cap_free(cap); ++ return -1; ++ } ++ } ++ cap_free(cap); ++ return 0; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int opt; ++ struct option long_options[] = { ++ {"policy", required_argument, NULL, 'p'}, ++ {"socket", required_argument, NULL, 's'}, ++ {"log", required_argument, NULL, 'l'}, ++ {"timeout", required_argument, NULL, 't'}, ++ {"help", no_argument, NULL, 'h'}, ++ {NULL, 0, NULL, 0}, ++ }; ++ time_t timeout; ++ char *policy_file = NULL, *socket_path = NULL; ++ char *endptr = NULL; ++ ++ while ((opt = getopt_long(argc, argv, "p:s:l:t:h", long_options, NULL)) != -1) { ++ switch (opt) { ++ case 'p': ++ policy_file = optarg; ++ break; ++ case 's': ++ socket_path = optarg; ++ break; ++ case 'l': ++ if (init_log_level(optarg) < 0) { ++ printf("error parsing log level: %s\n", optarg); ++ return -EINVAL; ++ } ++ break; ++ case 't': ++ errno = 0; ++ timeout = strtol(optarg, &endptr, TIMEOUT_VALID_LEN); ++ if (errno || optarg == endptr || (endptr && *endptr != ' ' && *endptr != '\0') || timeout < 0) { ++ printf("error parsing timeout %s\n", optarg); ++ return -EINVAL; ++ } ++ init_collect_pages_timeout(timeout); ++ break; ++ case 'h': ++ usage(); ++ return 0; ++ default: ++ usage(); ++ return -EINVAL; ++ } ++ } ++ ++ if (policy_file == NULL) { ++ printf("policy file should be assigned\n"); ++ usage(); ++ return 0; ++ } ++ if (socket_path == NULL) ++ socket_path = DEFAULT_SOCK_PATH; ++ ++ if (check_permission() != 0) { ++ memdcd_log(_LOG_ERROR, "This program is lack of nessary privileges."); ++ return -1; ++ } ++ ++ if (init_mem_policy(policy_file) != 0) { ++ memdcd_log(_LOG_ERROR, "Error parsing policy from policy config file %s.", policy_file); ++ return -1; ++ } ++ ++ memdcd_daemon_start(socket_path); ++ ++ return 0; ++} +diff --git a/memRouter/src/memdcd_cmd.c b/memRouter/src/memdcd_cmd.c +new file mode 100644 +index 0000000..9f3fcc0 +--- /dev/null ++++ b/memRouter/src/memdcd_cmd.c +@@ -0,0 +1,93 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2021-02-26 ++ * Description: handle receive buffer. ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "memdcd_process.h" ++#include "memdcd_log.h" ++#include "memdcd_cmd.h" ++ ++#define FILEPATH_MAX_LEN 64 ++ ++static uint64_t get_process_vmsize(int pid) ++{ ++ char statm_path[FILEPATH_MAX_LEN]; ++ FILE *fp = NULL; ++ uint64_t vmsize; ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ ++ if (snprintf(statm_path, FILEPATH_MAX_LEN, "/proc/%d/statm", pid) <= 0) { ++ memdcd_log(_LOG_ERROR, "memdcd_uswap: snprintf for statm_path from pid %d failed.", pid); ++ return -1; ++ } ++ fp = fopen(statm_path, "r"); ++ if (fp == NULL) { ++ memdcd_log(_LOG_ERROR, "Error opening statm file %s: %s.", statm_path, error_str); ++ return 0; ++ } ++ if (fscanf(fp, "%lu", &vmsize) <= 0) { ++ memdcd_log(_LOG_ERROR, "Error reading file %s. err: %s", ++ statm_path, strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ fclose(fp); ++ return 0; ++ } ++ fclose(fp); ++ return vmsize; ++} ++ ++static int handle_mem_message(const struct memory_message *msg) ++{ ++ uint64_t total_pages = get_process_vmsize(msg->pid); ++ if (total_pages == 0) { ++ memdcd_log(_LOG_ERROR, "Error getting vmsize of process %d.", msg->pid); ++ return -1; ++ } else if (total_pages < msg->vma.total_length) { ++ memdcd_log(_LOG_ERROR, "Total page num of process %lu is less than incoming page num %lu.", ++ total_pages, msg->vma.total_length); ++ return -1; ++ } ++ ++ if (msg->vma.length / sizeof(struct vma_addr_with_count) > MAX_VMA_NUM) { ++ memdcd_log(_LOG_ERROR, "Invalid message length %lu.", msg->vma.length); ++ return -1; ++ } ++ ++ return migrate_process_get_pages(msg->pid, &msg->vma); ++} ++ ++int handle_recv_buffer(const void *buffer, int msg_len) ++{ ++ struct memdcd_message *msg = (struct memdcd_message *)buffer; ++ if (msg_len != sizeof(struct memdcd_message)) { ++ memdcd_log(_LOG_ERROR, "Invalid recv message length %d.", msg_len); ++ return -1; ++ } ++ memdcd_log(_LOG_DEBUG, "Type: %d.", msg->cmd_type); ++ ++ switch (msg->cmd_type) { ++ case MEMDCD_CMD_MEM: ++ return handle_mem_message(&msg->memory_msg); ++ default: ++ memdcd_log(_LOG_ERROR, "Invalid cmd type."); ++ return -1; ++ } ++ return 0; ++} +\ No newline at end of file +diff --git a/memRouter/src/memdcd_daemon.c b/memRouter/src/memdcd_daemon.c +new file mode 100644 +index 0000000..f88593d +--- /dev/null ++++ b/memRouter/src/memdcd_daemon.c +@@ -0,0 +1,257 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2021-02-26 ++ * Description: init memdcd daemon. ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "memdcd_log.h" ++#include "memdcd_process.h" ++#include "memdcd_cmd.h" ++#include "memdcd_daemon.h" ++ ++#define MAX_PENDING_QUEUE_LENGTH 64 ++#define MAX_SOCK_PATH_LENGTH 108 ++ ++static volatile sig_atomic_t g_sock_fd; ++static volatile sig_atomic_t g_exit_signal; ++ ++static void _set_exit_flag(int s) ++{ ++ (void)s; ++ g_exit_signal = 1; ++ if (g_sock_fd > 0) { ++ close(g_sock_fd); ++ } ++ g_sock_fd = -1; ++} ++ ++static void memdcd_install_signal(void) ++{ ++ signal(SIGINT, _set_exit_flag); ++ signal(SIGTERM, _set_exit_flag); ++} ++ ++ ++static int _set_socket_option(int sock_fd) ++{ ++ int rc; ++ int buf_len = MAX_MESSAGE_LENGTH; ++ struct timeval timeout = {5, 0}; ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ ++ /* set timeout limit to socket for sending */ ++ rc = setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout)); ++ if (rc < 0) { ++ memdcd_log(_LOG_ERROR, "Set send timeout for socket failed. err: %s", ++ strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ return -1; ++ } ++ ++ /* set max length of buffer to recive */ ++ rc = setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, (const char *)&buf_len, sizeof(buf_len)); ++ if (rc < 0) { ++ memdcd_log(_LOG_ERROR, "Set recive buffer length for socket failed. err: %s", ++ strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ return -1; ++ } ++ ++ /* set max length of buffer to send */ ++ rc = setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, (const char *)&buf_len, sizeof(buf_len)); ++ if (rc < 0) { ++ memdcd_log(_LOG_ERROR, "Set send buffer length for socket failed. err: %s", ++ strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int memdcd_server_init(const char *sock_path) ++{ ++ int sock_fd; ++ struct sockaddr_un sock_addr; ++ size_t sock_len; ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ ++ memset(&sock_addr, 0, sizeof(struct sockaddr_un)); ++ ++ sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (sock_fd < 0) { ++ memdcd_log(_LOG_ERROR, "Create socket for fail. err: %s", strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ return -1; ++ } ++ ++ sock_len = strlen(sock_path); ++ if (sock_len >= MAX_SOCK_PATH_LENGTH) { ++ memdcd_log(_LOG_ERROR, "Socket path is too long."); ++ close(sock_fd); ++ return -1; ++ } ++ sock_addr.sun_family = AF_UNIX; ++ memcpy(sock_addr.sun_path, sock_path, sock_len); ++ ++ sock_addr.sun_path[0] = 0; ++ sock_len += offsetof(struct sockaddr_un, sun_path); ++ ++ if (_set_socket_option(sock_fd) != 0) { ++ memdcd_log(_LOG_ERROR, "Set for socket fail. err: %s", strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ close(sock_fd); ++ return -1; ++ } ++ ++ if (bind(sock_fd, (struct sockaddr *)&sock_addr, sock_len) != 0) { ++ memdcd_log(_LOG_ERROR, "Socket bind %s fail. err: %s", ++ (char *)&sock_addr.sun_path[1], strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ close(sock_fd); ++ return -1; ++ } ++ ++ return sock_fd; ++} ++ ++static int check_socket_permission(int sock_fd) ++{ ++ struct ucred cred; ++ socklen_t len; ++ ssize_t rc; ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ ++ len = sizeof(struct ucred); ++ ++ rc = getsockopt(sock_fd, ++ SOL_SOCKET, ++ SO_PEERCRED, ++ &cred, ++ &len); ++ if (rc < 0) { ++ memdcd_log(_LOG_ERROR, "Getsockopt failed. err: %s\n", strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ return -1; ++ } ++ ++ if (cred.uid != 0 || cred.gid != 0) { ++ memdcd_log(_LOG_ERROR, "Socket connect failed, need recieving from app of root privilege.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int memdcd_accept(char *recv_buf) ++{ ++ int accp_fd = -1; ++ int ret = 0; ++ ssize_t rc; ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ ++ accp_fd = accept(g_sock_fd, NULL, NULL); ++ if (accp_fd < 0) { ++ memdcd_log(_LOG_ERROR, "Accept message failed. err: %s", strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ return -1; ++ } ++ ++ rc = check_socket_permission(accp_fd); ++ if (rc != 0) { ++ ret = rc; ++ goto close_fd; ++ } ++ ++ rc = recv(accp_fd, recv_buf, MAX_MESSAGE_LENGTH, 0); ++ if (rc <= 0) { ++ memdcd_log(_LOG_WARN, "Socket recive from client fail. err: %s", \ ++ strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ ret = -1; ++ goto close_fd; ++ } ++ ++ if (rc > MAX_MESSAGE_LENGTH) { ++ memdcd_log(_LOG_WARN, "Buffer sent to memdcd is too long, should be less than %d.", MAX_MESSAGE_LENGTH); ++ ret = -1; ++ goto close_fd; ++ } ++ ++ memdcd_log(_LOG_DEBUG, "Memdcd got one connection."); ++ ret = rc; ++ ++close_fd: ++ close(accp_fd); ++ return ret; ++} ++ ++void *memdcd_daemon_start(const char *sock_path) ++{ ++ char *recv_buf = NULL; ++ int msg_len; ++ int sock_fd; ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ ++ if (sock_path == NULL) { ++ return NULL; ++ } ++ g_exit_signal = 0; ++ g_sock_fd = 0; ++ memdcd_install_signal(); ++ ++ sock_fd = memdcd_server_init(sock_path); ++ if (sock_fd < 0) ++ return NULL; ++ ++ recv_buf = (char *)malloc(sizeof(char) * MAX_MESSAGE_LENGTH); ++ if (recv_buf == NULL) { ++ memdcd_log(_LOG_ERROR, "Failed to alloc buffer to receive message."); ++ close(sock_fd); ++ sock_fd = -1; ++ return NULL; ++ } ++ ++ /* allow RPC_CLIENT_MAX clients to connect at the same time */ ++ if (listen(sock_fd, MAX_PENDING_QUEUE_LENGTH) != 0) { ++ memdcd_log(_LOG_ERROR, "Error listening on socket %s. err: %s", ++ sock_path, strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ close(sock_fd); ++ sock_fd = -1; ++ goto free_buf; ++ } ++ ++ if (g_sock_fd < 0) { ++ close(sock_fd); ++ sock_fd = -1; ++ goto free_buf; ++ } ++ g_sock_fd = sock_fd; ++ memdcd_log(_LOG_INFO, "Start listening on %s.", sock_path); ++ while (g_exit_signal == 0) { ++ msg_len = memdcd_accept(recv_buf); ++ if (msg_len < 0) { ++ memdcd_log(_LOG_ERROR, "Error accepting message. err: %s", strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ continue; ++ } ++ if (handle_recv_buffer(recv_buf, msg_len) < 0) ++ memdcd_log(_LOG_DEBUG, "Error handling message."); ++ } ++ migrate_process_exit(); ++ ++ if (g_sock_fd > 0) { ++ close(g_sock_fd); ++ g_sock_fd = -1; ++ } ++free_buf: ++ free(recv_buf); ++ return NULL; ++} +diff --git a/memRouter/src/memdcd_log.c b/memRouter/src/memdcd_log.c +new file mode 100644 +index 0000000..125fced +--- /dev/null ++++ b/memRouter/src/memdcd_log.c +@@ -0,0 +1,80 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2020-10-30 ++ * Description: print log. ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "memdcd_log.h" ++ ++static int log_level = 0; ++ ++int set_log_level(const int level) ++{ ++ log_level = level; ++ return log_level; ++} ++ ++int init_log_level(const char *log_level_str) ++{ ++ if (log_level_str == NULL) ++ return set_log_level(_LOG_INFO); ++ if (strcmp(log_level_str, "LOG_DEBUG") == 0) ++ return set_log_level(_LOG_DEBUG); ++ if (strcmp(log_level_str, "LOG_INFO") == 0) ++ return set_log_level(_LOG_INFO); ++ if (strcmp(log_level_str, "LOG_WARN") == 0) ++ return set_log_level(_LOG_WARN); ++ if (strcmp(log_level_str, "LOG_ERROR") == 0) ++ return set_log_level(_LOG_ERROR); ++ memdcd_log(_LOG_ERROR, "Error initint log_level: %s.", log_level_str); ++ return -EINVAL; ++} ++ ++void memdcd_log(const int level, const char *va_alist, ...) ++{ ++ va_list ap; ++ ++ if (level > log_level) ++ return; ++ ++ va_start(ap, va_alist); ++ switch (level) { ++ case _LOG_INFO: ++ openlog("[MEMDCD_INFO] ", LOG_PID, LOG_USER); ++ vsyslog(LOG_INFO, va_alist, ap); ++ break; ++ case _LOG_DEBUG: ++ openlog("[MEMDCD_DEBUG] ", LOG_PID, LOG_USER); ++ vsyslog(LOG_INFO, va_alist, ap); ++ break; ++ case _LOG_WARN: ++ openlog("[MEMDCD_WARNING] ", LOG_PID, LOG_USER); ++ vsyslog(LOG_WARNING, va_alist, ap); ++ break; ++ case _LOG_ERROR: ++ openlog("[MEMDCD_ERROR] ", LOG_PID, LOG_USER); ++ vsyslog(LOG_ERR, va_alist, ap); ++ break; ++ default: ++ va_end(ap); ++ return; ++ } ++ ++ va_end(ap); ++ closelog(); ++ return; ++} +\ No newline at end of file +diff --git a/memRouter/src/memdcd_migrate.c b/memRouter/src/memdcd_migrate.c +new file mode 100644 +index 0000000..4017033 +--- /dev/null ++++ b/memRouter/src/memdcd_migrate.c +@@ -0,0 +1,150 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * etmem/memRouter 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: zhangxuzhou ++ * Create: 2020-09-18 ++ * Description: engines migrating memory pages ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "memdcd_policy.h" ++#include "memdcd_process.h" ++#include "memdcd_log.h" ++#include "memdcd_migrate.h" ++ ++#define CLIENT_RECV_DEFAULT_TIME 10 // default 10s ++#define RESP_MSG_MAX_LEN 10 ++#define FILEPATH_MAX_LEN 64 ++ ++static int uswap_init_connection(int server_pid, time_t recv_timeout) ++{ ++ socklen_t addrlen; ++ struct timeval timeout; ++ struct sockaddr_un addr; ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ ++ int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0); ++ if (socket_fd < 0) { ++ memdcd_log(_LOG_ERROR, "memdcd_uswap: Error opening socket."); ++ return -1; ++ } ++ ++ /* set recv timeout */ ++ timeout.tv_sec = recv_timeout; ++ timeout.tv_usec = 0; ++ if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(struct timeval)) != 0) { ++ memdcd_log(_LOG_ERROR, "memdcd_uswap: Setsockopt set recv timeout failed!"); ++ close(socket_fd); ++ return -1; ++ } ++ ++ bzero(&addr, sizeof(struct sockaddr_un)); ++ /* UNIX domain Socket abstract namespace */ ++ addr.sun_family = AF_UNIX; ++ addr.sun_path[0] = 0; ++ ++ if (snprintf(addr.sun_path + 1, FILEPATH_MAX_LEN, "userswap%d.sock", server_pid) <= 0) { ++ memdcd_log(_LOG_ERROR, "memdcd_uswap: Snprintf_s for abtract_path from pid %d failed.", server_pid); ++ close(socket_fd); ++ return -1; ++ } ++ ++ addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path + 1) + 1; ++ if (connect(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) { ++ memdcd_log(_LOG_ERROR, "memdcd_uswap: Connect failed. err: %s! ", \ ++ strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ close(socket_fd); ++ return -1; ++ } ++ ++ return socket_fd; ++} ++ ++static int uswap_send_data(int client_fd, int server_pid, const struct swap_vma *swap_vma) ++{ ++ int ret = 0; ++ int read_bytes; ++ int write_bytes; ++ int in_datalen; ++ char buff[RESP_MSG_MAX_LEN] = {0}; ++ int len = strlen("success"); ++ ++ in_datalen = swap_vma->length + sizeof(int) + sizeof(long); ++ write_bytes = write(client_fd, swap_vma, in_datalen); ++ if (write_bytes <= 0) { ++ memdcd_log(_LOG_DEBUG, "memdcd_uswap: Write to pid %d server, bytes: %d.", server_pid, write_bytes); ++ return -1; ++ } ++ ++ read_bytes = read(client_fd, buff, RESP_MSG_MAX_LEN - 1); ++ if (read_bytes >= len && strncmp(buff, "success", len) == 0) { ++ memdcd_log(_LOG_DEBUG, "memdcd_uswap: Recv respond success."); ++ } else { ++ memdcd_log(_LOG_DEBUG, "memdcd_uswap: Recv respond failed."); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++static int min(int a, int b) ++{ ++ return a < b ? a : b; ++} ++ ++int send_to_userswap(int pid, const struct migrate_page_list *page_list) ++{ ++ int ret = 0; ++ struct swap_vma *swap_vma = NULL; ++ int client_fd; ++ uint64_t i, rest, size; ++ uint64_t dst; ++ if (page_list->pages == NULL) { ++ memdcd_log(_LOG_WARN, "memdcd_uswap: Mig_addrs NULL."); ++ return 0; ++ } ++ memdcd_log(_LOG_INFO, "Send %lu addresses to userswap: pid %d.", page_list->length, pid); ++ swap_vma = (struct swap_vma *)malloc(sizeof(struct swap_vma)); ++ if (swap_vma == NULL) { ++ memdcd_log(_LOG_WARN, "memdcd_uswap: Malloc for swap vma failed."); ++ return -ENOMEM; ++ } ++ swap_vma->type = SWAP_TYPE_VMA_ADDR; ++ rest = page_list->length; ++ while (rest > 0) { ++ client_fd = uswap_init_connection(pid, CLIENT_RECV_DEFAULT_TIME); ++ if (client_fd < 0) { ++ ret = -1; ++ break; ++ } ++ size = min(rest, MAX_VMA_NUM); ++ ++ swap_vma->length = size * sizeof(struct vma_addr); ++ for (i = 0; i < size; i++) { ++ dst = page_list->length - rest + i; ++ swap_vma->vma_addrs[i].start_addr = page_list->pages[dst].addr; ++ swap_vma->vma_addrs[i].vma_len = page_list->pages[dst].length; ++ } ++ if (uswap_send_data(client_fd, pid, swap_vma) != 0) ++ ret = -1; ++ close(client_fd); ++ rest -= size; ++ } ++ ++ free(swap_vma); ++ return ret; ++} +\ No newline at end of file +diff --git a/memRouter/src/memdcd_policy.c b/memRouter/src/memdcd_policy.c +new file mode 100644 +index 0000000..063dbfc +--- /dev/null ++++ b/memRouter/src/memdcd_policy.c +@@ -0,0 +1,132 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * etmem/memRouter 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: zhangxuzhou ++ * Create: 2020-09-08 ++ * Description: init policy ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "memdcd_log.h" ++#include "memdcd_policy_threshold.h" ++#include "memdcd_policy.h" ++ ++#define FULL_PERMISSION 0777 ++ ++static struct { ++ char *name; ++ enum mem_policy_type type; ++ struct memdcd_policy_opt * (*get_opt)(void); ++} mem_policy_opts[] = { ++ {"mig_policy_threshold", POL_TYPE_THRESHOLD, get_threshold_policy}, ++ {NULL, POL_TYPE_MAX, NULL}, ++}; ++ ++struct mem_policy g_policy; ++ ++static int check_policy_file_permission(const char *path) ++{ ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ struct stat permission_buffer; ++ ++ if (stat(path, &permission_buffer) != 0) { ++ memdcd_log(_LOG_ERROR, "Get file stat failed. err: %s", ++ strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ return -1; ++ } ++ ++ if (permission_buffer.st_uid != geteuid()) { ++ memdcd_log(_LOG_ERROR, "Owner of config file is not same with user of this process."); ++ return -EACCES; ++ } ++ ++ if ((permission_buffer.st_mode & FULL_PERMISSION) != (S_IRUSR | S_IWUSR)) { ++ memdcd_log(_LOG_ERROR, "Access permission of config file is not 600."); ++ return -EACCES; ++ } ++ ++ return 0; ++} ++ ++static int parse_policy_type(const char *path) ++{ ++ int i; ++ const char *str = NULL; ++ ++ json_object *root = json_object_from_file(path); ++ if (root == NULL) ++ return -1; ++ ++ json_object *type = json_object_object_get(root, "type"); ++ if (type == NULL) ++ return -1; ++ ++ str = json_object_get_string(type); ++ if (str == NULL) ++ return -1; ++ ++ for (i = 0; mem_policy_opts[i].name != NULL; i++) { ++ if (strcmp(str, mem_policy_opts[i].name) == 0) { ++ return i; ++ } ++ } ++ ++ return -1; ++} ++ ++int init_mem_policy(char *path) ++{ ++ int ret; ++ int type; ++ struct memdcd_policy_opt *opt = NULL; ++ char file_path[PATH_MAX] = {0}; ++ ++ if (!realpath(path, file_path)) { ++ memdcd_log(_LOG_ERROR, "Config file not exist."); ++ return -EEXIST; ++ } ++ ret = check_policy_file_permission(file_path); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ type = parse_policy_type(file_path); ++ if (type < 0) ++ return -EINVAL; ++ ++ memdcd_log(_LOG_DEBUG, "%s: type: %d.", __func__, g_policy.type); ++ ++ opt = mem_policy_opts[type].get_opt(); ++ ++ ret = opt->init(&g_policy, file_path); ++ if (ret != 0) ++ return ret; ++ ++ return 0; ++} ++ ++struct mem_policy *get_policy(void) ++{ ++ return &g_policy; ++} +diff --git a/memRouter/src/memdcd_policy_threshold.c b/memRouter/src/memdcd_policy_threshold.c +new file mode 100644 +index 0000000..3b5e1dc +--- /dev/null ++++ b/memRouter/src/memdcd_policy_threshold.c +@@ -0,0 +1,209 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2021-02-26 ++ * Description: function of threshold policy ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "memdcd_log.h" ++#include "memdcd_policy.h" ++#include "memdcd_process.h" ++#include "memdcd_policy_threshold.h" ++ ++struct threshold_policy { ++ uint64_t threshold; ++}; ++ ++int threshold_policy_init(struct mem_policy *policy, const char *path); ++int threshold_policy_parse(const struct mem_policy *policy, int pid, struct migrate_page_list *page_list, ++ struct migrate_page_list **pages_to_numa, struct migrate_page_list **pages_to_swap); ++int threshold_policy_destroy(struct mem_policy *policy); ++ ++struct memdcd_policy_opt threshold_policy_opt = { ++ .init = threshold_policy_init, ++ .parse = threshold_policy_parse, ++ .destroy = threshold_policy_destroy, ++}; ++ ++int threshold_policy_init(struct mem_policy *policy, const char *path) ++{ ++ int ret = 0; ++ json_object *root = NULL, *obj_policy = NULL, *unit = NULL, *threshold = NULL; ++ int th_val = -1; ++ const char *str = NULL; ++ struct threshold_policy *t = (struct threshold_policy *)malloc(sizeof(struct threshold_policy)); ++ if (t == NULL) ++ return -1; ++ ++ root = json_object_from_file(path); ++ if (root == NULL) { ++ ret = -1; ++ goto err_out; ++ } ++ ++ obj_policy = json_object_object_get(root, "policy"); ++ if (obj_policy == NULL) { ++ ret = -1; ++ goto err_out; ++ } ++ ++ unit = json_object_object_get(obj_policy, "unit"); ++ if (unit == NULL) { ++ ret = -1; ++ goto err_out; ++ } ++ ++ threshold = json_object_object_get(obj_policy, "threshold"); ++ if (threshold == NULL) { ++ ret = -1; ++ goto err_out; ++ } ++ ++ th_val = json_object_get_int(threshold); ++ if (th_val == INT32_MAX || th_val < 0) { ++ memdcd_log(_LOG_ERROR, "Invalid threshold value, allowed range is [0, INT_MAX)."); ++ ret = -1; ++ goto err_out; ++ } ++ ++ str = json_object_get_string(unit); ++ if (str == NULL) { ++ ret = -1; ++ goto err_out; ++ } ++ ++ memdcd_log(_LOG_INFO, "Threshold policy loaded."); ++ if (strcmp("B", str) == 0) { ++ t->threshold = th_val; ++ } else if (strcmp("KB", str) == 0) { ++ t->threshold = (uint64_t)th_val * 1024; ++ } else if (strcmp("MB", str) == 0) { ++ t->threshold = (uint64_t)th_val * 1024 * 1024; ++ } else if (strcmp("GB", str) == 0) { ++ t->threshold = (uint64_t)th_val * 1024 * 1024 * 1024; ++ } else { ++ memdcd_log(_LOG_ERROR, "Detected invalid threshold setting. Abort."); ++ ret = -1; ++ goto err_out; ++ } ++ ++ policy->type = POL_TYPE_THRESHOLD; ++ policy->opt = &threshold_policy_opt; ++ policy->private = t; ++ ++ return 0; ++ ++err_out: ++ free(t); ++ return ret; ++} ++ ++static int addr_cmp_by_count(const void *a, const void *b) ++{ ++ return ((struct migrate_page *)a)->visit_count - ((struct migrate_page *)b)->visit_count; ++} ++ ++int threshold_policy_parse(const struct mem_policy *policy, int pid, struct migrate_page_list *page_list, ++ struct migrate_page_list **pages_to_numa, struct migrate_page_list **pages_to_swap) ++{ ++ int ret = 0; ++ uint64_t swap_count = 0; ++ uint64_t sum_size = 0; ++ int *status = NULL; ++ uint64_t *move_addr = NULL; ++ uint64_t length = page_list->length; ++ ++ (void)pages_to_numa; ++ ++ qsort(page_list->pages, length, sizeof(struct migrate_page), addr_cmp_by_count); ++ ++ status = malloc(sizeof(int) * length); ++ if (status == NULL) ++ return -1; ++ ++ move_addr = malloc(sizeof(uint64_t) * length); ++ if (move_addr == NULL) { ++ free(status); ++ return -1; ++ } ++ ++ for (uint64_t i = 0; i < length; i++) ++ move_addr[i] = page_list->pages[i].addr; ++ ++ if (move_pages(pid, length, (void **)move_addr, NULL, status, MPOL_MF_MOVE) < 0) { ++ memdcd_log(_LOG_ERROR, "Error when locate node for src_addr by move_page."); ++ ret = -1; ++ goto tpp_err_out; ++ } ++ ++ for (int64_t i = length - 1; i >= 0; i--) { ++ page_list->pages[i].numanode = status[i]; ++ if (status[i] < 0) { // negative means not on a numa node ++ memdcd_log(_LOG_DEBUG, "memdcd_migrate: Error getting current node of page %lx: %d, %ld.", ++ move_addr[i], status[i], i); ++ continue; ++ } ++ ++ /*judge if Integer Overflow happen*/ ++ if (sum_size + page_list->pages[i].length < sum_size) { ++ ret = -1; ++ goto tpp_err_out; ++ } ++ sum_size += page_list->pages[i].length; ++ if (sum_size < ((struct threshold_policy *)policy->private)->threshold) ++ continue; ++ ++ swap_count++; ++ // reuse the second half array ++ page_list->pages[length - swap_count] = page_list->pages[i]; ++ } ++ ++ *pages_to_swap = malloc(sizeof(struct migrate_page) * swap_count + sizeof(struct migrate_page_list)); ++ if (*pages_to_swap == NULL) { ++ memdcd_log(_LOG_ERROR, "memdcd_migrate: error allocating space for pages_to_swap."); ++ ret = -1; ++ goto tpp_err_out; ++ } ++ ++ memcpy((*pages_to_swap)->pages, page_list->pages + length - swap_count, sizeof(struct migrate_page) * swap_count); ++ (*pages_to_swap)->length = swap_count; ++ ++tpp_err_out: ++ free(status); ++ free(move_addr); ++ return ret; ++} ++ ++int threshold_policy_destroy(struct mem_policy *policy) ++{ ++ if (policy == NULL) { ++ return -1; ++ } ++ if (policy->private == NULL) { ++ return -1; ++ } ++ free(policy->private); ++ policy->private = NULL; ++ return 0; ++} ++ ++struct memdcd_policy_opt *get_threshold_policy(void) ++{ ++ return &threshold_policy_opt; ++} +diff --git a/memRouter/src/memdcd_process.c b/memRouter/src/memdcd_process.c +new file mode 100644 +index 0000000..8b2ef71 +--- /dev/null ++++ b/memRouter/src/memdcd_process.c +@@ -0,0 +1,345 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. ++ * etmem/memRouter 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: liruilin ++ * Create: 2021-02-26 ++ * Description: process received pages ++ ******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "memdcd_log.h" ++#include "memdcd_policy.h" ++#include "memdcd_migrate.h" ++#include "memdcd_message.h" ++ ++#define PID_MAX_FILE "/proc/sys/kernel/pid_max" ++#define PID_MAX_LEN 256 ++ ++struct migrate_process { ++ int pid; ++ ++ struct migrate_page_list *page_list; ++ uint64_t offset; ++ struct timeval timestamp; ++ ++ pthread_t worker; ++ ++ struct migrate_process *prev; ++ struct migrate_process *next; ++}; ++ ++struct migrate_process g_process_head = { ++ .prev = &g_process_head, ++ .next = &g_process_head, ++}; ++pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++time_t collect_page_timeout = DEFAULT_COLLECT_PAGE_TIMEOUT; ++ ++static void migrate_process_free(struct migrate_process *p) ++{ ++ p->prev->next = p->next; ++ p->next->prev = p->prev; ++ ++ if (p->page_list) ++ free(p->page_list); ++ free(p); ++} ++ ++static void migrate_process_remove(int pid) ++{ ++ struct migrate_process *cur; ++ ++ cur = g_process_head.next; ++ ++ memdcd_log(_LOG_DEBUG, "Remove process %d.", pid); ++ while (cur != &g_process_head) { ++ if (cur->pid == pid) ++ break; ++ cur = cur->next; ++ } ++ if (cur == &g_process_head) { ++ memdcd_log(_LOG_DEBUG, "Failed to remove process %d: not exist.", pid); ++ return; ++ } ++ ++ migrate_process_free(cur); ++ memdcd_log(_LOG_DEBUG, "End free process %d.", pid); ++} ++ ++static struct migrate_process *migrate_process_search(int pid) ++{ ++ struct migrate_process *cur; ++ ++ cur = g_process_head.next; ++ while (cur != &g_process_head) { ++ if (cur->pid == pid) { ++ return cur; ++ } ++ cur = cur->next; ++ } ++ ++ return NULL; ++} ++ ++static struct migrate_process *migrate_process_add(int pid, uint64_t len) ++{ ++ struct migrate_process *process = NULL; ++ ++ process = (struct migrate_process *)malloc(sizeof(struct migrate_process)); ++ if (process == NULL) ++ return NULL; ++ ++ process->page_list = ++ (struct migrate_page_list *)malloc(sizeof(struct migrate_page) * len + sizeof(struct migrate_page_list)); ++ if (process->page_list == NULL) { ++ free(process); ++ return NULL; ++ } ++ ++ process->pid = pid; ++ process->page_list->length = len; ++ process->offset = 0; ++ process->worker = 0; ++ ++ process->next = g_process_head.next; ++ process->next->prev = process; ++ g_process_head.next = process; ++ process->prev = &g_process_head; ++ ++ memdcd_log(_LOG_INFO, "Add new process %d.", pid); ++ ++ return process; ++} ++ ++static void migrate_process_recycle(void) ++{ ++ static struct timeval last = {0}; ++ struct timeval now; ++ struct migrate_process *iter = g_process_head.next, *next = NULL; ++ time_t time_lag; ++ ++ if (collect_page_timeout == 0) ++ return; ++ ++ gettimeofday(&now, NULL); ++ if (last.tv_sec == 0 || now.tv_sec - last.tv_sec < collect_page_timeout) { ++ last = now; ++ return; ++ } ++ last = now; ++ ++ pthread_mutex_lock(&mutex); ++ while (iter != &g_process_head) { ++ next = iter->next; ++ time_lag = now.tv_sec - iter->timestamp.tv_sec; ++ if (time_lag > collect_page_timeout && !(iter->worker && pthread_tryjoin_np(iter->worker, NULL) == EBUSY)) { ++ memdcd_log(_LOG_WARN, "Process exceed collect page timeout %ld: %ld.", time_lag, collect_page_timeout); ++ migrate_process_free(iter); ++ } ++ iter = next; ++ } ++ pthread_mutex_unlock(&mutex); ++ ++} ++ ++static pthread_t get_active_tid(void) ++{ ++ pthread_mutex_lock(&mutex); ++ struct migrate_process *iter = g_process_head.next; ++ pthread_t tid = iter->worker; ++ pthread_mutex_unlock(&mutex); ++ return (iter == &g_process_head) ? 0 : tid; ++} ++ ++void migrate_process_exit(void) ++{ ++ pthread_t tid; ++ migrate_process_recycle(); ++ while ((tid = get_active_tid()) != 0) { ++ pthread_join(tid, NULL); ++ } ++} ++ ++static struct migrate_process *migrate_process_collect_pages(int pid, const struct swap_vma_with_count *vma) ++{ ++ uint64_t count = vma->length / sizeof(struct vma_addr_with_count); ++ struct migrate_process *process = NULL; ++ uint64_t i; ++ ++ migrate_process_recycle(); ++ ++ pthread_mutex_lock(&mutex); ++ process = migrate_process_search(pid); ++ if (process != NULL) { ++ if (process->worker != 0 && pthread_tryjoin_np(process->worker, NULL) == EBUSY) { ++ memdcd_log(_LOG_DEBUG, "Previous send work of process %d has been doing. discard pages.", pid); ++ pthread_mutex_unlock(&mutex); ++ return NULL; ++ } ++ ++ if (vma->status == MEMDCD_SEND_START) { ++ memdcd_log(_LOG_DEBUG, "Previous send work of process %d is interrupted.", pid); ++ migrate_process_remove(pid); ++ process = NULL; ++ } ++ } ++ if (process == NULL) { ++ if (vma->status != MEMDCD_SEND_START) { ++ memdcd_log(_LOG_DEBUG, "Current send work of process %d is incomplete.", pid); ++ pthread_mutex_unlock(&mutex); ++ return NULL; ++ } ++ ++ process = migrate_process_add(pid, vma->total_length); ++ if (process == NULL) { ++ memdcd_log(_LOG_ERROR, "Cannot allocate space for process %d.", pid); ++ pthread_mutex_unlock(&mutex); ++ return NULL; ++ } ++ } ++ pthread_mutex_unlock(&mutex); ++ ++ memdcd_log(_LOG_DEBUG, "Collect %d pages for process %d; %lu has been collected; total %lu.", count, pid, ++ process->offset, process->page_list->length); ++ ++ if (process->offset + count > process->page_list->length) { ++ memdcd_log(_LOG_ERROR, "Collected pages of process %d is greater than total count: %lu %lu %lu.", pid, ++ process->offset, count, process->page_list->length); ++ migrate_process_remove(pid); ++ return NULL; ++ } ++ ++ for (i = 0; i < count; i++) { ++ process->page_list->pages[process->offset + i].addr = vma->vma_addrs[i].vma.start_addr; ++ process->page_list->pages[process->offset + i].length = vma->vma_addrs[i].vma.vma_len; ++ process->page_list->pages[process->offset + i].visit_count = vma->vma_addrs[i].count; ++ } ++ process->offset += count; ++ gettimeofday(&process->timestamp, NULL); ++ ++ if (vma->status == MEMDCD_SEND_END && process->offset != process->page_list->length) { ++ memdcd_log(_LOG_ERROR, "Count of pages of process %d is not equal to total count: %lu %lu.", ++ pid, process->offset, process->page_list->length); ++ migrate_process_remove(pid); ++ return NULL; ++ } ++ if (vma->status != MEMDCD_SEND_PROCESS && process->offset == process->page_list->length) { ++ memdcd_log(_LOG_INFO, "Collected %lu vmas for process %d.", process->page_list->length, pid); ++ return process; ++ } ++ ++ return NULL; ++} ++ ++void init_collect_pages_timeout(time_t timeout) ++{ ++ collect_page_timeout = timeout; ++} ++ ++static void *memdcd_migrate(void *args) ++{ ++ struct migrate_process *process = (struct migrate_process *)args; ++ struct mem_policy *policy = NULL; ++ struct migrate_page_list *pages = NULL, *pages_to_numa = NULL, *pages_to_swap = NULL; ++ ++ if (process == NULL) { ++ memdcd_log(_LOG_ERROR, "Process freed."); ++ return NULL; ++ } ++ ++ policy = get_policy(); ++ if (policy == NULL) { ++ memdcd_log(_LOG_ERROR, "Policy not initialized."); ++ return NULL; ++ } ++ ++ pages = (struct migrate_page_list *)malloc(sizeof(struct migrate_page_list) + ++ sizeof(struct migrate_page) * process->page_list->length); ++ if (pages == NULL) ++ return NULL; ++ memcpy(pages, process->page_list, ++ sizeof(struct migrate_page_list) + sizeof(struct migrate_page) * process->page_list->length); ++ ++ if (policy->opt->parse(policy, process->pid, pages, &pages_to_numa, &pages_to_swap)) { ++ memdcd_log(_LOG_ERROR, "Error parsing policy."); ++ goto free_pages; ++ } ++ ++ if (pages_to_swap->pages != NULL) ++ send_to_userswap(process->pid, pages_to_swap); ++ ++ if (pages_to_numa != NULL) ++ free(pages_to_numa); ++ if (pages_to_swap != NULL) ++ free(pages_to_swap); ++ ++free_pages: ++ free(pages); ++ ++ pthread_mutex_lock(&mutex); ++ migrate_process_remove(process->pid); ++ pthread_mutex_unlock(&mutex); ++ return NULL; ++} ++ ++static int get_pid_max(void) ++{ ++ FILE *fp; ++ char buf[PID_MAX_LEN] = {0}; ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ ++ fp = fopen(PID_MAX_FILE, "r"); ++ if (fp == NULL) { ++ memdcd_log(_LOG_ERROR, "Error opening pid_max file %s. err: %s", ++ PID_MAX_FILE, strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ return 0; ++ } ++ if (fread(buf, sizeof(buf), 1, fp) == 0) { ++ if (feof(fp) == 0) { ++ memdcd_log(_LOG_ERROR, "Error reading pid_max file %s.", PID_MAX_FILE); ++ fclose(fp); ++ return 0; ++ } ++ } ++ fclose(fp); ++ return atoi(buf); ++} ++ ++int migrate_process_get_pages(int pid, const struct swap_vma_with_count *vma) ++{ ++ char error_str[ERROR_STR_MAX_LEN] = {0}; ++ struct migrate_process *process = NULL; ++ if (pid <= 0 || pid > get_pid_max()) { ++ memdcd_log(_LOG_ERROR, "Invalid input pid:%d.\n ", pid); ++ return -1; ++ } ++ ++ process = migrate_process_collect_pages(pid, vma); ++ ++ if (process != NULL) { ++ if (pthread_create(&process->worker, NULL, memdcd_migrate, (void *)process) != 0) { ++ memdcd_log(_LOG_ERROR, "Error creating pthread for process %d. err: %s", ++ process->pid, strerror_r(errno, error_str, ERROR_STR_MAX_LEN)); ++ return -1; ++ } ++ } else { ++ return -1; ++ } ++ return 0; ++} ++ +diff --git a/userswap/CMakeLists.txt b/userswap/CMakeLists.txt +new file mode 100644 +index 0000000..415b0f7 +--- /dev/null ++++ b/userswap/CMakeLists.txt +@@ -0,0 +1,36 @@ ++# /****************************************************************************** ++# * Copyright (c) Huawei Technologies Co., Ltd. 2020-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: LiuYongqiang ++# * Create: 2020-11-06 ++# * Description: CMakefileList for userswap to compile ++# ******************************************************************************/ ++ ++cmake_minimum_required (VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) ++ ++project(libuswap) ++ ++set(SRC_DIR ${PROJECT_SOURCE_DIR}/src) ++set(BUILD_DIR ${PROJECT_SOURCE_DIR}/build) ++ ++set(USWAP_SRC ++ ${SRC_DIR}/lib_uswap.c ++ ${SRC_DIR}/uswap_server.c ++ ${SRC_DIR}/uswap_log.c) ++ ++include_directories(${PROJECT_SOURCE_DIR}/include) ++ ++add_library(uswap STATIC ${USWAP_SRC}) ++ ++target_compile_options(uswap PRIVATE -fPIC -ftrapv -D_FORTIFY_SOURCE=2 -O2 ++-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -fvisibility=hidden) ++ ++install(TARGETS uswap PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE DESTINATION /usr/lib64) ++install(FILES ${PROJECT_SOURCE_DIR}/include/uswap_api.h DESTINATION /usr/include) +diff --git a/userswap/License/LICENSE b/userswap/License/LICENSE +new file mode 100644 +index 0000000..0db93af +--- /dev/null ++++ b/userswap/License/LICENSE +@@ -0,0 +1,127 @@ ++木兰宽松许可证, 第2版 ++ ++ 木兰宽松许可证, 第2版 ++ 2020年1月 http://license.coscl.org.cn/MulanPSL2 ++ ++ ++ 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: ++ ++ 0. 定义 ++ ++ “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 ++ ++ “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 ++ ++ “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 ++ ++ “法人实体”是指提交贡献的机构及其“关联实体”。 ++ ++ “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 ++ ++ 1. 授予版权许可 ++ ++ 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 ++ ++ 2. 授予专利许可 ++ ++ 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 ++ ++ 3. 无商标许可 ++ ++ “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 ++ ++ 4. 分发限制 ++ ++ 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 ++ ++ 5. 免责声明与责任限制 ++ ++ “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 ++ ++ 6. 语言 ++ “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 ++ ++ 条款结束 ++ ++ 如何将木兰宽松许可证,第2版,应用到您的软件 ++ ++ 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: ++ ++ 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; ++ ++ 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; ++ ++ 3, 请将如下声明文本放入每个源文件的头部注释中。 ++ ++ Copyright (c) [Year] [name of copyright holder] ++ [Software Name] is licensed under 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. ++ ++ ++ Mulan Permissive Software License,Version 2 ++ ++ Mulan Permissive Software License,Version 2 (Mulan PSL v2) ++ January 2020 http://license.coscl.org.cn/MulanPSL2 ++ ++ Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: ++ ++ 0. Definition ++ ++ Software means the program and related documents which are licensed under this License and comprise all Contribution(s). ++ ++ Contribution means the copyrightable work licensed by a particular Contributor under this License. ++ ++ Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. ++ ++ Legal Entity means the entity making a Contribution and all its Affiliates. ++ ++ Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. ++ ++ 1. Grant of Copyright License ++ ++ Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. ++ ++ 2. Grant of Patent License ++ ++ Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. ++ ++ 3. No Trademark License ++ ++ No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. ++ ++ 4. Distribution Restriction ++ ++ You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. ++ ++ 5. Disclaimer of Warranty and Limitation of Liability ++ ++ THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ++ ++ 6. Language ++ ++ THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. ++ ++ END OF THE TERMS AND CONDITIONS ++ ++ How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software ++ ++ To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: ++ ++ i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; ++ ++ ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; ++ ++ iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. ++ ++ ++ Copyright (c) [Year] [name of copyright holder] ++ [Software Name] is licensed under 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. +diff --git a/userswap/README.md b/userswap/README.md +new file mode 100644 +index 0000000..b02edfe +--- /dev/null ++++ b/userswap/README.md +@@ -0,0 +1,7 @@ ++# Introduction ++userswap is a component of RAA memory-fabric. It supplies a userswap method for ++storage and net devices which is designed by user-mode protocol. It works with ++special kernel. ++ ++# Build ++./configure +diff --git a/userswap/configure.sh b/userswap/configure.sh +new file mode 100644 +index 0000000..6bca78d +--- /dev/null ++++ b/userswap/configure.sh +@@ -0,0 +1,4 @@ ++mkdir build ++cd ./build ++cmake .. ++make +diff --git a/userswap/include/uswap_api.h b/userswap/include/uswap_api.h +new file mode 100644 +index 0000000..9e26dfe +--- /dev/null ++++ b/userswap/include/uswap_api.h +@@ -0,0 +1,69 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * userswap 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: liuyongqiang ++ * Create: 2020-11-06 ++ * Description: userswap interface ++ ******************************************************************************/ ++ ++#ifndef __USWAP_API_H__ ++#define __USWAP_API_H__ ++ ++#include ++ ++#define USWAP_SUCCESS 0 ++#define USWAP_ERROR (-1) ++#define USWAP_UNREGISTER_MEM (-2) ++#define USWAP_ALREADY_SWAPPED (-3) ++#define USWAP_ABORT (-4) ++#define USWAP_ALREADY_SWAPIN (-5) ++ ++#define MAX_USWAP_NAME_LEN 32 ++#define MAX_SWAPIN_THREAD_NUMS 5 ++ ++/* flag field of struct swap_data */ ++#define USWAP_DATA_DIRTY 0x1 ++#define USWAP_DATA_ABORT 0x2 ++ ++struct swap_data { ++ void *start_va; ++ size_t len; ++ void *buf; ++ /* ++ * Bit 0 (Dirty Flag): ++ * indicate the data in the range of 'start_va ~ start_va+len' is ++ * dirty if this bit is set. ++ * Bit 1 (Abort Flag): ++ * This bit only takes affect in do_swapout. It indicates ++ * aborting the swapout operation if it is set. ++ */ ++ size_t flag; ++}; ++ ++struct uswap_operations { ++ int (*get_swapout_buf) (const void *, size_t, struct swap_data *); ++ int (*do_swapout) (struct swap_data *); ++ int (*do_swapin) (const void *, struct swap_data *); ++ int (*release_buf) (struct swap_data *); ++}; ++ ++int set_uswap_log_level(int log_level); ++ ++int register_userfaultfd(void *addr, size_t size); ++ ++int unregister_userfaultfd(void *addr, size_t size); ++ ++int register_uswap(const char *name, size_t len, ++ const struct uswap_operations *ops); ++ ++int force_swapout(const void *addr, size_t len); ++ ++int uswap_init(int swapin_nums); ++#endif +diff --git a/userswap/include/uswap_log.h b/userswap/include/uswap_log.h +new file mode 100644 +index 0000000..1084d16 +--- /dev/null ++++ b/userswap/include/uswap_log.h +@@ -0,0 +1,30 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * userswap 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: liuyongqiang ++ * Create: 2020-11-06 ++ * Description: userswap log headfile ++ ******************************************************************************/ ++ ++#ifndef __USWAP_LOG_H__ ++#define __USWAP_LOG_H__ ++ ++enum log_level { ++ USWAP_LOG_DEBUG = 0, ++ USWAP_LOG_INFO, ++ USWAP_LOG_WARN, ++ USWAP_LOG_ERR, ++ USWAP_LOG_INVAL, ++}; ++ ++int uswap_log_level_init(enum log_level level); ++ ++void uswap_log(enum log_level level, const char *format, ...); ++#endif +diff --git a/userswap/include/uswap_server.h b/userswap/include/uswap_server.h +new file mode 100644 +index 0000000..bcfb16f +--- /dev/null ++++ b/userswap/include/uswap_server.h +@@ -0,0 +1,40 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * userswap 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: liuyongqiang ++ * Create: 2020-11-06 ++ * Description: userswap server interface ++ ******************************************************************************/ ++ ++#ifndef __USWAP_SERVER_H__ ++#define __USWAP_SERVER_H__ ++ ++#define MAX_VMA_NUM 512 ++ ++enum swap_type { ++ SWAP_TYPE_VMA_ADDR = 0xFFFFFF01, ++ SWAP_TYPE_MAX ++}; ++ ++struct vma_addr { ++ unsigned long start_addr; ++ unsigned long vma_len; ++}; ++ ++struct swap_vma { ++ enum swap_type type; ++ unsigned long length; ++ struct vma_addr vma_addrs[MAX_VMA_NUM]; ++}; ++ ++int init_socket(void); ++int sock_handle_rec(int fd, struct swap_vma *swap_vma); ++int sock_handle_respond(int client_fd, int result); ++#endif +diff --git a/userswap/src/lib_uswap.c b/userswap/src/lib_uswap.c +new file mode 100644 +index 0000000..0dc1337 +--- /dev/null ++++ b/userswap/src/lib_uswap.c +@@ -0,0 +1,663 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * userswap 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: liuyongqiang ++ * Create: 2020-11-06 ++ * Description: userswap interface definition. ++ ******************************************************************************/ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "uswap_server.h" ++#include "uswap_log.h" ++#include "uswap_api.h" ++ ++#define MAP_REPLACE 0x1000000 ++#ifndef UFFDIO_REGISTER_MODE_USWAP ++#define UFFDIO_REGISTER_MODE_USWAP (1 << 2) ++#endif ++#define MMAP_RETVAL_DIRTY_MASK 0x01L ++#define MAX_TRY_NUMS 10 ++ ++struct uswap_dev { ++ char name[MAX_USWAP_NAME_LEN]; ++ struct uswap_operations *ops; ++ bool enabled; ++ bool alive; ++ int uffd; ++ pthread_cond_t cond; ++ pthread_mutex_t mutex; ++}; ++ ++static struct uswap_dev g_dev = { ++ .name = "", ++ .ops = NULL, ++ .enabled = false, ++ .alive = false, ++ .uffd = -1, ++ .cond = PTHREAD_COND_INITIALIZER, ++ .mutex = PTHREAD_MUTEX_INITIALIZER, ++}; ++ ++static size_t get_page_size(void) ++{ ++ static size_t page_size = 0; ++ if (page_size != 0) { ++ return page_size; ++ } ++ ++ page_size = sysconf(_SC_PAGESIZE); ++ return page_size; ++} ++ ++static bool is_uswap_enabled(void) ++{ ++ return g_dev.enabled; ++} ++ ++static bool is_uswap_threads_alive(void) ++{ ++ return g_dev.alive; ++} ++ ++static int set_uswap_uffd(int uffd) ++{ ++ if (g_dev.uffd != -1) { ++ return USWAP_ERROR; ++ } ++ g_dev.uffd = uffd; ++ return USWAP_SUCCESS; ++} ++ ++static int get_uswap_uffd(void) ++{ ++ return g_dev.uffd; ++} ++ ++static void uswap_mutex_lock(void) ++{ ++ pthread_mutex_lock(&g_dev.mutex); ++} ++ ++static void uswap_mutex_unlock(void) ++{ ++ pthread_mutex_unlock(&g_dev.mutex); ++} ++ ++static void uswap_cond_wait(void) ++{ ++ pthread_cond_wait(&g_dev.cond, &g_dev.mutex); ++} ++ ++static void uswap_cond_wake(void) ++{ ++ pthread_cond_signal(&g_dev.cond); ++} ++ ++static int call_get_swapout_buf(const void *start_va, size_t len, ++ struct swap_data *swapout_data) ++{ ++ return g_dev.ops->get_swapout_buf(start_va, len, swapout_data); ++} ++ ++static int call_do_swapout(struct swap_data *swapout_data) ++{ ++ return g_dev.ops->do_swapout(swapout_data); ++} ++ ++static int call_do_swapin(const void *fault_addr, struct swap_data *swapin_data) ++{ ++ return g_dev.ops->do_swapin(fault_addr, swapin_data); ++} ++ ++static int call_release_buf(struct swap_data *swap_data) ++{ ++ return g_dev.ops->release_buf(swap_data); ++} ++ ++static int init_userfaultfd(void) ++{ ++ struct uffdio_api uffdio_api; ++ int uswap_uffd; ++ int ret; ++ ++ uswap_uffd = syscall(__NR_userfaultfd, O_NONBLOCK); ++ if (uswap_uffd < 0) { ++ return USWAP_ERROR; ++ } ++ ++ uffdio_api.api = UFFD_API; ++ uffdio_api.features = 0; ++ ret = ioctl(uswap_uffd, UFFDIO_API, &uffdio_api); ++ if (ret < 0) { ++ return ret; ++ } ++ ret = set_uswap_uffd(uswap_uffd); ++ return ret; ++} ++ ++int register_userfaultfd(void *addr, size_t size) ++{ ++ struct uffdio_register uffdio_register; ++ int ret; ++ int uswap_uffd; ++ size_t page_size; ++ ++ if (size > SSIZE_MAX || addr == NULL) { ++ return USWAP_ERROR; ++ } ++ ++ uswap_uffd = get_uswap_uffd(); ++ if (uswap_uffd < 0) { ++ uswap_mutex_lock(); ++ ret = init_userfaultfd(); ++ uswap_cond_wake(); ++ uswap_mutex_unlock(); ++ if (ret == USWAP_ERROR) { ++ uswap_log(USWAP_LOG_ERR, "init userfaultfd failed\n"); ++ return USWAP_ERROR; ++ } ++ uswap_uffd = get_uswap_uffd(); ++ } ++ ++ page_size = get_page_size(); ++ if (size >= page_size) { ++ uffdio_register.range.start = (unsigned long)addr; ++ uffdio_register.range.len = size; ++ uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING | ++ UFFDIO_REGISTER_MODE_USWAP; ++ ret = ioctl(uswap_uffd, UFFDIO_REGISTER, &uffdio_register); ++ if (ret < 0) { ++ uswap_log(USWAP_LOG_ERR, "register uffd failed\n"); ++ return USWAP_ERROR; ++ } ++ return USWAP_SUCCESS; ++ } ++ uswap_log(USWAP_LOG_ERR, "register uffd: the size smaller than page_size\n"); ++ return USWAP_ERROR; ++} ++ ++int unregister_userfaultfd(void *addr, size_t size) ++{ ++ struct uffdio_register uffdio_register; ++ int uswap_uffd; ++ int ret; ++ ++ uswap_uffd = get_uswap_uffd(); ++ if (uswap_uffd < 0 || size > SSIZE_MAX || addr == NULL) { ++ return USWAP_ERROR; ++ } ++ ++ uffdio_register.range.start = (unsigned long)addr; ++ uffdio_register.range.len = size; ++ ret = ioctl(uswap_uffd, UFFDIO_UNREGISTER, &uffdio_register); ++ if (ret < 0) { ++ uswap_log(USWAP_LOG_ERR, "unregister userfaultfd failed\n"); ++ return USWAP_ERROR; ++ } ++ return USWAP_SUCCESS; ++} ++ ++int register_uswap(const char *name, size_t len, ++ const struct uswap_operations *ops) ++{ ++ static struct uswap_operations uswap_ops; ++ if (name == NULL || len > MAX_USWAP_NAME_LEN - 1) { ++ return USWAP_ERROR; ++ } ++ ++ if (ops == NULL) { ++ return USWAP_ERROR; ++ } ++ ++ if (ops->get_swapout_buf == NULL || ops->do_swapout == NULL || ++ ops->do_swapin == NULL || ops->release_buf == NULL) { ++ return USWAP_ERROR; ++ } ++ ++ uswap_ops = *ops; ++ ++ snprintf(g_dev.name, MAX_USWAP_NAME_LEN, "%s", name); ++ g_dev.ops = &uswap_ops; ++ g_dev.enabled = true; ++ uswap_log(USWAP_LOG_INFO, "register uswap ops [%s] success\n", g_dev.name); ++ return USWAP_SUCCESS; ++} ++ ++static int mlock_pthread_stack(pthread_t tid) ++{ ++ int ret; ++ pthread_attr_t attr_t; ++ void *stack_addr = NULL; ++ size_t stack_size; ++ ++ ret = pthread_getattr_np(tid, &attr_t); ++ if (ret < 0) { ++ return USWAP_ERROR; ++ } ++ ret = pthread_attr_getstack(&attr_t, &stack_addr, &stack_size); ++ pthread_attr_destroy(&attr_t); ++ if (ret < 0) { ++ return USWAP_ERROR; ++ } ++ ++ ret = mlock(stack_addr, stack_size); ++ if (ret < 0) { ++ return USWAP_ERROR; ++ } ++ return USWAP_SUCCESS; ++} ++ ++static int read_uffd_msg(int uffd, struct uffd_msg *msg) ++{ ++ int ret; ++ int msg_len = sizeof(struct uffd_msg); ++ ++ for (int i = 0; i < MAX_TRY_NUMS; i++) { ++ ret = read(uffd, msg, msg_len); ++ if (ret != msg_len) { ++ if (errno == EAGAIN) { ++ continue; ++ } ++ return USWAP_ERROR; ++ } ++ ++ if (msg->event != UFFD_EVENT_PAGEFAULT) { ++ uswap_log(USWAP_LOG_ERR, "unexpected event on userfaultfd\n"); ++ return USWAP_ERROR; ++ } ++ return USWAP_SUCCESS; ++ } ++ return USWAP_ABORT; ++} ++ ++static int ioctl_uffd_copy_pages(int uffd, const struct swap_data *swapin_data) ++{ ++ int ret; ++ int offset = 0; ++ size_t page_size = get_page_size(); ++ struct uffdio_copy uffdio_copy = { ++ .len = page_size, ++ .mode = 0, ++ .copy = 0, ++ }; ++ ++ while (offset < swapin_data->len) { ++ uffdio_copy.src = (unsigned long)swapin_data->buf + offset; ++ uffdio_copy.dst = (unsigned long)swapin_data->start_va + offset; ++ ret = ioctl(uffd, UFFDIO_COPY, &uffdio_copy); ++ if (ret < 0 && errno != EEXIST) { ++ uswap_log(USWAP_LOG_ERR, "uffd ioctl copy one page failed\n"); ++ return USWAP_ERROR; ++ } ++ offset += page_size; ++ } ++ ++ return USWAP_SUCCESS; ++} ++ ++static int ioctl_uffd_copy(int uffd, struct swap_data *swapin_data) ++{ ++ int ret; ++ struct uffdio_copy uffdio_copy = { ++ .src = (unsigned long)swapin_data->buf, ++ .dst = (unsigned long)swapin_data->start_va, ++ .len = swapin_data->len, ++ .mode = 0, ++ .copy = 0, ++ }; ++ for (int i = 0; i < MAX_TRY_NUMS; i++) { ++ ret = ioctl(uffd, UFFDIO_COPY, &uffdio_copy); ++ if (ret < 0) { ++ if (errno == EAGAIN) { ++ continue; ++ } ++ ++ if (errno == EEXIST) { ++ return USWAP_ALREADY_SWAPIN; ++ } ++ /* ++ * 'start_va ~ start_va+len' may exceed the range of one vma. ++ * If that is the case, copy one page at a time. ++ */ ++ ret = ioctl_uffd_copy_pages(uffd, swapin_data); ++ if (ret == USWAP_ERROR) { ++ return USWAP_ERROR; ++ } ++ } ++ return USWAP_SUCCESS; ++ } ++ uswap_log(USWAP_LOG_ERR, "ioctl copy max try failed\n"); ++ return USWAP_ERROR; ++} ++ ++static void *swapin_thread(void *arg) ++{ ++ struct swap_data swapin_data; ++ struct uffd_msg uffd_msg; ++ struct pollfd pollfd; ++ unsigned long fault_addr; ++ int uswap_uffd; ++ int ret; ++ ++ prctl(PR_SET_NAME, "uswap-swapin", 0, 0, 0); ++ ++ uswap_mutex_lock(); ++ uswap_uffd = get_uswap_uffd(); ++ while (uswap_uffd < 0) { ++ uswap_cond_wait(); ++ uswap_uffd = get_uswap_uffd(); ++ } ++ uswap_mutex_unlock(); ++ while (1) { ++ pollfd.fd = uswap_uffd; ++ pollfd.events = POLLIN; ++ ret = poll(&pollfd, 1, -1); ++ if (ret < 0) { ++ uswap_log(USWAP_LOG_ERR, "poll failed\n"); ++ usleep(10); ++ continue; ++ } ++ ret = read_uffd_msg(uswap_uffd, &uffd_msg); ++ if (ret == USWAP_ABORT) { ++ continue; ++ } else if (ret == USWAP_ERROR) { ++ uswap_log(USWAP_LOG_ERR, "read uffd failed\n"); ++ continue; ++ } ++ ++ fault_addr = uffd_msg.arg.pagefault.address; ++ ++ ret = call_do_swapin((void *)fault_addr, &swapin_data); ++ if (ret == USWAP_ERROR) { ++ uswap_log(USWAP_LOG_ERR, "do_swapin failed\n"); ++ exit(-1); ++ } ++ ++ ret = ioctl_uffd_copy(uswap_uffd, &swapin_data); ++ if (ret == USWAP_ERROR) { ++ uswap_log(USWAP_LOG_ERR, "uffd ioctl copy failed\n"); ++ exit(-1); ++ } ++ ret = call_release_buf(&swapin_data); ++ if (ret == USWAP_ERROR) { ++ uswap_log(USWAP_LOG_ERR, "release buf failed\n"); ++ } ++ } ++} ++ ++static void* mmap_tmpva(const void *start, size_t len, int *is_dirty) ++{ ++ unsigned long new_addr; ++ new_addr = syscall(__NR_mmap, start, len, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS | MAP_REPLACE, -1, 0); ++ if ((void *)new_addr == MAP_FAILED) { ++ if (errno != ENODEV) { ++ uswap_log(USWAP_LOG_ERR, "the addr can't be swapout\n"); ++ } ++ return MAP_FAILED; ++ } else { ++ *is_dirty = new_addr & MMAP_RETVAL_DIRTY_MASK; ++ new_addr = new_addr & (~MMAP_RETVAL_DIRTY_MASK); ++ } ++ return (void *)new_addr; ++} ++ ++static int do_swapout_once(const void *start, size_t len, ++ struct swap_data *swapout_data) ++{ ++ int ret; ++ int is_dirty = 1; ++ void *tmpva = NULL; ++ ++ ret = call_get_swapout_buf(start, len, swapout_data); ++ if (ret == USWAP_ALREADY_SWAPPED) { ++ return USWAP_SUCCESS; ++ } ++ if (ret < 0) { ++ uswap_log(USWAP_LOG_ERR, "get swapout buf error\n"); ++ return ret; ++ } ++ ++ tmpva = mmap_tmpva(swapout_data->start_va, swapout_data->len, &is_dirty); ++ ++ swapout_data->flag = 0; ++ if (tmpva != MAP_FAILED) { ++ memcpy(swapout_data->buf, tmpva, swapout_data->len); ++ munmap(tmpva, swapout_data->len); ++ } else { ++ swapout_data->flag |= USWAP_DATA_ABORT; ++ } ++ ++ if (is_dirty != 0) { ++ swapout_data->flag |= USWAP_DATA_DIRTY; ++ } ++ ++ ret = call_do_swapout(swapout_data); ++ ++ return ret; ++} ++ ++static int do_swapout(const void *start, size_t len) ++{ ++ int ret; ++ size_t succ_len = 0; ++ struct swap_data swapout_data; ++ ++ while (succ_len < len) { ++ ret = do_swapout_once(start + succ_len, len - succ_len, &swapout_data); ++ if (ret < 0) { ++ return ret; ++ } ++ if (succ_len >= len - swapout_data.len) { ++ break; ++ } ++ succ_len += swapout_data.len; ++ } ++ uswap_log(USWAP_LOG_DEBUG, "do swapout addr: %p, len %lx\n", start, len); ++ return succ_len; ++} ++ ++static int vma_merge(const struct swap_vma *src, struct swap_vma *dst) ++{ ++ int index = 0; ++ int swapout_nums; ++ size_t page_size = get_page_size(); ++ ++ swapout_nums = src->length / sizeof(struct vma_addr); ++ if (swapout_nums > MAX_VMA_NUM) { ++ swapout_nums = MAX_VMA_NUM; ++ } ++ for (int i = 0; i < swapout_nums; i++) { ++ if (src->vma_addrs[i].vma_len == 0 || ++ src->vma_addrs[i].vma_len > SSIZE_MAX) { ++ continue; ++ } ++ if (src->vma_addrs[i].vma_len == page_size) { ++ int j = i + 1; ++ dst->vma_addrs[index].start_addr = src->vma_addrs[i].start_addr; ++ dst->vma_addrs[index].vma_len = page_size; ++ while (j < swapout_nums && ++ src->vma_addrs[j - 1].start_addr + page_size == ++ src->vma_addrs[j].start_addr) { ++ j++; ++ dst->vma_addrs[index].vma_len += page_size; ++ } ++ i = j - 1; ++ index++; ++ } else { ++ dst->vma_addrs[index].start_addr = src->vma_addrs[i].start_addr; ++ dst->vma_addrs[index].vma_len = src->vma_addrs[i].vma_len; ++ index++; ++ } ++ } ++ dst->length = index * sizeof(struct vma_addr); ++ return USWAP_SUCCESS; ++} ++ ++static int swapout_source_init(void) ++{ ++ size_t page_size; ++ int socket_fd = -1; ++ ++ page_size = get_page_size(); ++ socket_fd = init_socket(); ++ if (socket_fd < 0) { ++ uswap_log(USWAP_LOG_DEBUG, "init_socket failed err:%d\n", errno); ++ return USWAP_ERROR; ++ } ++ return socket_fd; ++} ++ ++static void *swapout_thread(void *arg) ++{ ++ struct swap_vma src, dst; ++ unsigned long start; ++ size_t len; ++ int swapout_nums; ++ int succ_count = 0; ++ int socket_fd, client_fd; ++ int ret; ++ ++ prctl(PR_SET_NAME, "uswap-swapout", 0, 0, 0); ++ ret = swapout_source_init(); ++ if (ret < 0) { ++ uswap_log(USWAP_LOG_ERR, "swapout source init failed\n"); ++ return NULL; ++ } ++ socket_fd = ret; ++ while (1) { ++ client_fd = sock_handle_rec(socket_fd, &src); ++ if (client_fd <= 0) { ++ uswap_log(USWAP_LOG_DEBUG, "sock_handle_rec failed\n"); ++ continue; ++ } ++ ++ vma_merge(&src, &dst); ++ ret = USWAP_SUCCESS; ++ swapout_nums = dst.length / sizeof(struct vma_addr); ++ for (int i = 0; i < swapout_nums; i++) { ++ len = dst.vma_addrs[i].vma_len; ++ start = dst.vma_addrs[i].start_addr; ++ succ_count = do_swapout((void *)start, len); ++ if (succ_count < 0) { ++ uswap_log(USWAP_LOG_ERR, "do swapout once failed\n"); ++ ret = USWAP_ERROR; ++ } ++ } ++ sock_handle_respond(client_fd, ret); ++ } ++ close(socket_fd); ++} ++ ++int force_swapout(const void *addr, size_t len) ++{ ++ int ret; ++ size_t page_size = get_page_size(); ++ if (!is_uswap_enabled() || !is_uswap_threads_alive()) { ++ return USWAP_ERROR; ++ } ++ if (addr == NULL || len > SSIZE_MAX) { ++ return USWAP_ERROR; ++ } ++ ++ ret = do_swapout(addr, len); ++ return ret; ++} ++ ++static int create_uswap_threads(int swapin_nums) ++{ ++ int ret; ++ pthread_t swapout_tid; ++ pthread_t swapin_tid[MAX_SWAPIN_THREAD_NUMS]; ++ ++ if (swapin_nums <= 0 || swapin_nums > MAX_SWAPIN_THREAD_NUMS) { ++ return USWAP_ERROR; ++ } ++ ++ ret = pthread_create(&swapout_tid, NULL, swapout_thread, NULL); ++ if (ret < 0) { ++ uswap_log(USWAP_LOG_ERR, "can't create swapout thread"); ++ return USWAP_ERROR; ++ } ++ ret = mlock_pthread_stack(swapout_tid); ++ if (ret == USWAP_ERROR) { ++ uswap_log(USWAP_LOG_ERR, "mlock swapout thread stack failed\n"); ++ pthread_cancel(swapout_tid); ++ return USWAP_ERROR; ++ } ++ ++ for (int i = 0; i < swapin_nums; i++) { ++ ret = pthread_create(&swapin_tid[i], NULL, swapin_thread, NULL); ++ if (ret < 0) { ++ uswap_log(USWAP_LOG_ERR, "can't create swapin thread\n"); ++ pthread_cancel(swapout_tid); ++ for (int j = 0; j < i; j++) { ++ pthread_cancel(swapin_tid[j]); ++ } ++ return USWAP_ERROR; ++ } ++ ret = mlock_pthread_stack(swapin_tid[i]); ++ if (ret == USWAP_ERROR) { ++ uswap_log(USWAP_LOG_ERR, "mlock swapin thread stack failed\n"); ++ pthread_cancel(swapout_tid); ++ for (int j = 0; j <= i; j++) { ++ pthread_cancel(swapin_tid[j]); ++ } ++ return USWAP_ERROR; ++ } ++ } ++ ++ return USWAP_SUCCESS; ++} ++ ++int set_uswap_log_level(int log_level) ++{ ++ return uswap_log_level_init(log_level); ++} ++ ++int uswap_init(int swapin_nums) ++{ ++ int ret; ++ ++ if (!is_uswap_enabled() || is_uswap_threads_alive()) { ++ return USWAP_ERROR; ++ } ++ ++ ret = create_uswap_threads(swapin_nums); ++ if (ret == USWAP_ERROR) { ++ return USWAP_ERROR; ++ } ++ ++ g_dev.alive = true; ++ return USWAP_SUCCESS; ++} +diff --git a/userswap/src/uswap_log.c b/userswap/src/uswap_log.c +new file mode 100644 +index 0000000..09bdff6 +--- /dev/null ++++ b/userswap/src/uswap_log.c +@@ -0,0 +1,81 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * userswap 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: liuyongqiang ++ * Create: 2020-11-06 ++ * Description: userswap log definition. ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include "uswap_log.h" ++ ++enum log_level g_log_level = USWAP_LOG_ERR; ++ ++static void log_level_usage(void) ++{ ++ printf("\n" ++ "[0] for debug level\n" ++ "[1] for info level\n" ++ "[2] for warning level\n" ++ "[3] for error level\n" ++ "default level is error\n" ++ "\n"); ++} ++ ++int uswap_log_level_init(enum log_level level) ++{ ++ if (level < 0 || level >= USWAP_LOG_INVAL) { ++ printf("error: invalid log level [%d]\n", level); ++ log_level_usage(); ++ return -EINVAL; ++ } ++ g_log_level = level; ++ return 0; ++} ++ ++void uswap_log(enum log_level level, const char *format, ...) ++{ ++ va_list args; ++ ++ if (level < g_log_level) { ++ return; ++ } ++ ++ va_start(args, format); ++ ++ switch (level) { ++ case USWAP_LOG_DEBUG: ++ openlog("[uswap_debug] ", LOG_PID, LOG_USER); ++ vsyslog(LOG_INFO, format, args); ++ break; ++ case USWAP_LOG_INFO: ++ openlog("[uswap_info] ", LOG_PID, LOG_USER); ++ vsyslog(LOG_INFO, format, args); ++ break; ++ case USWAP_LOG_WARN: ++ openlog("[uswap_warn] ", LOG_PID, LOG_USER); ++ vsyslog(LOG_WARNING, format, args); ++ break; ++ case USWAP_LOG_ERR: ++ openlog("[uswap_error] ", LOG_PID, LOG_USER); ++ vsyslog(LOG_ERR, format, args); ++ break; ++ default: ++ openlog("[uswap_error] ", LOG_PID, LOG_USER); ++ vsyslog(LOG_ERR, "invalid uswap_log_level\n", args); ++ } ++ ++ va_end(args); ++ closelog(); ++ return; ++} +diff --git a/userswap/src/uswap_server.c b/userswap/src/uswap_server.c +new file mode 100644 +index 0000000..ecb16a9 +--- /dev/null ++++ b/userswap/src/uswap_server.c +@@ -0,0 +1,138 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved. ++ * userswap 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: liuyongqiang ++ * Create: 2020-11-06 ++ * Description: userswap server definition. ++ ******************************************************************************/ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "uswap_log.h" ++#include "uswap_server.h" ++ ++#define MAX_LISTENQ_NUM 1 ++#define RESP_MSG_MAX_LEN 10 ++#define PATH_MAX_LEN 127 ++ ++ ++int init_socket(void) ++{ ++ int socket_fd; ++ int addrlen; ++ struct sockaddr_un addr; ++ char abstract_path[PATH_MAX_LEN] = {0}; ++ pid_t pid = getpid(); ++ ++ socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0); ++ if (socket_fd < 0) { ++ uswap_log(USWAP_LOG_ERR, "create socket failed\n"); ++ return -EINVAL; ++ } ++ ++ bzero(&addr, sizeof(struct sockaddr_un)); ++ addr.sun_family = AF_UNIX; ++ addr.sun_path[0] = 0; ++ snprintf(abstract_path, sizeof(abstract_path), "userswap%d.sock", pid); ++ memcpy(addr.sun_path + 1, abstract_path, strlen(abstract_path) + 1); ++ addrlen = sizeof(addr.sun_family) + strlen(abstract_path) + 1; ++ if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) { ++ uswap_log(USWAP_LOG_ERR, "bind socket failed\n"); ++ close(socket_fd); ++ return -EINVAL; ++ } ++ ++ listen(socket_fd, MAX_LISTENQ_NUM); ++ ++ return socket_fd; ++} ++ ++static int check_socket_permission(int fd, int client_fd) ++{ ++ struct ucred local_cred, client_cred; ++ socklen_t len; ++ int ret; ++ ++ len = sizeof(struct ucred); ++ ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &local_cred, &len); ++ if (ret < 0) { ++ uswap_log(USWAP_LOG_ERR, "get server sockopt failed\n"); ++ return ret; ++ } ++ ret = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &client_cred, &len); ++ if (ret < 0) { ++ uswap_log(USWAP_LOG_ERR, "get client sockopt failed\n"); ++ return ret; ++ } ++ ++ if (local_cred.uid != client_cred.uid || ++ local_cred.gid != client_cred.gid) { ++ return -EPERM; ++ } ++ return 0; ++} ++ ++int sock_handle_rec(int fd, struct swap_vma *swap_vma) ++{ ++ int client_fd; ++ int readbytes; ++ struct sockaddr_un clientun; ++ socklen_t clientun_len = sizeof(clientun); ++ ++ client_fd = accept(fd, (struct sockaddr *)&clientun, &clientun_len); ++ if (client_fd < 0) { ++ return -EINVAL; ++ } ++ ++ if (check_socket_permission(fd, client_fd) < 0) { ++ close(client_fd); ++ return -EPERM; ++ } ++ ++ readbytes = read(client_fd, swap_vma, sizeof(struct swap_vma)); ++ if (readbytes <= 0) { ++ close(client_fd); ++ return -EINVAL; ++ } ++ ++ return client_fd; ++} ++ ++int sock_handle_respond(int client_fd, int result) ++{ ++ int writebytes; ++ char buff[RESP_MSG_MAX_LEN] = {0}; ++ ++ if (client_fd < 0) { ++ return -EINVAL; ++ } ++ ++ if (result == 0) { ++ snprintf(buff, sizeof(buff), "success"); ++ } else { ++ snprintf(buff, sizeof(buff), "failed"); ++ } ++ ++ writebytes = write(client_fd, buff, (strlen(buff) + 1)); ++ if (writebytes != (strlen(buff) + 1)) { ++ close(client_fd); ++ return -EIO; ++ } ++ ++ close(client_fd); ++ return 0; ++} +-- +2.27.0 + diff --git a/etmem.spec b/etmem.spec index b7bb4de..46752a8 100644 --- a/etmem.spec +++ b/etmem.spec @@ -53,7 +53,8 @@ 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 - +Patch46: 0047-move-all-the-files-to-sub-directory-of-etmem.patch +Patch47: 0048-Commit-new-features-memRouter-and-userswap-to-etmem.patch #Dependency BuildRequires: cmake gcc gcc-c++ -- Gitee From 3bd06e9a259081d308803420ee7b693d49b9f484 Mon Sep 17 00:00:00 2001 From: YangXin <245051644@qq.com> Date: Fri, 1 Oct 2021 00:16:53 +0800 Subject: [PATCH 3/4] add new features memRouter and userswap. Signed-off-by: YangXin <245051644@qq.com> (cherry picked from commit 194e6fb0c8482a8df28875ad8d7f85ccdf0890fe) --- 0049-Add-engine-memdcd-to-etmemd.patch | 481 ++++++++++++++++++ ...ists.txt-for-three-features-of-etmem.patch | 39 ++ etmem.spec | 25 +- 3 files changed, 539 insertions(+), 6 deletions(-) create mode 100644 0049-Add-engine-memdcd-to-etmemd.patch create mode 100644 0050-Add-CMakeLists.txt-for-three-features-of-etmem.patch diff --git a/0049-Add-engine-memdcd-to-etmemd.patch b/0049-Add-engine-memdcd-to-etmemd.patch new file mode 100644 index 0000000..ec8bc1f --- /dev/null +++ b/0049-Add-engine-memdcd-to-etmemd.patch @@ -0,0 +1,481 @@ +From 498679879e2a81820126971839a23d307cdce9f5 Mon Sep 17 00:00:00 2001 +From: Yangxin <245051644@qq.com> +Date: Thu, 30 Sep 2021 18:09:41 +0800 +Subject: [PATCH 49/50] Add engine memdcd to etmemd. + +Signed-off-by: Yangxin <245051644@qq.com> +--- + etmem/CMakeLists.txt | 1 + + etmem/inc/etmemd_inc/etmemd_engine.h | 1 + + etmem/inc/etmemd_inc/etmemd_memdcd.h | 31 +++ + etmem/src/etmemd_src/etmemd_engine.c | 2 + + etmem/src/etmemd_src/etmemd_memdcd.c | 374 +++++++++++++++++++++++++++ + 5 files changed, 409 insertions(+) + create mode 100644 etmem/inc/etmemd_inc/etmemd_memdcd.h + create mode 100644 etmem/src/etmemd_src/etmemd_memdcd.c + +diff --git a/etmem/CMakeLists.txt b/etmem/CMakeLists.txt +index 6d11da9..b5eb83e 100644 +--- a/etmem/CMakeLists.txt ++++ b/etmem/CMakeLists.txt +@@ -31,6 +31,7 @@ set(ETMEMD_SRC + ${ETMEMD_SRC_DIR}/etmemd_log.c + ${ETMEMD_SRC_DIR}/etmemd_project.c + ${ETMEMD_SRC_DIR}/etmemd_engine.c ++ ${ETMEMD_SRC_DIR}/etmemd_memdcd.c + ${ETMEMD_SRC_DIR}/etmemd_slide.c + ${ETMEMD_SRC_DIR}/etmemd_cslide.c + ${ETMEMD_SRC_DIR}/etmemd_thirdparty.c +diff --git a/etmem/inc/etmemd_inc/etmemd_engine.h b/etmem/inc/etmemd_inc/etmemd_engine.h +index 0134d21..9a50e10 100644 +--- a/etmem/inc/etmemd_inc/etmemd_engine.h ++++ b/etmem/inc/etmemd_inc/etmemd_engine.h +@@ -24,6 +24,7 @@ + enum eng_type { + SLIDE_ENGINE = 0, + CSLIDE_ENGINE, ++ MEMDCD_ENGINE, + DYNAMIC_FB_ENGINE, + HISTORICAL_FB_ENGINE, + THIRDPARTY_ENGINE, +diff --git a/etmem/inc/etmemd_inc/etmemd_memdcd.h b/etmem/inc/etmemd_inc/etmemd_memdcd.h +new file mode 100644 +index 0000000..96f9307 +--- /dev/null ++++ b/etmem/inc/etmemd_inc/etmemd_memdcd.h +@@ -0,0 +1,31 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-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: YangXin ++ * Create: 2021-4-20 ++ * Description: This is a header file of the function declaration for memdcd engine.. ++ ******************************************************************************/ ++ ++ ++#ifndef ETMEMD_MEMDCD_H ++#define ETMEMD_MEMDCD_H ++ ++#include "etmemd_engine.h" ++ ++#define MAX_SOCK_PATH_LENGTH 108 ++ ++struct memdcd_params { ++ struct task_executor *executor; ++ char memdcd_socket[MAX_SOCK_PATH_LENGTH]; ++}; ++ ++int fill_engine_type_memdcd(struct engine *eng, GKeyFile *config); ++ ++#endif +diff --git a/etmem/src/etmemd_src/etmemd_engine.c b/etmem/src/etmemd_src/etmemd_engine.c +index f57d52b..6a14ecb 100644 +--- a/etmem/src/etmemd_src/etmemd_engine.c ++++ b/etmem/src/etmemd_src/etmemd_engine.c +@@ -18,6 +18,7 @@ + #include "etmemd_engine.h" + #include "etmemd_slide.h" + #include "etmemd_cslide.h" ++#include "etmemd_memdcd.h" + #include "etmemd_thirdparty.h" + #include "etmemd_log.h" + #include "etmemd_common.h" +@@ -36,6 +37,7 @@ struct engine_remove_item { + static struct engine_add_item g_engine_add_items[] = { + {"slide", fill_engine_type_slide}, + {"cslide", fill_engine_type_cslide}, ++ {"memdcd", fill_engine_type_memdcd}, + {"thirdparty", fill_engine_type_thirdparty}, + }; + +diff --git a/etmem/src/etmemd_src/etmemd_memdcd.c b/etmem/src/etmemd_src/etmemd_memdcd.c +new file mode 100644 +index 0000000..635e5a2 +--- /dev/null ++++ b/etmem/src/etmemd_src/etmemd_memdcd.c +@@ -0,0 +1,374 @@ ++/****************************************************************************** ++ * 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: Yangxin ++ * Create: 2021-04-05 ++ * Description: API of memdcd engine. ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "securec.h" ++#include "etmemd_log.h" ++#include "etmemd_common.h" ++#include "etmemd_engine.h" ++#include "etmemd_scan.h" ++#include "etmemd_migrate.h" ++#include "etmemd_pool_adapter.h" ++#include "etmemd_file.h" ++#include "etmemd_memdcd.h" ++ ++#define MAX_VMA_NUM 512 ++#define RESP_MSG_MAX_LEN 10 ++#define CLIENT_RECV_DEFAULT_TIME 10 ++ ++enum MEMDCD_CMD_TYPE { ++ MEMDCD_CMD_MEM = 0 ++}; ++ ++enum SwapType { ++ SWAP_TYPE_VMA_ADDR = 0xFFFFFF01, ++ SWAP_TYPE_MAX ++}; ++ ++struct vma_addr { ++ uint64_t start_addr; ++ uint64_t vma_len; ++}; ++ ++struct vma_addr_with_count { ++ struct vma_addr vma; ++ int count; ++}; ++ ++enum MEMDCD_MESSAGE_STATUS { ++ MEMDCD_SEND_START, ++ MEMDCD_SEND_PROCESS, ++ MEMDCD_SEND_END, ++}; ++ ++struct swap_vma_with_count { ++ enum SwapType type; ++ uint64_t length; ++ uint64_t total_length; ++ enum MEMDCD_MESSAGE_STATUS status; ++ struct vma_addr_with_count vma_addrs[MAX_VMA_NUM]; ++}; ++ ++struct memory_message { ++ int pid; ++ uint32_t enable_uswap; ++ struct swap_vma_with_count vma; ++}; ++ ++struct memdcd_message { ++ enum MEMDCD_CMD_TYPE cmd_type; ++ union { ++ struct memory_message memory_msg; ++ }; ++}; ++ ++static int memdcd_connection_init(time_t tm_out, const char sock_path[]) ++{ ++ struct sockaddr_un addr; ++ int len; ++ ++ int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (sockfd < 0){ ++ etmemd_log(ETMEMD_LOG_ERR, "new socket for memdcd error."); ++ return -1; ++ } ++ ++ len = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path); ++ ++ if (memset_s(&addr, sizeof(struct sockaddr_un), ++ 0, sizeof(struct sockaddr_un)) != EOK) { ++ etmemd_log(ETMEMD_LOG_ERR, "clear addr failed\n"); ++ goto err_out; ++ } ++ ++ addr.sun_family = AF_UNIX; ++ if (memcpy_s(addr.sun_path, sizeof(addr.sun_path), ++ sock_path, strlen(sock_path)) != EOK) { ++ etmemd_log(ETMEMD_LOG_ERR, "copy for memdcd server path to addr fail, error(%s)\n", ++ strerror(errno)); ++ goto err_out; ++ } ++ ++ /* note, the below two line **MUST** maintain the order */ ++ len = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path); ++ addr.sun_path[0] = '\0'; ++ if (connect(sockfd, (struct sockaddr *)&addr, len) < 0){ ++ etmemd_log(ETMEMD_LOG_ERR, "connect memdcd failed\n"); ++ goto err_out; ++ } ++ ++ return sockfd; ++ ++err_out: ++ close(sockfd); ++ return -1; ++} ++ ++static int send_data_to_memdcd(unsigned int pid, struct memdcd_message *msg, const char sock_path[]) ++{ ++ int client_fd; ++ int ret = 0; ++ int read_bytes; ++ int write_bytes; ++ char buff[RESP_MSG_MAX_LEN] = {0}; ++ time_t recv_timeout = CLIENT_RECV_DEFAULT_TIME; ++ ++ client_fd = memdcd_connection_init(recv_timeout, sock_path); ++ if (client_fd < 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "%s: connect error %d.\n", __func__, client_fd); ++ return -1; ++ } ++ write_bytes = write(client_fd, msg, sizeof(struct memdcd_message)); ++ if (write_bytes <= 0) { ++ etmemd_log(ETMEMD_LOG_DEBUG, "etmemd_socket: send to memdcd for pid %u, bytes: %d\n", ++ pid, write_bytes); ++ ret = -1; ++ goto CLOSE_SOCK; ++ } ++ ++ read_bytes = read(client_fd, buff, RESP_MSG_MAX_LEN); ++ if (read_bytes > 0) { ++ if (strcmp(buff, "success") == 0) { ++ etmemd_log(ETMEMD_LOG_INFO, "etmemd_socket: recv respond success.\n"); ++ } else { ++ etmemd_log(ETMEMD_LOG_ERR, "etmemd_socket: recv respond failed.\n"); ++ ret = -1; ++ } ++ } ++ ++CLOSE_SOCK: ++ close(client_fd); ++ ++ return ret; ++} ++ ++static int memdcd_do_migrate(unsigned int pid, struct page_refs *page_refs_list, const char sock_path[]) ++{ ++ int count = 0, total_count = 0; ++ int ret = 0; ++ struct swap_vma_with_count *swap_vma = NULL; ++ struct page_refs *page_refs = page_refs_list; ++ struct memdcd_message *msg; ++ ++ if (page_refs_list == NULL) { ++ /* do nothing */ ++ return 0; ++ } ++ ++ while (page_refs != NULL) { ++ page_refs = page_refs->next; ++ total_count++; ++ } ++ page_refs = page_refs_list; ++ ++ msg = (struct memdcd_message *)calloc(1, sizeof(struct memdcd_message)); ++ if (msg == NULL) { ++ etmemd_log(ETMEMD_LOG_WARN, "memigd_socket: malloc for swap vma failed. \n"); ++ return -1; ++ } ++ ++ msg->cmd_type = MEMDCD_CMD_MEM; ++ msg->memory_msg.pid = pid; ++ msg->memory_msg.enable_uswap = true; ++ msg->memory_msg.vma.status = MEMDCD_SEND_START; ++ ++ swap_vma = &(msg->memory_msg.vma); ++ swap_vma->type = SWAP_TYPE_VMA_ADDR; ++ swap_vma->total_length = total_count; ++ ++ while (page_refs != NULL) { ++ swap_vma->vma_addrs[count].vma.start_addr = page_refs->addr; ++ swap_vma->vma_addrs[count].vma.vma_len = page_type_to_size(page_refs->type); ++ swap_vma->vma_addrs[count].count = page_refs->count; ++ count++; ++ page_refs = page_refs->next; ++ ++ if (count < MAX_VMA_NUM) { ++ continue; ++ } ++ if (page_refs == NULL) { ++ break; ++ } ++ swap_vma->length = count * sizeof(struct vma_addr_with_count); ++ if (send_data_to_memdcd(pid, msg, sock_path) != 0) { ++ ret = -1; ++ goto FREE_SWAP; ++ } ++ count = 0; ++ msg->memory_msg.vma.status = MEMDCD_SEND_PROCESS; ++ if (memset_s(swap_vma->vma_addrs, sizeof(swap_vma->vma_addrs), ++ 0, sizeof(swap_vma->vma_addrs)) != EOK) { ++ etmemd_log(ETMEMD_LOG_ERR, "clear swap_vma failed\n"); ++ ret = -1; ++ goto FREE_SWAP; ++ } ++ } ++ ++ if (msg->memory_msg.vma.status != MEMDCD_SEND_START) ++ msg->memory_msg.vma.status = MEMDCD_SEND_END; ++ swap_vma->length = count * sizeof(struct vma_addr_with_count); ++ if (send_data_to_memdcd(pid, msg, sock_path) != 0) { ++ ret = -1; ++ } ++ ++FREE_SWAP: ++ free(msg); ++ return ret; ++} ++ ++static void *memdcd_executor(void *arg) ++{ ++ struct task_pid *tk_pid = (struct task_pid *)arg; ++ struct memdcd_params *memdcd_params = (struct memdcd_params *)(tk_pid->tk->params); ++ struct page_refs *page_refs = 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_page_refs_unexpected, &page_refs); ++ page_refs = etmemd_do_scan(tk_pid, tk_pid->tk); ++ if (page_refs != NULL) { ++ if (memdcd_do_migrate(tk_pid->pid, page_refs, memdcd_params->memdcd_socket) != 0) { ++ etmemd_log(ETMEMD_LOG_WARN, "memdcd migrate for pid %u fail\n", tk_pid->pid); ++ } ++ } ++ ++ /* 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, ++ * but mig_policy_func() may fails to move page_refs in rare cases. ++ * It will do nothing if page_refs is NULL */ ++ pthread_cleanup_pop(1); ++ ++ return NULL; ++} ++ ++static int fill_task_sock_path(void *obj, void *val) ++{ ++ const char *default_path = "@_memdcd.server"; ++ ++ struct memdcd_params *params = (struct memdcd_params *)obj; ++ char *sock_path = (char *)val; ++ ++ if(strcmp(sock_path, "-") == 0) { ++ if (strncpy_s(params->memdcd_socket, MAX_SOCK_PATH_LENGTH, default_path, strlen(default_path)) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "strncpy for memdcd_socket fail"); ++ return -1; ++ } ++ } else { ++ if (strncpy_s(params->memdcd_socket, MAX_SOCK_PATH_LENGTH, sock_path, strlen(sock_path)) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "strncpy for memdcd_socket fail"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct config_item g_memdcd_task_config_items[] = { ++ {"Sock", STR_VAL, fill_task_sock_path, false}, ++}; ++ ++static int memdcd_fill_task(GKeyFile *config, struct task *tk) ++{ ++ struct memdcd_params *params = calloc(1, sizeof(struct memdcd_params)); ++ memset_s(params->memdcd_socket, MAX_SOCK_PATH_LENGTH, 0, MAX_SOCK_PATH_LENGTH); ++ ++ if (params == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "alloc memdcd param fail\n"); ++ return -1; ++ } ++ ++ if (parse_file_config(config, TASK_GROUP, g_memdcd_task_config_items, ARRAY_SIZE(g_memdcd_task_config_items), ++ (void *)params) != 0) { ++ etmemd_log(ETMEMD_LOG_ERR, "memdcd fill task fail\n"); ++ goto free_params; ++ } ++ ++ if (strlen(params->memdcd_socket) >= MAX_SOCK_PATH_LENGTH) { ++ etmemd_log(ETMEMD_LOG_ERR, "length of engine param Sock must less than 108.\n"); ++ goto free_params; ++ } ++ ++ tk->params = params; ++ return 0; ++ ++free_params: ++ free(params); ++ return -1; ++} ++ ++static void memdcd_clear_task(struct task *tk) ++{ ++ free(tk->params); ++ tk->params = NULL; ++} ++ ++static int memdcd_start_task(struct engine *eng, struct task *tk) ++{ ++ struct memdcd_params *params = tk->params; ++ ++ params->executor = malloc(sizeof(struct task_executor)); ++ if (params->executor == NULL) { ++ etmemd_log(ETMEMD_LOG_ERR, "memdcd alloc memory for task_executor fail\n"); ++ return -1; ++ } ++ ++ params->executor->tk = tk; ++ params->executor->func = memdcd_executor; ++ if (start_threadpool_work(params->executor) != 0) { ++ free(params->executor); ++ params->executor = NULL; ++ etmemd_log(ETMEMD_LOG_ERR, "memdcd start task executor fail\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void memdcd_stop_task(struct engine *eng, struct task *tk) ++{ ++ struct memdcd_params *params = tk->params; ++ ++ stop_and_delete_threadpool_work(tk); ++ free(params->executor); ++ params->executor = NULL; ++} ++ ++struct engine_ops g_memdcd_eng_ops = { ++ .fill_eng_params = NULL, ++ .clear_eng_params = NULL, ++ .fill_task_params = memdcd_fill_task, ++ .clear_task_params = memdcd_clear_task, ++ .start_task = memdcd_start_task, ++ .stop_task = memdcd_stop_task, ++ .alloc_pid_params = NULL, ++ .free_pid_params = NULL, ++ .eng_mgt_func = NULL, ++}; ++ ++int fill_engine_type_memdcd(struct engine *eng, GKeyFile *config) ++{ ++ eng->ops = &g_memdcd_eng_ops; ++ eng->engine_type = MEMDCD_ENGINE; ++ eng->name = "memdcd"; ++ return 0; ++} +\ No newline at end of file +-- +2.27.0 + diff --git a/0050-Add-CMakeLists.txt-for-three-features-of-etmem.patch b/0050-Add-CMakeLists.txt-for-three-features-of-etmem.patch new file mode 100644 index 0000000..8cd6ac7 --- /dev/null +++ b/0050-Add-CMakeLists.txt-for-three-features-of-etmem.patch @@ -0,0 +1,39 @@ +From 1aef995d51254409b7aa1e2e84b9b750007e2413 Mon Sep 17 00:00:00 2001 +From: YangXin <245051644@qq.com> +Date: Thu, 30 Sep 2021 18:58:33 +0800 +Subject: [PATCH 50/50] Add CMakeLists.txt for three features of etmem. + +Signed-off-by: YangXin <245051644@qq.com> +--- + CMakeLists.txt | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + create mode 100644 CMakeLists.txt + +diff --git a/CMakeLists.txt b/CMakeLists.txt +new file mode 100644 +index 0000000..a5d6761 +--- /dev/null ++++ b/CMakeLists.txt +@@ -0,0 +1,18 @@ ++# /****************************************************************************** ++# * Copyright (c) Huawei Technologies Co., Ltd. 2020-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:YangXin ++# * Create: 2021-09-31 ++# * Description:CMakeLists for three features of etmem to compile ++# ******************************************************************************/ ++ ++add_subdirectory(etmem) ++add_subdirectory(memRouter) ++add_subdirectory(userswap) +\ No newline at end of file +-- +2.27.0 + diff --git a/etmem.spec b/etmem.spec index 46752a8..a014c9c 100644 --- a/etmem.spec +++ b/etmem.spec @@ -2,7 +2,7 @@ Name: etmem Version: 1.0 -Release: 6 +Release: 7 Summary: etmem License: Mulan PSL v2 Source0: etmem-%{version}.tar.gz @@ -55,11 +55,13 @@ Patch44: 0045-add-dram_percent-to-etmem.patch Patch45: 0046-Fix-memory-leak-in-slide-engine.patch Patch46: 0047-move-all-the-files-to-sub-directory-of-etmem.patch Patch47: 0048-Commit-new-features-memRouter-and-userswap-to-etmem.patch +Patch48: 0049-Add-engine-memdcd-to-etmemd.patch +Patch49: 0050-Add-CMakeLists.txt-for-three-features-of-etmem.patch #Dependency BuildRequires: cmake gcc gcc-c++ -BuildRequires: libboundscheck -Requires: libboundscheck +BuildRequires: libboundscheck numactl-devel libcap-devel json-c-devel +Requires: libboundscheck json-c libcap numactl %description etmem module @@ -76,23 +78,34 @@ make %install mkdir -p $RPM_BUILD_ROOT%{_bindir} +mkdir -p $RPM_BUILD_ROOT%{_libdir} +mkdir -p $RPM_BUILD_ROOT%{_includedir} install -d $RPM_BUILD_ROOT%{_sysconfdir}/etmem/ -install -m 0500 build/bin/etmem $RPM_BUILD_ROOT%{_bindir} -install -m 0500 build/bin/etmemd $RPM_BUILD_ROOT%{_bindir} -install -m 0600 conf/example_conf.yaml $RPM_BUILD_ROOT%{_sysconfdir}/etmem/ +install -m 0500 etmem/build/bin/etmem $RPM_BUILD_ROOT%{_bindir} +install -m 0500 etmem/build/bin/etmemd $RPM_BUILD_ROOT%{_bindir} +install -m 0600 etmem/conf/example_conf.yaml $RPM_BUILD_ROOT%{_sysconfdir}/etmem/ +install -m 0550 build/memRouter/memdcd $RPM_BUILD_ROOT%{_bindir} +install -m 0550 build/userswap/libuswap.a $RPM_BUILD_ROOT%{_libdir} +install -m 0644 userswap/include/uswap_api.h $RPM_BUILD_ROOT%{_includedir} %files %defattr(-,root,root,0750) %{_bindir}/etmem %{_bindir}/etmemd %dir %{_sysconfdir}/etmem %{_sysconfdir}/etmem/example_conf.yaml +%{_bindir}/memdcd +%{_libdir}/libuswap.a +%{_includedir}/uswap_api.h %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %changelog +* Thu Oct 30 2021 yangxin <245051644@qq.com> 1.0-7 +- Update etmem and add new features memRouter and userswap.= + * Mon Aug 1 2021 louhongxiang 1.0-6 - cancel write permission of root. -- Gitee From 074446fe04035077e77878f583db5b53bd8a5a61 Mon Sep 17 00:00:00 2001 From: Kemeng Shi Date: Tue, 19 Oct 2021 18:58:25 +0800 Subject: [PATCH 4/4] etmem: Fix build problems Add missing Requires Remove write permssion in %file section after strip Change Requires numactl to numactl-libs Signed-off-by: Kemeng Shi (cherry picked from commit 6a04742f87976901a7ec968f7593c55963fe8330) --- etmem.spec | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/etmem.spec b/etmem.spec index a014c9c..31c3c3b 100644 --- a/etmem.spec +++ b/etmem.spec @@ -2,7 +2,7 @@ Name: etmem Version: 1.0 -Release: 7 +Release: 8 Summary: etmem License: Mulan PSL v2 Source0: etmem-%{version}.tar.gz @@ -59,9 +59,10 @@ Patch48: 0049-Add-engine-memdcd-to-etmemd.patch Patch49: 0050-Add-CMakeLists.txt-for-three-features-of-etmem.patch #Dependency -BuildRequires: cmake gcc gcc-c++ +BuildRequires: cmake gcc gcc-c++ glib2-devel BuildRequires: libboundscheck numactl-devel libcap-devel json-c-devel -Requires: libboundscheck json-c libcap numactl +Requires: libboundscheck json-c libcap numactl-libs +Requires: glib2 %description etmem module @@ -82,28 +83,33 @@ mkdir -p $RPM_BUILD_ROOT%{_libdir} mkdir -p $RPM_BUILD_ROOT%{_includedir} install -d $RPM_BUILD_ROOT%{_sysconfdir}/etmem/ -install -m 0500 etmem/build/bin/etmem $RPM_BUILD_ROOT%{_bindir} -install -m 0500 etmem/build/bin/etmemd $RPM_BUILD_ROOT%{_bindir} +install -m 0700 etmem/build/bin/etmem $RPM_BUILD_ROOT%{_bindir} +install -m 0700 etmem/build/bin/etmemd $RPM_BUILD_ROOT%{_bindir} install -m 0600 etmem/conf/example_conf.yaml $RPM_BUILD_ROOT%{_sysconfdir}/etmem/ -install -m 0550 build/memRouter/memdcd $RPM_BUILD_ROOT%{_bindir} -install -m 0550 build/userswap/libuswap.a $RPM_BUILD_ROOT%{_libdir} +install -m 0750 build/memRouter/memdcd $RPM_BUILD_ROOT%{_bindir} +install -m 0750 build/userswap/libuswap.a $RPM_BUILD_ROOT%{_libdir} install -m 0644 userswap/include/uswap_api.h $RPM_BUILD_ROOT%{_includedir} %files %defattr(-,root,root,0750) -%{_bindir}/etmem -%{_bindir}/etmemd +%attr(0500, -, -) %{_bindir}/etmem +%attr(0500, -, -) %{_bindir}/etmemd %dir %{_sysconfdir}/etmem %{_sysconfdir}/etmem/example_conf.yaml -%{_bindir}/memdcd -%{_libdir}/libuswap.a +%attr(0550, -, -) %{_bindir}/memdcd +%attr(0550, -, -) %{_libdir}/libuswap.a %{_includedir}/uswap_api.h %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %changelog -* Thu Oct 30 2021 yangxin <245051644@qq.com> 1.0-7 +* Thu Oct 20 2021 shikemeng 1.0-8 +- Add missing Requires +- Remove write permssion in %file after strip +- Change Requires numactl to numactl-libs + +* Thu Sep 30 2021 yangxin <245051644@qq.com> 1.0-7 - Update etmem and add new features memRouter and userswap.= * Mon Aug 1 2021 louhongxiang 1.0-6 -- Gitee