4 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
29 #include <sys/types.h>
32 #include <sys/sysinfo.h>
34 #include <sys/resource.h>
35 #include <memory-cgroup.h>
37 #include <linux/loop.h>
42 #include "module-data.h"
43 #include "dbus-handler.h"
44 #include "swap-common.h"
45 #include "config-parser.h"
46 #include "lowmem-handler.h"
51 #include "file-helper.h"
52 #include "proc-common.h"
53 #include "proc-main.h"
58 #define SWAP_PRIORITY 20
59 #define SWAP_HARD_LIMIT_DEFAULT 0.5
60 #define SWAP_FORCE_RECLAIM_NUM_MAX 5
61 #define SWAP_RECLAIM_PAGES_MAX 2560
62 #define SWAP_RECLAIM_PAGES_MIN 128
63 #define SWAP_MEMCG_SWAPPINESS 60
64 #define SWAP_MIN_SWAPPINESS 0
65 #define SWAP_EARLYRECLAIM_TIME_DEFAULT 60
66 #define SWAP_EARLYRECLAIM_INTERVAL 1
67 #define SWAP_EARLYRECLAIM_MAXTRY 2
68 #define SWAP_EARLYRECLAIM_THRESHOLD_DEFAULT MBYTE_TO_BYTE(1024)
70 #define EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN "early memory reclaim (done to retrieve resources used by daemons during system start-up)"
79 enum swap_reclaim_node {
81 SWAP_NODE_FORCE_RECLAIM,
86 struct proc_app_info *pai;
90 struct swap_safe_queue {
95 struct swap_thread_bundle {
96 struct swap_status_msg msg;
97 enum swap_thread_op op;
100 static pthread_mutex_t swap_mutex;
101 static pthread_cond_t swap_cond;
102 static struct swap_safe_queue swap_thread_queue;
103 static struct module_ops swap_modules_ops;
104 static float swap_hard_limit_fraction = SWAP_HARD_LIMIT_DEFAULT;
105 static enum swap_reclaim_node swap_node;
107 static bool arg_swap_enable = false;
108 static bool arg_swap_at_boot = false;
109 static int arg_timer_swap_at_boot = SWAP_EARLYRECLAIM_TIME_DEFAULT;
110 static enum swap_type arg_swap_type = SWAP_TYPE_ZRAM;
111 static int current_swappiness = SWAP_MEMCG_SWAPPINESS;
113 static GSList *swap_module; /* module list */
114 static GSource *swap_activating_timer = NULL;
115 static unsigned long arg_swap_at_boot_threshold = SWAP_EARLYRECLAIM_THRESHOLD_DEFAULT;
116 static int arg_swap_at_boot_maxtry = SWAP_EARLYRECLAIM_MAXTRY;
117 static int arg_swap_at_boot_interval = SWAP_EARLYRECLAIM_INTERVAL;
119 static int swap_sort_func(const struct swap_module_ops *a,
120 const struct swap_module_ops *b)
122 return (a->priority - b->priority);
125 void swap_add(const struct swap_module_ops *ops)
127 _I("Swap module name: %s", ops->name);
128 swap_module = g_slist_insert_sorted(swap_module,
130 (GCompareFunc) swap_sort_func);
133 void swap_remove(const struct swap_module_ops *ops)
135 swap_module = g_slist_remove(swap_module, (gpointer)ops);
138 int do_mkswap(const char *device)
140 const char *argv[3] = { "/sbin/mkswap", NULL, NULL };
142 argv[1] = (char *) device;
144 return exec_cmd(ARRAY_SIZE(argv), argv);
147 int do_dd(char *input, char *output, unsigned int size, unsigned int count)
149 const char *argv[6] = { "/bin/dd", NULL, NULL, NULL, NULL, NULL };
150 _cleanup_free_ char *if_arg = NULL, *of_arg = NULL;
151 _cleanup_free_ char *bs_arg = NULL, *count_arg = NULL;
153 if (asprintf(&if_arg, "if=%s", input) < 0 ||
154 asprintf(&of_arg, "of=%s", output) < 0 ||
155 asprintf(&bs_arg, "bs=%u", size) < 0 ||
156 asprintf(&count_arg, "count=%u", count) < 0)
164 return exec_cmd(ARRAY_SIZE(argv), argv);
167 static const char *compact_reason_to_str(enum swap_compact_reason reason)
169 static const char *reasons_table[] = {"lowmem: critical", "lowmem: oom",
171 if (reason >= SWAP_COMPACT_MEM_LEVEL_CRITICAL && reason < SWAP_COMPACT_RESASON_MAX)
172 return reasons_table[reason];
176 static unsigned int swap_calculate_hard_limit_in_bytes(unsigned int mem_subcg_usage)
178 return (unsigned int)((float)mem_subcg_usage * swap_hard_limit_fraction);
181 static inline void swap_add_bundle(struct swap_thread_bundle *bundle)
183 pthread_mutex_lock(&swap_thread_queue.lock);
184 g_queue_push_tail(swap_thread_queue.queue, bundle);
185 pthread_mutex_unlock(&swap_thread_queue.lock);
188 static int swap_move_to_cgroup_by_pid(enum cgroup_type type, pid_t pid)
192 int lowest_oom_score_adj;
193 struct proc_app_info *pai = find_app_info(pid);
194 GSList *iter_child = NULL;
196 error = proc_get_oom_score_adj(pid, &oom_score_adj);
198 _E("Cannot get oom_score_adj of pid (%d)", pid);
199 return RESOURCED_ERROR_FAIL;
202 lowest_oom_score_adj = cgroup_get_lowest_oom_score_adj(type);
204 if (oom_score_adj < lowest_oom_score_adj)
205 oom_score_adj = lowest_oom_score_adj;
208 return proc_set_oom_score_adj(pid, oom_score_adj, pai);
210 proc_set_oom_score_adj(pai->main_pid, oom_score_adj, pai);
213 return RESOURCED_ERROR_NONE;
215 gslist_for_each_item(iter_child, pai->childs) {
216 pid_t child = GPOINTER_TO_PID(iter_child->data);
217 error = proc_set_oom_score_adj(child, oom_score_adj, pai);
224 static int swap_use_hard_limit(char *memcg)
227 unsigned int usage, memcg_limit;
229 ret = cgroup_read_node_uint32(memcg, MEMCG_USAGE, &usage);
230 if (ret != RESOURCED_ERROR_NONE)
233 memcg_limit = swap_calculate_hard_limit_in_bytes(usage);
234 _D("Swap request: %s cgroup usage is %u, hard limit set to %u (hard limit fraction %f)",
235 memcg, usage, memcg_limit, swap_hard_limit_fraction);
236 if (memcg_limit != 0)
237 ret = check_oom_and_set_limit(memcg, memcg_limit);
239 /* If the group is empty don't set the limit to enable adding processes. */
240 ret = cgroup_write_node_int32(memcg, MEMCG_SWAP_LIMIT_BYTE, -1);
241 ret = cgroup_write_node_int32(memcg, MEMCG_LIMIT_BYTE, -1);
244 if (ret != RESOURCED_ERROR_NONE)
245 _E("Not able to set hard limit of %s memory cgroup", memcg);
250 static int swap_use_force_reclaim(char *memcg)
253 int try = SWAP_FORCE_RECLAIM_NUM_MAX;
254 unsigned int usage, nr_to_reclaim;
255 unsigned int total_reclaim = 0;
256 bool root_memcg = false;
259 * In case of MEMCG_PATH,
260 * it is no necessary to check anon usage of memcg
261 * because it doesn't include all memory usage.
262 * But instead, try to swap memory as much as possible.
263 * It will be happend only once after booting done.
266 if (!strncmp(memcg, MEMCG_PATH, len))
271 * Currently, we only move only anonymous pages to swap memcg by
272 * setting move_charge_at_immigrate as 0. However, there might
273 * be a little of inactive file pages in swap memcg.
274 * For this reason it's better to use '.stat' and calculate only
275 * anoynymous memory usage.
278 ret = cgroup_read_node_uint32(memcg, MEMCG_USAGE, &usage);
280 ret = memcg_get_anon_usage(memcg, &usage);
282 if (ret != RESOURCED_ERROR_NONE)
285 nr_to_reclaim = BYTE_TO_PAGE(usage);
286 if (nr_to_reclaim <= SWAP_RECLAIM_PAGES_MIN)
287 break; /* don't reclaim if little gain */
288 if (nr_to_reclaim > SWAP_RECLAIM_PAGES_MAX)
289 nr_to_reclaim = SWAP_RECLAIM_PAGES_MAX;
291 total_reclaim += nr_to_reclaim;
292 ret = cgroup_write_node_uint32(memcg, MEMCG_FORCE_RECLAIM,
294 if (ret != RESOURCED_ERROR_NONE)
295 break; /* if we can't reclaim don't continue */
300 _D("FORCE_RECLAIM tried %u pages from %s", total_reclaim, memcg);
304 static int swap_start_reclaim(char *memcg)
309 r = cgroup_read_node_int32(memcg, MEMCG_SWAPPINESS,
315 * Resourced sometimes changes swappiness value.
316 * But, this function means to reclaim memory by force as much as possible
317 * If current swappiness value is smaller than default swappiness,
318 * it is better to set default value before reclaiming memory.
319 * And current value will be set again after reclaim.
321 if (swappiness != SWAP_MEMCG_SWAPPINESS) {
322 r = cgroup_write_node_uint32(memcg,
323 MEMCG_SWAPPINESS, SWAP_MEMCG_SWAPPINESS);
325 _I("failed to write %s %d to %s the",
326 MEMCG_SWAPPINESS, SWAP_MEMCG_SWAPPINESS, memcg);
330 if (swap_node == SWAP_NODE_FORCE_RECLAIM)
331 swap_use_force_reclaim(memcg);
333 swap_use_hard_limit(memcg);
336 * restore original swappiness value
338 if (current_swappiness != SWAP_MEMCG_SWAPPINESS) {
339 r = cgroup_write_node_uint32(memcg,
340 MEMCG_SWAPPINESS, current_swappiness);
342 _I("failed to write %s %d to %s the",
343 MEMCG_SWAPPINESS, SWAP_MEMCG_SWAPPINESS, memcg);
350 static int swap_compact_in_module(void)
354 struct swap_module_ops *swaps;
356 gslist_for_each_item(iter, swap_module) {
357 swaps = (struct swap_module_ops *)iter->data;
362 r = swaps->reclaim(swaps);
366 return fail ? fail : 0;
369 //static int swap_reclaim_memcg(struct swap_status_msg msg)
370 static int swap_reclaim_memcg(char *path)
377 r = swap_compact_in_module();
381 * If swap space is not enough, swap module will trigger the proactive LMK.
382 * While saving swap space again,
383 * swap will be blocked with minimum swappiness.
385 r = cgroup_read_node_int32(path,
386 MEMCG_SWAPPINESS, ¤t_swappiness);
390 r = cgroup_write_node_uint32(path,
391 MEMCG_SWAPPINESS, SWAP_MIN_SWAPPINESS);
396 return swap_start_reclaim(path);
399 static int gen_urandom_string(char *buf, size_t len)
401 _cleanup_close_ int fd = -1;
404 fd = open("/dev/urandom", O_RDONLY);
408 l = read(fd, buf, len);
415 static int swap_losetup(struct swap_module_ops *swap,
419 char swapdevice[MAX_NAME_LENGTH];
420 char passwd[LO_KEY_SIZE] = "";
423 if (!is_empty(crypt_type)) {
424 r = gen_urandom_string(passwd, LO_KEY_SIZE);
426 _E("Failed to generate random passwd: %m");
431 r = find_loop_device(swapfile, swapdevice);
434 _I("'%s' is already setuped to '%s'", swapfile, swapdevice);
437 _E("Failed to find available loop device.");
441 r = losetup(swapdevice, swapfile, 0, 0,
442 crypt_type, passwd, false);
445 _E("Failed to setup loop: %d", r);
450 swap->path = strdup(swapdevice);
456 int swap_set_file(char *filename, struct swap_module_ops *swap, char *crypt_type)
460 r = access(filename, F_OK);
461 if (r < 0 && errno == ENOENT) {
462 r = do_dd("/dev/zero", filename, PAGE_SIZE,
463 KBYTE_TO_BYTE(swap->k_size) >> PAGE_SHIFT);
465 _E("Failed to create swap file(%s), exit code: %d",
469 _E("Failed to create swap file(%s): %d",
473 _I("SwapFile is created: %s", filename);
475 _E("Failed to access swap file(%s): %m", filename);
479 r = swap_losetup(swap, crypt_type, filename);
486 r = do_mkswap(swap->path);
488 _E("Failed to make swap device(%s), exit code: %d", swap->path, r);
491 _E("Failed to make swap device(%s): %d", swap->path, r);
496 bool swap_is_on(const char *name)
498 _cleanup_proc_swaps_free_ struct proc_swaps **swaps = NULL;
501 n = proc_get_swaps(&swaps);
502 if (n <= 0 || !swaps)
505 for (i = 0; i < n; i++) {
506 if (streq(swaps[i]->filename, name))
513 static void swap_activate_in_module(void)
517 struct swap_module_ops *swaps;
518 static bool early_reclaim;
520 r = cgroup_read_node_int32(MEMCG_PATH,
521 MEMCG_SWAPPINESS, ¤t_swappiness);
525 if (swap_get_state() == SWAP_ON)
528 gslist_for_each_item(iter, swap_module) {
529 int flags = SWAP_FLAG_DISCARD;
531 swaps = (struct swap_module_ops *)iter->data;
533 if (!swaps->activate)
536 r = swaps->activate(swaps);
539 _E("%s activate failed", swaps->name);
542 swap_set_state(SWAP_ON);
546 #ifdef SWAP_FLAG_PREFER
547 if (swaps->priority >= 0) {
548 flags |= SWAP_FLAG_PREFER |
549 (swaps->priority & SWAP_FLAG_PRIO_MASK) << SWAP_FLAG_PRIO_SHIFT;
552 r = swapon(swaps->path, flags);
554 _E("Failed to turn on swap device(%s): %m", swaps->path);
557 _I("swap device(%s) was turned on: %s", swaps->name, swaps->path);
560 * Most system daemons use much memory for intializing own process.
561 * but there is little change to reuse it while running.
562 * So early reclaiming moves unused system memory to swap device.
563 * If multiple swap devices are available,
564 * first swap with the lowest priority will start reclaiming.
566 if (!early_reclaim) {
567 int try = arg_swap_at_boot_maxtry;
568 unsigned int usage, prev_usage = 0;
570 r = cgroup_read_node_uint32(MEMCG_PATH,
571 MEMCG_SWAP_USAGE, &prev_usage);
573 prev_usage = UINT_MAX;
577 swap_start_reclaim(MEMCG_PATH);
579 r = cgroup_read_node_uint32(MEMCG_PATH,
580 MEMCG_SWAP_USAGE, &usage);
582 _E("Early reclaimed is aborted");
587 * Continue to reclaim memory at boot time until
588 * there is no more saving or trial reaches maximum.
589 * The default threshold is very large, so it may
592 if (!try || prev_usage - usage < arg_swap_at_boot_threshold)
597 * To prevent continuous reclaim to harm entire system,
598 * having relaxation on each reclaim
600 sleep(arg_swap_at_boot_interval);
602 early_reclaim = true;
605 swap_set_state(SWAP_ON);
609 static void *swap_thread_main(void * data)
612 struct swap_thread_bundle *bundle;
614 setpriority(PRIO_PROCESS, 0, SWAP_PRIORITY);
617 pthread_mutex_lock(&swap_mutex);
618 /* THREAD: WAIT FOR START */
619 pthread_mutex_lock(&swap_thread_queue.lock);
620 is_empty = g_queue_is_empty(swap_thread_queue.queue);
621 pthread_mutex_unlock(&swap_thread_queue.lock);
623 /* The queue is empty, wait for thread signal */
624 pthread_cond_wait(&swap_cond, &swap_mutex);
627 /* We're in swap thread, now it's time to dispatch bundles */
628 pthread_mutex_lock(&swap_thread_queue.lock);
629 bundle = g_queue_pop_head(swap_thread_queue.queue);
630 pthread_mutex_unlock(&swap_thread_queue.lock);
635 switch (bundle->op) {
636 /* Swap activation operttion: mkswap, swapon etc. */
637 case SWAP_OP_ACTIVATE:
638 swap_activate_in_module();
640 /* Swap reclaim opertation: move to swap, force_reclaim */
641 case SWAP_OP_RECLAIM:
642 swap_reclaim_memcg(bundle->msg.path);
644 /* Swap compact operation of zsmalloc. */
645 case SWAP_OP_COMPACT:
646 swap_compact_in_module();
648 /* Move inactive procesess to swap, and reclaim after that. */
651 _D("wrong swap thread operation selected");
656 pthread_mutex_unlock(&swap_mutex);
661 static int swap_communicate_thread(struct swap_thread_bundle *bundle)
666 return RESOURCED_ERROR_NO_DATA;
668 swap_add_bundle(bundle);
669 /* Try to signal swap thread, that there is some work to do */
670 ret = pthread_mutex_trylock(&swap_mutex);
672 pthread_cond_signal(&swap_cond);
673 pthread_mutex_unlock(&swap_mutex);
674 _I("send signal to swap thread");
675 return RESOURCED_ERROR_NONE;
676 } else if (ret == EBUSY) {
677 _D("swap thread already active");
678 return RESOURCED_ERROR_NONE;
681 _E("pthread_mutex_trylock fail: %d, errno: %d", ret, errno);
682 return RESOURCED_ERROR_FAIL;
685 static int swap_start_handler(void *data)
688 struct swap_thread_bundle *bundle;
692 return RESOURCED_ERROR_NO_DATA;
695 bundle = malloc(sizeof(struct swap_thread_bundle));
697 return RESOURCED_ERROR_OUT_OF_MEMORY;
699 bundle->op = SWAP_OP_RECLAIM;
700 memcpy(bundle->msg.path, data, sizeof(struct swap_status_msg));
701 ret = swap_communicate_thread(bundle);
705 static int swap_internal_bundle_sender(enum swap_thread_op operation)
708 struct swap_thread_bundle *bundle;
710 bundle = malloc(sizeof(struct swap_thread_bundle));
712 return RESOURCED_ERROR_OUT_OF_MEMORY;
713 bundle->op = operation;
714 ret = swap_communicate_thread(bundle);
718 static int swap_activate_handler(void *data)
720 return swap_internal_bundle_sender(SWAP_OP_ACTIVATE);
723 static gboolean swap_activate_timer_cb(gpointer data)
725 _I("Starting an " EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN);
726 swap_activating_timer = NULL;
727 swap_internal_bundle_sender(SWAP_OP_ACTIVATE);
731 static int swap_booting_done(void *data)
733 if (!arg_swap_at_boot) {
734 _D(EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN " is disabled");
735 return RESOURCED_ERROR_NONE;
738 /* No need to involve the timer mechanism when the delay is 0,
739 * partially to keep things simple but primarily because it can
740 * introduce an artificial delay since the timer is ran async
741 * in another thread. */
742 if (arg_timer_swap_at_boot == 0) {
743 swap_activate_timer_cb(NULL);
744 return RESOURCED_ERROR_NONE;
747 _D("booting done; starting up a timer to perform an " EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN " %ds from now", arg_timer_swap_at_boot);
748 swap_activating_timer = g_timeout_source_new_seconds((guint) arg_timer_swap_at_boot);
749 g_source_set_callback(swap_activating_timer, swap_activate_timer_cb, NULL, NULL);
750 g_source_attach(swap_activating_timer, NULL);
752 return RESOURCED_ERROR_NONE;
755 static int swap_compact_handler(void *data)
757 _I("compaction request. Reason: %s",
758 compact_reason_to_str((enum swap_compact_reason)data));
759 return swap_internal_bundle_sender(SWAP_OP_COMPACT);
762 /* This function is callback function for the notifier RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT.
763 * This notifier is notified from normal_act function of vmpressure module whenever the
764 * memory state changes to normal.
765 * This function resets the hard limit of the swap subcgroup to -1 (unlimited) */
766 static int swap_cgroup_reset_limit(void *data)
769 struct memcg_info *mi = (struct memcg_info *)data;
772 _E("memory cgroup information is NULL");
773 return RESOURCED_ERROR_INVALID_PARAMETER;
776 if (swap_node == SWAP_NODE_FORCE_RECLAIM)
777 return RESOURCED_ERROR_NONE;
779 ret = check_oom_and_set_limit(mi->name, mi->limit);
780 // ret = cgroup_write_node_int32(mi->name, MEMCG_LIMIT_BYTE, mi->limit);
781 if (ret != RESOURCED_ERROR_NONE)
782 _E("Failed to change hard limit of %s cgroup to -1", mi->name);
784 _D("changed hard limit of %s cgroup to -1", mi->name);
789 static void swap_start_pid_dbus_signal_handler(GVariant *params)
792 struct cgroup *cgroup_swap;
793 // struct swap_status_msg ss_msg;
795 do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &pid);
797 _D("Invalid parameter");
801 cgroup_swap = get_cgroup_tree(CGROUP_LOW);
804 swap_move_to_cgroup_by_pid(CGROUP_LOW, pid);
806 ss_msg.type = CGROUP_LOW;
807 ss_msg.memcg_info = cgroup_swap->memcg_info;*/
808 swap_start_handler(cgroup_swap->memcg_info->name);
809 _I("swap cgroup entered : pid : %d", (int)pid);
813 static const struct d_bus_signal dbus_signals[] = {
815 {RESOURCED_PATH_SWAP, RESOURCED_INTERFACE_SWAP,
816 SIGNAL_NAME_SWAP_START_PID, swap_start_pid_dbus_signal_handler, NULL},
819 static void swap_dbus_init(void)
821 d_bus_register_signals(dbus_signals, ARRAY_SIZE(dbus_signals));
824 static int config_parse_swap_types(
828 enum swap_type *type = data;
832 if (is_empty(rvalue))
837 FOREACH_WORD_SEPARATOR(word, l, rvalue, "+|", state) {
838 if (strneq(word, "zram", l))
839 *type |= SWAP_TYPE_ZRAM;
840 else if (strneq(word, "file", l))
841 *type |= SWAP_TYPE_FILE;
842 else if (strneq(word, "zswap", l))
843 *type |= SWAP_TYPE_ZSWAP;
851 static void print_swap_conf(void)
853 _I("[DEBUG] swap %s", arg_swap_enable == true ? "enable" : "disable");
854 _I("[DEBUG] swap at boot %s", arg_swap_at_boot == true ? "enable" : "disable");
855 _I("[DEBUG] swap type = %d", arg_swap_type);
857 for(int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) {
858 _I("[DEBUG] cgroup (%s) swapiness = %d", cgroup == CGROUP_VIP ? "vip" :
859 cgroup == CGROUP_HIGH ? "high" :
860 cgroup == CGROUP_MEDIUM ? "medium" : "lowest", get_memcg_info(cgroup)->swappiness);
864 static int swap_parse_config_file(void)
866 int r = RESOURCED_ERROR_NONE;
868 struct swap_module_ops *swaps;
869 struct swap_conf *swap_conf = get_swap_conf();
871 _E("Swap configuration should not be NULL");
872 return RESOURCED_ERROR_FAIL;
875 arg_swap_enable = swap_conf->enable;
876 if (arg_swap_enable == false)
879 arg_swap_at_boot = swap_conf->boot_reclaim_enable;
880 if (config_parse_swap_types(swap_conf->type, &arg_swap_type) < 0) {
881 _E("[DEBUG] Failed to parse type of swap, so use default zram type");
882 arg_swap_type = SWAP_TYPE_ZRAM;
885 for(int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) {
886 if (swap_conf->swappiness[cgroup] >= 0 &&
887 swap_conf->swappiness[cgroup] <= 100)
888 memcg_info_set_swappiness(get_memcg_info(cgroup),
889 swap_conf->swappiness[cgroup]);
892 gslist_for_each_item(iter, swap_module) {
893 swaps = (struct swap_module_ops *)iter->data;
898 if (!strncmp(swaps->name, "ZRAM", 5))
899 r = swaps->conf(&swap_conf->zram);
900 else if (!strncmp(swaps->name, "ZSWAP", 6))
901 r = swaps->conf(&swap_conf->zswap);
902 else if (!strncmp(swaps->name, "FILESWAP", 9))
903 r = swaps->conf(&swap_conf->fileswap);
913 /*static int swap_parse_config_file(void)
915 const ConfigTableItem items[] = {
916 { "SWAP", "Enable", config_parse_bool,
917 0, &arg_swap_enable },
918 { "SWAP", "Type", config_parse_swap_types,
920 { "SWAP", "ReclaimAtBoot", config_parse_bool,
921 0, &arg_swap_at_boot },
922 { "SWAP", "TimerReclaimAtBoot", config_parse_int,
923 0, &arg_timer_swap_at_boot },
924 { "SWAP", "ReclaimAtBootThreshold", config_parse_bytes,
925 0, &arg_swap_at_boot_threshold },
926 { "SWAP", "ReclaimAtBootMaxTry", config_parse_int,
927 0, &arg_swap_at_boot_maxtry },
928 { "SWAP", "ReclaimAtBootInterval", config_parse_int,
929 0, &arg_swap_at_boot_interval },
936 r = config_parse_new(SWAP_CONF_FILE, (void*) items);
938 _E("Failed to parse configuration file: %d", r);
942 if (arg_timer_swap_at_boot < 0) {
943 _E("The `TimerReclaimAtBoot` field in the `" SWAP_CONF_FILE "` config file cannot be negative because it represents a time period for " EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN);
950 static int swap_thread_create(void)
955 pthread_mutex_init(&swap_mutex, NULL);
956 pthread_cond_init(&swap_cond, NULL);
957 pthread_mutex_init(&(swap_thread_queue.lock), NULL);
958 swap_thread_queue.queue = g_queue_new();
960 if (!swap_thread_queue.queue) {
961 _E("fail to allocate swap thread queue");
962 return RESOURCED_ERROR_FAIL;
965 ret = pthread_create(&pth, NULL, &swap_thread_main, (void *)NULL);
967 _E("pthread creation for swap_thread failed\n");
973 return RESOURCED_ERROR_NONE;
976 static int swap_init(void)
980 struct swap_module_ops *swaps = NULL;
981 int swap_pri = SWAP_PRI_DEFAULT;
983 r = swap_parse_config_file();
987 if (!arg_swap_enable)
990 memcg_write_optimizer_params();
992 gslist_for_each_safe(swap_module, iter, next, swaps) {
993 swaps = (struct swap_module_ops *)iter->data;
994 if (!CHECK_BIT(arg_swap_type, swaps->type)) {
1003 * swap_pri has a priority of previous swaps.
1004 * If swaps has SWAP_PRI_DISABLE,
1005 * swap will be supported with only one module.
1006 * After that, other modules should be removed.
1008 if (swap_pri == SWAP_PRI_DISABLE) {
1010 _E("don't allow other %s module", swaps->name);
1013 swap_pri = swaps->priority;
1015 r = swaps->init(swaps);
1017 _E("%s module init failed", swaps->name);
1022 r = swap_thread_create();
1024 _E("swap thread create failed");
1032 static int swap_check_node(char *path)
1034 _cleanup_fclose_ FILE *fp = NULL;
1036 fp = fopen(path, "w");
1038 _E("%s open failed", path);
1039 return RESOURCED_ERROR_NO_DATA;
1041 return RESOURCED_ERROR_NONE;
1044 static int resourced_swap_check_runtime_support(void *data)
1050 * Check whether CONFIG_SWAP is enabled in kernel.
1052 if (access("/proc/swaps", R_OK) != 0)
1056 * Check whether kernel is supporting MEMCG_SWAP.
1058 r = cgroup_read_node_uint32(MEMCG_PATH,
1059 MEMCG_SWAP_USAGE, &usage);
1067 * Quote from: kernel Documentation/cgroups/memory.txt
1069 * Each bit in move_charge_at_immigrate has its own meaning about what type of
1070 * charges should be moved. But in any case, it must be noted that an account of
1071 * a page or a swap can be moved only when it is charged to the task's current
1072 * (old) memory cgroup.
1074 * bit | what type of charges would be moved ?
1075 * -----+------------------------------------------------------------------------
1076 * 0 | A charge of an anonymous page (or swap of it) used by the target task.
1077 * | You must enable Swap Extension (see 2.4) to enable move of swap charges.
1078 * -----+------------------------------------------------------------------------
1079 * 1 | A charge of file pages (normal file, tmpfs file (e.g. ipc shared memory)
1080 * | and swaps of tmpfs file) mmapped by the target task. Unlike the case of
1081 * | anonymous pages, file pages (and swaps) in the range mmapped by the task
1082 * | will be moved even if the task hasn't done page fault, i.e. they might
1083 * | not be the task's "RSS", but other task's "RSS" that maps the same file.
1084 * | And mapcount of the page is ignored (the page can be moved even if
1085 * | page_mapcount(page) > 1). You must enable Swap Extension (see 2.4) to
1086 * | enable move of swap charges.
1089 * In our case it's better to set only the bit number 0 to charge only
1090 * anon pages. Therefore file pages etc. will be managed directly by
1091 * kernel reclaim mechanisms.
1092 * That will help focus us only on swapping the memory that we actually
1093 * can swap - anonymous pages.
1094 * This will prevent from flushing file pages from memory - causing
1095 * slowdown when re-launching applications.
1097 static void resourced_swap_change_memcg_settings(enum cgroup_type type)
1100 struct cgroup *cgroup_swap = NULL;
1101 char buf[MAX_PATH_LENGTH];
1103 cgroup_swap = get_cgroup_tree(type);
1107 cgroup_write_node_uint32(cgroup_swap->memcg_info->name, MEMCG_MOVE_CHARGE, 1);
1108 snprintf(buf, sizeof(buf), "%s/%s", MEMCG_PATH, MEMCG_FORCE_RECLAIM);
1109 ret = swap_check_node(buf);
1110 if (ret == RESOURCED_ERROR_NONE) {
1111 swap_node = SWAP_NODE_FORCE_RECLAIM;
1112 _I("use %s node for swapping memory", MEMCG_FORCE_RECLAIM);
1114 swap_node = SWAP_NODE_HARD_LIMIT;
1115 _I("use %s node for swapping memory", MEMCG_LIMIT_BYTE);
1119 static int resourced_swap_init(void *data)
1123 resourced_swap_change_memcg_settings(CGROUP_LOW);
1124 swap_set_state(SWAP_OFF);
1127 if (ret != RESOURCED_ERROR_NONE)
1130 if (!resourced_restarted()) {
1131 register_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, swap_booting_done);
1133 _I("Assuming swap is already set up. To reconfigure, reboot the device.");
1136 register_notifier(RESOURCED_NOTIFIER_SWAP_START, swap_start_handler);
1137 register_notifier(RESOURCED_NOTIFIER_SWAP_ACTIVATE, swap_activate_handler);
1138 register_notifier(RESOURCED_NOTIFIER_SWAP_COMPACT, swap_compact_handler);
1139 register_notifier(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, swap_cgroup_reset_limit);
1144 static int resourced_swap_finalize(void *data)
1146 unregister_notifier(RESOURCED_NOTIFIER_SWAP_START, swap_start_handler);
1147 unregister_notifier(RESOURCED_NOTIFIER_SWAP_ACTIVATE, swap_activate_handler);
1148 unregister_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, swap_booting_done);
1149 unregister_notifier(RESOURCED_NOTIFIER_SWAP_COMPACT, swap_compact_handler);
1150 unregister_notifier(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, swap_cgroup_reset_limit);
1152 g_queue_free(swap_thread_queue.queue);
1154 return RESOURCED_ERROR_NONE;
1157 static struct module_ops swap_modules_ops = {
1158 .priority = MODULE_PRIORITY_NORMAL,
1160 .init = resourced_swap_init,
1161 .exit = resourced_swap_finalize,
1162 .check_runtime_support = resourced_swap_check_runtime_support,
1165 MODULE_REGISTER(&swap_modules_ops)