From bd759fa3b51eef118fa6170df4e2c4d8e7eba01e Mon Sep 17 00:00:00 2001 From: Kichan Kwon Date: Wed, 22 Mar 2017 20:04:21 +0900 Subject: [PATCH] swap : make module to build without error - Until now, swap module is not concerned (just disabled) - However, it can be used vaulable in low memory - In addition, it checks whether kernel supports force reclaim or not - Regardless of force reclaim, you can use swap module Change-Id: I3c6c41e3f40b5a1293bad91cfd3d628c148c9e36 Signed-off-by: Kichan Kwon --- packaging/resourced.spec | 2 +- src/common/procfs.c | 17 ++ src/common/procfs.h | 6 + src/common/util.c | 61 ++++- src/common/util.h | 3 +- src/memory/vmpressure-lowmem-handler.c | 10 + src/swap/swap-common.c | 38 --- src/swap/swap.c | 447 ++++++++++++++++++--------------- src/swap/swap.conf | 1 + 9 files changed, 335 insertions(+), 250 deletions(-) delete mode 100644 src/swap/swap-common.c diff --git a/packaging/resourced.spec b/packaging/resourced.spec index 41107a7..5e04465 100644 --- a/packaging/resourced.spec +++ b/packaging/resourced.spec @@ -17,7 +17,7 @@ Source0: %{name}-%{version}.tar.gz %define freezer_module ON %define memory_module ON %define mem_stress OFF -%define swap_module OFF +%define swap_module ON %define timer_slack OFF %define vip_agent_module ON diff --git a/src/common/procfs.c b/src/common/procfs.c index 7b6a825..40a9576 100644 --- a/src/common/procfs.c +++ b/src/common/procfs.c @@ -379,6 +379,23 @@ unsigned int proc_get_swap_free(void) return mi.value[MEMINFO_ID_SWAP_FREE]; } +unsigned int proc_get_swap_total(void) +{ + struct meminfo mi; + int ret; + char error_buf[256]; + + ret = proc_get_meminfo(&mi, MEMINFO_MASK_SWAP_TOTAL); + if (ret < 0) { + _E("Failed to get %s: %s", + meminfo_id_to_string(MEMINFO_ID_SWAP_TOTAL), + strerror_r(-ret, error_buf, sizeof(error_buf))); + return 0; + } + + return mi.value[MEMINFO_ID_SWAP_TOTAL]; +} + int proc_get_cpu_time(pid_t pid, unsigned long *utime, unsigned long *stime, unsigned long *starttime) { diff --git a/src/common/procfs.h b/src/common/procfs.h index 1cff7b4..5e905b8 100644 --- a/src/common/procfs.h +++ b/src/common/procfs.h @@ -274,6 +274,12 @@ unsigned int proc_get_mem_available(void); unsigned int proc_get_swap_free(void); /** + * @desc get SwapTotal from /proc/meminfo + * @return 0 if the values can't be read or the total swap size + */ +unsigned int proc_get_swap_total(void); + +/** * @desc get number of CPUs from /proc/cpuinfo * @return 0 if the number can't be found or number of CPUs */ diff --git a/src/common/util.c b/src/common/util.c index fbca481..5cf8109 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -27,12 +27,71 @@ #include #include #include +#include +#include #include "util.h" #include "trace.h" #include "resourced.h" -int exec_cmd(char *argv[], char *filename) +static int parent(pid_t pid) +{ + int status; + + /* wait for child */ + if (waitpid(pid, &status, 0) != -1) { + /* terminated normally */ + if (WIFEXITED(status)) { + _I("%d terminated by exit(%d)", pid, WEXITSTATUS(status)); + return WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) + _I("%d terminated by signal %d", pid, WTERMSIG(status)); + else if (WIFSTOPPED(status)) + _I("%d stopped by signal %d", pid, WSTOPSIG(status)); + } else + _I("%d waitpid() failed : %m", pid); + + return RESOURCED_ERROR_FAIL; +} + +static void child(int argc, const char *argv[]) +{ + int i, r; + + for (i = 0; i < _NSIG; ++i) + signal(i, SIG_DFL); + + r = execv(argv[0], (char **)argv); + if (r < 0) + exit(EXIT_FAILURE); +} + +int exec_cmd(int argc, const char *argv[]) +{ + pid_t pid; + int r = 0; + + if (!argv) + return RESOURCED_ERROR_INVALID_PARAMETER; + + if (access(argv[0], F_OK)) { + _E("There is no %s", argv[0]); + return RESOURCED_ERROR_INVALID_PARAMETER; + } + + pid = fork(); + if (pid < 0) { + _E("failed to fork"); + r = -errno; + } else if (pid == 0) { + child(argc, argv); + } else + r = parent(pid); + + return r; +} + +int exec_dump_cmd(char *argv[], char *filename) { int status = 0; int fd = -1; diff --git a/src/common/util.h b/src/common/util.h index af6a0ac..28ba123 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -145,7 +145,8 @@ static inline bool strstart_with(const char *str, const char *with) filename - output file * @return None */ -int exec_cmd(char *argv[], char *filename); +int exec_dump_cmd(char *argv[], char *filename); +int exec_cmd(int argc, const char *argv[]); bool streq_ptr(const char *a, const char *b) _pure_; int parse_boolean(const char *v) _pure_; diff --git a/src/memory/vmpressure-lowmem-handler.c b/src/memory/vmpressure-lowmem-handler.c index 8a307d3..947eae0 100644 --- a/src/memory/vmpressure-lowmem-handler.c +++ b/src/memory/vmpressure-lowmem-handler.c @@ -284,6 +284,7 @@ static struct module_ops memory_modules_ops; static const struct module_ops *lowmem_ops; static bool oom_popup_enable; static bool oom_popup; +static bool memcg_swap_status; static struct memcg_info gmi[MEMCG_MAX] = { {LOWMEM_ROOT_CGROUP, "/", MEMCG_ROOT,}, @@ -1133,6 +1134,7 @@ static void lowmem_swap_memory(enum memcg_type type, struct memcg_info *mi) msg.type = type; msg.info = mi; resourced_notify(RESOURCED_NOTIFIER_SWAP_START, &msg); + memcg_swap_status = true; } void lowmem_trigger_swap(pid_t pid, int memcg_idx) @@ -1182,6 +1184,7 @@ static void memory_level_send_system_event(int lv) static void normal_act(void) { int ret, status; + struct swap_status_msg msg; ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status); if (ret) @@ -1193,6 +1196,13 @@ static void normal_act(void) } change_lowmem_state(LOWMEM_NORMAL); + + if (swap_get_state() == SWAP_ON && memcg_swap_status) { + msg.type = MEMCG_SWAP; + msg.info = memcg_tree[msg.type]->info; + resourced_notify(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, &msg); + memcg_swap_status = false; + } if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED) resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE, (void *)CGROUP_FREEZER_ENABLED); diff --git a/src/swap/swap-common.c b/src/swap/swap-common.c deleted file mode 100644 index d329368..0000000 --- a/src/swap/swap-common.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * resourced - * - * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file swap-common.c - * - * @desc Swap state definition for resourced - */ - -#include "swap-common.h" -#include "module-data.h" -#include "trace.h" -#include "macro.h" - -enum swap_state swap_get_state(void) -{ - struct shared_modules_data *modules_data = get_shared_modules_data(); - - ret_value_msg_if(modules_data == NULL, RESOURCED_ERROR_FAIL, - "Invalid shared modules data\n"); - - return modules_data->swap_data.swap_state; -} diff --git a/src/swap/swap.c b/src/swap/swap.c index 577e5a9..55d8b8a 100644 --- a/src/swap/swap.c +++ b/src/swap/swap.c @@ -47,10 +47,12 @@ #include "const.h" #include "file-helper.h" #include "proc-common.h" +#include "proc-main.h" #include "util.h" #define MEMCG_PATH "/sys/fs/cgroup/memory/" #define MEMCG_SIZE_LIMIT "memory.limit_in_bytes" +#define SWAPCG_RECLAIM "memory.force_reclaim" #define MOVE_CHARGE "memory.move_charge_at_immigrate" #define SWAP_ON_EXEC_PATH "/sbin/swapon" @@ -59,6 +61,7 @@ #define SWAP_CONF_FILE RD_CONFIG_FILE(swap) #define SWAP_CONTROL_SECTION "CONTROL" +#define SWAP_CONF_ENABLE "SWAP_ENABLE" #define SWAP_CONF_STREAMS "MAX_COMP_STREAMS" #define SWAP_CONF_ALGORITHM "COMP_ALGORITHM" #define SWAP_CONF_RATIO "RATIO" @@ -84,25 +87,37 @@ #define SWAP_RATIO 0.5 #define SWAP_FULLNESS_RATIO 0.8 #define SWAP_HARD_LIMIT_DEFAULT 0.5 +#define SWAP_FORCE_RECLAIM_NUM_MAX 5 +#define SWAP_RECLIAM_PAGES_MAX 2560 +#define SWAP_RECLIAM_PAGES_MIN 128 enum swap_thread_op { SWAP_OP_ACTIVATE, SWAP_OP_RECLAIM, SWAP_OP_COMPACT, + SWAP_OP_MOVE_TO_SWAP_AND_RECLAIM, SWAP_OP_END, }; +enum swap_reclaim_node { + SWAP_NODE_HARD_LIMIT, + SWAP_NODE_FORCE_RECLAIM, + SWAP_NODE_END, +}; + struct swap_task { struct proc_app_info *pai; int size; }; struct swap_zram_control { + int swap_enable; int max_comp_streams; char comp_algorithm[5]; float ratio; unsigned long swap_size_bytes; unsigned long swap_almost_full_bytes; + enum swap_state swap_status; }; struct swap_safe_queue { @@ -116,23 +131,21 @@ struct swap_thread_bundle { }; static struct swap_zram_control swap_control = { + .swap_enable = 0, .max_comp_streams = -1, .comp_algorithm = "lzo", .ratio = SWAP_RATIO, .swap_size_bytes = 0, .swap_almost_full_bytes = 0, + .swap_status = SWAP_OFF, }; static pthread_mutex_t swap_mutex; static pthread_cond_t swap_cond; static struct swap_safe_queue swap_thread_queue; -static struct module_ops swap_modules_ops; -static char *swap_thread_op_names[SWAP_OP_END] = { - "ACTIVATE", - "RECLAIM", - "COMPACT", -}; +static const struct module_ops swap_modules_ops; static float swap_hard_limit_fraction = SWAP_HARD_LIMIT_DEFAULT; +static enum swap_reclaim_node swap_node; static int swap_compact_handler(void *data); @@ -145,51 +158,38 @@ static const char *compact_reason_to_str(enum swap_compact_reason reason) return ""; } -static void swap_set_state(enum swap_state state) +enum swap_state swap_get_state(void) { - struct shared_modules_data *modules_data = get_shared_modules_data(); - - ret_msg_if(modules_data == NULL, - "Invalid shared modules data\n"); + return swap_control.swap_status; +} +static void swap_set_state(enum swap_state state) +{ if ((state != SWAP_ON) && (state != SWAP_OFF)) return; - modules_data->swap_data.swap_state = state; + swap_control.swap_status = state; } - -static pid_t swap_change_state(enum swap_state state) +static int swap_change_state(enum swap_state state) { - int status; - pid_t child_pid; - pid_t pid = fork(); - - if (pid < 0) { - _E("failed to fork"); - return RESOURCED_ERROR_FAIL; - } - - /* child */ - if (pid == 0) { - if (state == SWAP_ON) - execl(SWAP_ON_EXEC_PATH, SWAP_ON_EXEC_PATH, "-d", - SWAP_ZRAM_DEVICE, (char *)NULL); - else if (state == SWAP_OFF) - execl(SWAP_OFF_EXEC_PATH, SWAP_OFF_EXEC_PATH, - SWAP_ZRAM_DEVICE, (char *)NULL); - exit(0); - } - - /* parent */ - child_pid = waitpid(pid, &status, 0); - if (child_pid < 0) { - _E("can't wait for a pid %d %d: %m", pid, status); - return child_pid; - } - - swap_set_state(state); - return pid; + int ret; + const char *argv[4] = {NULL, }; + + if (state == SWAP_ON) { + argv[0] = SWAP_ON_EXEC_PATH; + argv[1] = "-d"; + argv[2] = SWAP_ZRAM_DEVICE; + } else if (state == SWAP_OFF) { + argv[0] = SWAP_OFF_EXEC_PATH; + argv[1] = SWAP_ZRAM_DEVICE; + } else + return RESOURCED_ERROR_INVALID_PARAMETER; + + ret = exec_cmd(ARRAY_SIZE(argv), argv); + if (!ret) + swap_set_state(state); + return ret; } static unsigned int swap_calculate_hard_limit_in_bytes(unsigned int mem_subcg_usage) @@ -286,33 +286,6 @@ static int swap_sort_by_vmrss(const struct swap_task *ta, return ((int)(tb->size) - (int)(ta->size)); } -static int swap_prepare_victims(GArray *candidates) -{ - _cleanup_app_list_close_ GSList *proc_app_list = PAL_INIT_VALUE; - GSList *iter = NULL; - struct proc_app_info *pai = NULL; - struct swap_task victim; - - /* - * serch victims from proc_app_list - * It was better than searching backround cgroup - * because proc_app_list had already known current state and child processes - */ - proc_app_list = proc_app_list_open(); - gslist_for_each_item(iter, proc_app_list) { - pai = (struct proc_app_info *)iter->data; - if (pai->memory.memcg_idx != MEMCG_BACKGROUND) - continue; - if (pai->lru_state <= PROC_BACKGROUND) - continue; - - memset(&victim, 0, sizeof(struct swap_task)); - victim.pai = pai; - g_array_append_val(candidates, victim); - } - return candidates->len; -} - static int swap_reduce_victims(GArray *candidates, int max) { int index; @@ -356,12 +329,73 @@ static int swap_reduce_victims(GArray *candidates, int max) return RESOURCED_ERROR_NONE; } -static int swap_reclaim_memcg(struct swap_status_msg msg) +static int swap_use_hard_limit(struct memcg_info *mi) { int ret; - unsigned long swap_usage; unsigned int usage, memcg_limit; + ret = memcg_get_usage(mi, &usage); + if (ret != RESOURCED_ERROR_NONE) + usage = 0; + + memcg_limit = swap_calculate_hard_limit_in_bytes(usage); + _D("Swap request: %s cgroup usage is %lu, hard limit set to %lu (hard limit fraction %f)", + mi->name, usage, memcg_limit, swap_hard_limit_fraction); + ret = cgroup_write_node_uint32(mi->name, MEMCG_SIZE_LIMIT, memcg_limit); + if (ret != RESOURCED_ERROR_NONE) + _E("Not able to set hard limit of %s memory cgroup", mi->name); + + return ret; +} + +static int swap_use_force_reclaim(struct memcg_info *mi) +{ + int ret; + int try = SWAP_FORCE_RECLAIM_NUM_MAX; + unsigned int usage, usage_after_reclaim, nr_to_reclaim; + + do { + /* + * Currently, we only move only anonymous pages to swap memcg by + * setting move_charge_at_immigrate as 0. However, there might + * be a little of inactive file pages in swap memcg. + * For this reason it's better to use '.stat' and calculate only + * anoynymous memory usage. + */ + ret = memcg_get_anon_usage(mi, &usage); + if (ret != RESOURCED_ERROR_NONE) + usage = 0; + + nr_to_reclaim = BYTE_TO_PAGE(usage); + if (nr_to_reclaim <= SWAP_RECLIAM_PAGES_MIN) + break; /* don't reclaim if little gain */ + if (nr_to_reclaim > SWAP_RECLIAM_PAGES_MAX) + nr_to_reclaim = SWAP_RECLIAM_PAGES_MAX; + + ret = cgroup_write_node_uint32(mi->name, SWAPCG_RECLAIM, + nr_to_reclaim); + if (ret != RESOURCED_ERROR_NONE) + break; /* if we can't reclaim don't continue */ + + ret = memcg_get_anon_usage(mi, &usage_after_reclaim); + if (ret != RESOURCED_ERROR_NONE) + usage_after_reclaim = 0; + + if (usage_after_reclaim >= usage) + break; /* if we didn't reclaim more, let's stop */ + + _D("FORCE_RECLAIM try: %d, before: %d, after: %d", + try, usage, usage_after_reclaim); + try -= 1; + } while (try > 0); + + return ret; +} + +static int swap_reclaim_memcg(struct swap_status_msg msg) +{ + unsigned long swap_usage; + /* Test for restarted resourced, where zram already activated */ if (swap_control.swap_size_bytes == 0) { swap_control.swap_size_bytes = swap_get_disksize_bytes(); @@ -377,18 +411,10 @@ static int swap_reclaim_memcg(struct swap_status_msg msg) return RESOURCED_ERROR_NONE; } - ret = memcg_get_usage(msg.info, &usage); - if (ret != RESOURCED_ERROR_NONE) - usage = 0; - - memcg_limit = swap_calculate_hard_limit_in_bytes(usage); - _D("Swap request: %s cgroup usage is %lu, hard limit set to %lu (hard limit fraction %f)", - msg.info->name, usage, memcg_limit, swap_hard_limit_fraction); - ret = cgroup_write_node_uint32(msg.info->name, MEMCG_SIZE_LIMIT, memcg_limit); - if (ret != RESOURCED_ERROR_NONE) - _E("Not able to set hard limit of %s memory cgroup", msg.info->name); - - return ret; + if (swap_node == SWAP_NODE_FORCE_RECLAIM) + return swap_use_force_reclaim(msg.info); + else + return swap_use_hard_limit(msg.info); } static int swap_compact_zram(void) @@ -426,75 +452,59 @@ static int swap_compact_zram(void) return RESOURCED_ERROR_NONE; } -static int swap_move_background_to_swap(struct swap_status_msg *msg) +static int swap_move_inactive_to_swap(struct swap_status_msg *msg) { - int max_victims, selected; - int ret = RESOURCED_ERROR_NONE; - GArray *candidates = NULL, *pids_array = NULL; + GSList *proc_app_list = NULL; + GSList *iter; + int ret, max_victims; + struct swap_task victim; + GArray *candidates = NULL; struct memcg *memcg_swap = NULL; - - pids_array = g_array_new(false, false, sizeof(pid_t)); - if (!pids_array) { - _E("failed to allocate memory"); - ret = RESOURCED_ERROR_OUT_OF_MEMORY; - goto out; - } - - /* Get procs to check for swap candidates */ - memcg_get_pids(msg->info, pids_array); - if (pids_array->len == 0) { - ret = RESOURCED_ERROR_NO_DATA; - goto out; - } - /* - * background cgroup finds victims and moves them to swap group - */ - ret = lowmem_get_memcg(MEMCG_SWAP, &memcg_swap); - if (ret != RESOURCED_ERROR_NONE) - return RESOURCED_ERROR_FAIL; + struct proc_app_info *pai = NULL; candidates = g_array_new(false, false, sizeof(struct swap_task)); if (!candidates) { _E("failed to allocate memory"); - ret = RESOURCED_ERROR_OUT_OF_MEMORY; - goto out; + return RESOURCED_ERROR_OUT_OF_MEMORY; + } + memset(&victim, 0, sizeof(struct swap_task)); + + proc_app_list = proc_app_list_open(); + gslist_for_each_item(iter, proc_app_list) { + pai = (struct proc_app_info *)iter->data; + if ((!pai->main_pid) || + (pai->memory.memcg_info != msg->info) || + (pai->memory.oom_score_adj < OOMADJ_BACKGRD_UNLOCKED) || + (pai->lru_state <= PROC_BACKGROUND)) + continue; + victim.pai = pai; + g_array_append_val(candidates, victim); } + proc_app_list_close(); /* - * Let's consider 50% of background apps to be swappable. Using ZRAM - * swap makes the operation on swap cheaper. Only anonymous memory - * is swaped so the results are limited by size of allocations. + * Let's consider 50% of inactive apps to be swappable at once. */ - max_victims = pids_array->len >> 1; - /* It makes no sense if we will have no candidates */ + max_victims = candidates->len >> 1; if (max_victims == 0) { ret = RESOURCED_ERROR_NO_DATA; goto out; } - if (max_victims > SWAP_SORT_MAX) - max_victims = SWAP_SORT_MAX; - - selected = swap_prepare_victims(candidates); - if (selected == 0) { - ret = RESOURCED_ERROR_NO_DATA; - _D("no victims from proc_app_list (pids: %d)", max_victims); + swap_reduce_victims(candidates, max_victims); + ret = lowmem_get_memcg(MEMCG_SWAP, &memcg_swap); + if (ret != RESOURCED_ERROR_NONE) goto out; - } else if (selected > max_victims) - swap_reduce_victims(candidates, max_victims); - /* - * change swap info from background cgroup to swap group + * change swap info from inactive cgroup to swap group * for using same structure to move and swap it */ msg->info = memcg_swap->info; msg->type = MEMCG_SWAP; - swap_move_to_cgroup(msg->info, candidates); + ret = swap_move_to_cgroup(msg->info, candidates); out: if (candidates) g_array_free(candidates, TRUE); - if (pids_array) - g_array_free(pids_array, TRUE); - return ret; + return ret; } static int swap_size(void) @@ -516,22 +526,9 @@ static int swap_size(void) static int swap_mkswap(void) { - pid_t pid = fork(); - - if (pid < 0) { - _E("fork for mkswap failed"); - return pid; - } else if (pid == 0) { - _D("mkswap starts"); - execl(SWAP_MKSWAP_EXEC_PATH, SWAP_MKSWAP_EXEC_PATH, - SWAP_ZRAM_DEVICE, (char *)NULL); - exit(0); - } else { - wait(0); - _D("mkswap ends"); - } + const char *argv[3] = {SWAP_MKSWAP_EXEC_PATH, SWAP_ZRAM_DEVICE, NULL}; - return pid; + return exec_cmd(ARRAY_SIZE(argv), argv); } static int swap_zram_activate(void) @@ -583,25 +580,44 @@ static int swap_zram_activate(void) static void swap_activate_in_module(void) { + int ret; int disksize; + unsigned int swap_size; if (swap_get_state() == SWAP_ON) return; disksize = swap_get_disksize_bytes(); if (disksize <= 0) { - if (swap_zram_activate() < 0) { + ret = swap_zram_activate(); + if (ret < 0) { _E("swap cannot be activated"); return; } } - swap_change_state(SWAP_ON); + + ret = swap_change_state(SWAP_ON); + if (ret != 0) { + /* + * It is possible that resourced was restared etc. and swap + * was already activated in the system earlier (the system wasn't + * restarted). + * Then 'swapon' in swap_change_state will return error, we + * should check if swap was already enabled and if yes handle it. + */ + swap_size = proc_get_swap_total(); + if (swap_size == 0) { + _E("swap state cannot be changed"); + return; + } + swap_set_state(SWAP_ON); + } _D("swap activated"); } static void *swap_thread_main(void * data) { - int is_empty; + int is_empty, ret; struct swap_thread_bundle *bundle; setpriority(PRIO_PROCESS, 0, SWAP_PRIORITY); @@ -638,6 +654,13 @@ static void *swap_thread_main(void * data) case SWAP_OP_COMPACT: swap_compact_zram(); break; + /* Move inactive procesess to swap, and reclaim after that. */ + case SWAP_OP_MOVE_TO_SWAP_AND_RECLAIM: + ret = swap_move_inactive_to_swap(&(bundle->msg)); + /* Check if any process was moved to swap. */ + if (ret == RESOURCED_ERROR_NONE) + swap_reclaim_memcg(bundle->msg); + break; case SWAP_OP_END: default: _D("wrong swap thread operation selected"); @@ -650,31 +673,14 @@ unlock_out: return NULL; } -static int swap_start_handler(void *data) +static int swap_communicate_thread(struct swap_thread_bundle *bundle) { int ret; - struct swap_thread_bundle *bundle; - - if (!data) - return RESOURCED_ERROR_NO_DATA; - bundle = malloc(sizeof(struct swap_thread_bundle)); if (!bundle) - return RESOURCED_ERROR_OUT_OF_MEMORY; - - bundle->op = SWAP_OP_RECLAIM; - memcpy(&(bundle->msg), data, sizeof(struct swap_status_msg)); + return RESOURCED_ERROR_NO_DATA; - if (bundle->msg.type == MEMCG_BACKGROUND) { - ret = swap_move_background_to_swap(&(bundle->msg)); - /* add bundle only if some processes were moved into swap memcg */ - if (ret) { - free(bundle); - return RESOURCED_ERROR_NO_DATA; - } - } swap_add_bundle(bundle); - /* Try to signal swap thread, that there is some work to do */ ret = pthread_mutex_trylock(&swap_mutex); if (ret == 0) { @@ -682,62 +688,65 @@ static int swap_start_handler(void *data) pthread_mutex_unlock(&swap_mutex); _I("send signal to swap thread"); return RESOURCED_ERROR_NONE; - } - - if (ret && ret == EBUSY) { + } else if (ret == EBUSY) { _D("swap thread already active"); - } else { - _E("pthread_mutex_trylock fail : %d, errno : %d", ret, errno); - return RESOURCED_ERROR_FAIL; + return RESOURCED_ERROR_NONE; } - return RESOURCED_ERROR_NONE; + _E("pthread_mutex_trylock fail: %d, errno: %d", ret, errno); + return RESOURCED_ERROR_FAIL; + } -static int swap_simple_bundle_sender(enum swap_thread_op operation) +static int swap_start_handler(void *data) { int ret; struct swap_thread_bundle *bundle; + if (!data) + return RESOURCED_ERROR_NO_DATA; + bundle = malloc(sizeof(struct swap_thread_bundle)); if (!bundle) return RESOURCED_ERROR_OUT_OF_MEMORY; - bundle->op = operation; - swap_add_bundle(bundle); - - if (operation >= 0 && operation < SWAP_OP_END) - _D("added %s operation to swap queue", - swap_thread_op_names[operation]); + bundle->op = SWAP_OP_RECLAIM; + memcpy(&(bundle->msg), data, sizeof(struct swap_status_msg)); - /* Try to signal swap thread, that there is some work to do */ - ret = pthread_mutex_trylock(&swap_mutex); - if (ret == 0) { - pthread_cond_signal(&swap_cond); - pthread_mutex_unlock(&swap_mutex); - _I("send signal to swap thread"); - return RESOURCED_ERROR_NONE; + if (bundle->msg.type == MEMCG_APPS) { + /* + * Background tasks are concerned special way, we select + * tasks and move them to Swap cgroup. They are not there already. + */ + bundle->op = SWAP_OP_MOVE_TO_SWAP_AND_RECLAIM; } + ret = swap_communicate_thread(bundle); + return ret; +} - if (ret && ret == EBUSY) { - _D("swap thread already active"); - } else { - _E("pthread_mutex_trylock fail : %d, errno : %d", ret, errno); - return RESOURCED_ERROR_FAIL; - } - return RESOURCED_ERROR_NONE; +static int swap_internal_bundle_sender(enum swap_thread_op operation) +{ + int ret; + struct swap_thread_bundle *bundle; + + bundle = malloc(sizeof(struct swap_thread_bundle)); + if (!bundle) + return RESOURCED_ERROR_OUT_OF_MEMORY; + bundle->op = operation; + ret = swap_communicate_thread(bundle); + return ret; } static int swap_activate_handler(void *data) { - return swap_simple_bundle_sender(SWAP_OP_ACTIVATE); + return swap_internal_bundle_sender(SWAP_OP_ACTIVATE); } static int swap_compact_handler(void *data) { _I("compaction request. Reason: %s", compact_reason_to_str((enum swap_compact_reason)data)); - return swap_simple_bundle_sender(SWAP_OP_COMPACT); + return swap_internal_bundle_sender(SWAP_OP_COMPACT); } /* This function is callback function for the notifier RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT. @@ -749,6 +758,9 @@ static int swap_cgroup_reset_limit(void *data) int ret, limit; struct swap_status_msg *msg = data; + if (swap_node == SWAP_NODE_FORCE_RECLAIM) + return RESOURCED_ERROR_NONE; + limit = -1; ret = cgroup_write_node_int32(msg->info->name, MEMCG_SIZE_LIMIT, limit); if (ret != RESOURCED_ERROR_NONE) @@ -866,7 +878,13 @@ static int load_swap_config(struct parse_result *result, void *user_data) if (strncmp(result->section, SWAP_CONTROL_SECTION, strlen(SWAP_CONTROL_SECTION)+1)) return RESOURCED_ERROR_NO_DATA; - if (!strncmp(result->name, SWAP_CONF_STREAMS, strlen(SWAP_CONF_STREAMS)+1)) { + if (!strncmp(result->name, SWAP_CONF_ENABLE, strlen(SWAP_CONF_ENABLE)+1)) { + int value = atoi(result->value); + if (value > 0) { + swap_control.swap_enable = value; + _D("swap enable is %d", swap_control.swap_enable); + } + } else if (!strncmp(result->name, SWAP_CONF_STREAMS, strlen(SWAP_CONF_STREAMS)+1)) { int value = atoi(result->value); if (value > 0) { swap_control.max_comp_streams = value; @@ -946,6 +964,12 @@ static int swap_init(void) int ret; config_parse(SWAP_CONF_FILE, load_swap_config, NULL); + + if (swap_control.swap_enable != 1) { + _I("swap module is disabled."); + return RESOURCED_ERROR_FAIL; + } + ret = swap_thread_create(); if (ret) { _E("swap thread create failed"); @@ -956,23 +980,21 @@ static int swap_init(void) return ret; } -static int swap_check_node(void) +static int swap_check_node(char *path) { - FILE *fp; + _cleanup_fclose_ FILE *fp = NULL; - fp = fopen(SWAP_ZRAM_DEVICE, "w"); + fp = fopen(path, "w"); if (fp == NULL) { - _E("%s open failed", SWAP_ZRAM_DEVICE); + _E("%s open failed", path); return RESOURCED_ERROR_NO_DATA; } - fclose(fp); - return RESOURCED_ERROR_NONE; } static int resourced_swap_check_runtime_support(void *data) { - return swap_check_node(); + return swap_check_node(SWAP_ZRAM_DEVICE); } /* @@ -1010,22 +1032,29 @@ static void resourced_swap_change_memcg_settings(enum memcg_type type) { int ret; struct memcg *memcg_swap = NULL; + char buf[MAX_PATH_LENGTH]; ret = lowmem_get_memcg(type, &memcg_swap); if (ret != RESOURCED_ERROR_NONE) return; cgroup_write_node_uint32(memcg_swap->info->name, MOVE_CHARGE, 1); + snprintf(buf, sizeof(buf), "%s/%s", MEMCG_PATH, SWAPCG_RECLAIM); + ret = swap_check_node(buf); + if (ret == RESOURCED_ERROR_NONE) { + swap_node = SWAP_NODE_FORCE_RECLAIM; + _I("use %s node for swapping memory", SWAPCG_RECLAIM); + } else { + swap_node = SWAP_NODE_HARD_LIMIT; + _I("use %s node for swapping memory", MEMCG_SIZE_LIMIT); + } } static int resourced_swap_init(void *data) { int ret; - cgroup_make_subdir(MEMCG_PATH, "swap", NULL); resourced_swap_change_memcg_settings(MEMCG_SWAP); - resourced_swap_change_memcg_settings(MEMCG_FAVORITE); - resourced_swap_change_memcg_settings(MEMCG_PLATFORM); swap_set_state(SWAP_OFF); ret = swap_init(); @@ -1054,7 +1083,7 @@ static int resourced_swap_finalize(void *data) return RESOURCED_ERROR_NONE; } -static struct module_ops swap_modules_ops = { +static const struct module_ops swap_modules_ops = { .priority = MODULE_PRIORITY_NORMAL, .name = "swap", .init = resourced_swap_init, diff --git a/src/swap/swap.conf b/src/swap/swap.conf index e6ec647..aaf5b19 100644 --- a/src/swap/swap.conf +++ b/src/swap/swap.conf @@ -1,4 +1,5 @@ [CONTROL] +SWAP_ENABLE=0 # zram parameter COMP_ALGORITHM=lz4 # swap ratio -- 2.7.4