swap : make module to build without error 56/120356/10
authorKichan Kwon <k_c.kwon@samsung.com>
Wed, 22 Mar 2017 11:04:21 +0000 (20:04 +0900)
committerKichan Kwon <k_c.kwon@samsung.com>
Thu, 11 May 2017 02:21:32 +0000 (11:21 +0900)
- 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 <k_c.kwon@samsung.com>
packaging/resourced.spec
src/common/procfs.c
src/common/procfs.h
src/common/util.c
src/common/util.h
src/memory/vmpressure-lowmem-handler.c
src/swap/swap-common.c [deleted file]
src/swap/swap.c
src/swap/swap.conf

index 41107a7986b4e66a27df90b3376852cd8ccc7f54..5e0446519191f321801590740075b9918f130055 100644 (file)
@@ -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
 
index 7b6a8258ac2a0d07b52f63fc196bce1cb3bee5ec..40a9576ea7626d5e7fdad90e29a6e4ae325f6e62 100644 (file)
@@ -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)
 {
index 1cff7b48319f963b2784c426d0a130d27994f7e7..5e905b83e538e0e8d884622f65ee67c4e1bddea2 100644 (file)
@@ -273,6 +273,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
index fbca481658a057bfc892c08c63e65e02ab3309b9..5cf81097f413e5d7524af2c8672247301ef92516 100644 (file)
 #include <unistd.h>
 #include <stdio.h>
 #include <assert.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #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;
index af6a0acc4dc5cf53e04e84cb48bf2138deaedf13..28ba1238996916bd95574ea32e95d72b42766cd2 100644 (file)
@@ -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_;
index 8a307d378e0510f3262cb6bba3ae29e05b5860b2..947eae0da9a8d2a7c3c29eff578179bbc5dbaa6e 100644 (file)
@@ -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 (file)
index d329368..0000000
+++ /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;
-}
index 577e5a957a1b29ac899baedf9194db01fb8b1717..55d8b8a70f0bd09f10f2ca5f953fddd83d1aa68a 100644 (file)
 #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"
 #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,
index e6ec647106804e303654fc19529abbec0c3f3ef6..aaf5b1984d52cfa6e40991728a0032607a1ab9f5 100644 (file)
@@ -1,4 +1,5 @@
 [CONTROL]
+SWAP_ENABLE=0
 # zram parameter
 COMP_ALGORITHM=lz4
 # swap ratio