47801e2436b12d283b393f8eb372b1d98181a039
[platform/core/system/resourced.git] / src / resource-optimizer / memory / swap / swap.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18 */
19
20 /*
21  * @file swap.c
22  * @desc swap process
23  */
24 #include <trace.h>
25 #include <stdlib.h>
26 #include <sys/stat.h>
27 #include <sys/vfs.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <pthread.h>
32 #include <sys/sysinfo.h>
33 #include <sys/time.h>
34 #include <sys/resource.h>
35 #include <memory-cgroup.h>
36 #include <sys/swap.h>
37 #include <linux/loop.h>
38 #include <fcntl.h>
39
40 #include "macro.h"
41 #include "module.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"
47 #include "notifier.h"
48 #include "procfs.h"
49 #include "cgroup.h"
50 #include "const.h"
51 #include "file-helper.h"
52 #include "proc-common.h"
53 #include "proc-main.h"
54 #include "util.h"
55 #include "losetup.h"
56 #include "init.h"
57
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)
69
70 #define EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN "early memory reclaim (done to retrieve resources used by daemons during system start-up)"
71
72 enum swap_thread_op {
73         SWAP_OP_ACTIVATE,
74         SWAP_OP_RECLAIM,
75         SWAP_OP_COMPACT,
76         SWAP_OP_END,
77 };
78
79 enum swap_reclaim_node {
80         SWAP_NODE_HARD_LIMIT,
81         SWAP_NODE_FORCE_RECLAIM,
82         SWAP_NODE_END,
83 };
84
85 struct swap_task {
86         struct proc_app_info *pai;
87         int size;
88 };
89
90 struct swap_safe_queue {
91         GQueue *queue;
92         pthread_mutex_t lock;
93 };
94
95 struct swap_thread_bundle {
96         struct swap_status_msg msg;
97         enum swap_thread_op op;
98 };
99
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;
106
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;
112
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;
118
119 static int swap_sort_func(const struct swap_module_ops *a,
120                                             const struct swap_module_ops *b)
121 {
122         return (a->priority - b->priority);
123 }
124
125 void swap_add(const struct swap_module_ops *ops)
126 {
127         _I("Swap module name: %s", ops->name);
128         swap_module = g_slist_insert_sorted(swap_module,
129                                         (gpointer)ops,
130                                         (GCompareFunc) swap_sort_func);
131 }
132
133 void swap_remove(const struct swap_module_ops *ops)
134 {
135         swap_module = g_slist_remove(swap_module, (gpointer)ops);
136 }
137
138 int do_mkswap(const char *device)
139 {
140         const char *argv[3] = { "/sbin/mkswap", NULL, NULL };
141
142         argv[1] = (char *) device;
143
144         return exec_cmd(ARRAY_SIZE(argv), argv);
145 }
146
147 int do_dd(char *input, char *output, unsigned int size, unsigned int count)
148 {
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;
152
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)
157                 return -ENOMEM;
158
159         argv[1] = if_arg;
160         argv[2] = of_arg;
161         argv[3] = bs_arg;
162         argv[4] = count_arg;
163
164         return exec_cmd(ARRAY_SIZE(argv), argv);
165 }
166
167 static const char *compact_reason_to_str(enum swap_compact_reason reason)
168 {
169         static const char *reasons_table[] = {"lowmem: critical", "lowmem: oom",
170                         "swap: zram full"};
171         if (reason >= SWAP_COMPACT_MEM_LEVEL_CRITICAL && reason < SWAP_COMPACT_RESASON_MAX)
172                 return reasons_table[reason];
173         return "";
174 }
175
176 static unsigned int swap_calculate_hard_limit_in_bytes(unsigned int mem_subcg_usage)
177 {
178         return (unsigned int)((float)mem_subcg_usage * swap_hard_limit_fraction);
179 }
180
181 static inline void swap_add_bundle(struct swap_thread_bundle *bundle)
182 {
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);
186 }
187
188 static int swap_move_to_cgroup_by_pid(enum cgroup_type type, pid_t pid)
189 {
190         int error;
191         int oom_score_adj;
192         int lowest_oom_score_adj;
193         struct proc_app_info *pai = find_app_info(pid);
194         GSList *iter_child = NULL;
195
196         error = proc_get_oom_score_adj(pid, &oom_score_adj);
197         if (error) {
198                 _E("Cannot get oom_score_adj of pid (%d)", pid);
199                 return RESOURCED_ERROR_FAIL;
200         }
201
202         lowest_oom_score_adj = cgroup_get_lowest_oom_score_adj(type);
203
204         if (oom_score_adj < lowest_oom_score_adj)
205                 oom_score_adj = lowest_oom_score_adj;
206
207         if (!pai)
208                 return proc_set_oom_score_adj(pid, oom_score_adj, pai);
209
210         proc_set_oom_score_adj(pai->main_pid, oom_score_adj, pai);
211
212         if (!pai->childs)
213                 return RESOURCED_ERROR_NONE;
214
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);
218         }
219
220         return error;
221 }
222
223
224 static int swap_use_hard_limit(char *memcg)
225 {
226         int ret;
227         unsigned int usage, memcg_limit;
228
229         ret = cgroup_read_node_uint32(memcg, MEMCG_USAGE, &usage);
230         if (ret != RESOURCED_ERROR_NONE)
231                 usage = 0;
232
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); 
238         else {
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);
242         }
243
244         if (ret != RESOURCED_ERROR_NONE)
245                 _E("Not able to set hard limit of %s memory cgroup", memcg);
246
247         return ret;
248 }
249
250 static int swap_use_force_reclaim(char *memcg)
251 {
252         int ret, len;
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;
257
258         /*
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.
264          */
265         len = strlen(memcg);
266         if (!strncmp(memcg, MEMCG_PATH, len))
267                 root_memcg = true;
268
269         do {
270                 /*
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.
276                  */
277                 if (root_memcg)
278                         ret = cgroup_read_node_uint32(memcg, MEMCG_USAGE, &usage);
279                 else
280                         ret = memcg_get_anon_usage(memcg, &usage);
281
282                 if (ret != RESOURCED_ERROR_NONE)
283                         usage = 0;
284
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;
290
291                 total_reclaim += nr_to_reclaim;
292                 ret = cgroup_write_node_uint32(memcg, MEMCG_FORCE_RECLAIM,
293                         nr_to_reclaim);
294                 if (ret != RESOURCED_ERROR_NONE)
295                         break; /* if we can't reclaim don't continue */
296
297                 try -= 1;
298         } while (try > 0);
299
300         _D("FORCE_RECLAIM tried %u pages from %s", total_reclaim, memcg);
301         return ret;
302 }
303
304 static int swap_start_reclaim(char *memcg)
305 {
306         int r;
307         int swappiness;
308
309         r = cgroup_read_node_int32(memcg, MEMCG_SWAPPINESS,
310                         &swappiness);
311         if (r)
312                 return r;
313
314         /*
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.
320          */
321         if (swappiness != SWAP_MEMCG_SWAPPINESS) {
322                 r = cgroup_write_node_uint32(memcg,
323                         MEMCG_SWAPPINESS, SWAP_MEMCG_SWAPPINESS);
324                 if (r) {
325                         _I("failed to write %s %d to %s the",
326                                 MEMCG_SWAPPINESS, SWAP_MEMCG_SWAPPINESS, memcg);
327                         return -errno;
328                 }
329         }
330         if (swap_node == SWAP_NODE_FORCE_RECLAIM)
331                 swap_use_force_reclaim(memcg);
332         else
333                 swap_use_hard_limit(memcg);
334
335         /*
336          * restore original swappiness value
337          */
338         if (current_swappiness != SWAP_MEMCG_SWAPPINESS) {
339                 r = cgroup_write_node_uint32(memcg,
340                         MEMCG_SWAPPINESS, current_swappiness);
341                 if (r) {
342                         _I("failed to write %s %d to %s the",
343                                 MEMCG_SWAPPINESS, SWAP_MEMCG_SWAPPINESS, memcg);
344                         return -errno;
345                 }
346         }
347         return 0;
348 }
349
350 static int swap_compact_in_module(void)
351 {
352         int r, fail = 0;
353         GSList *iter;
354         struct swap_module_ops *swaps;
355
356         gslist_for_each_item(iter, swap_module) {
357                 swaps = (struct swap_module_ops *)iter->data;
358
359                 if (!swaps->reclaim)
360                         continue;
361
362                 r = swaps->reclaim(swaps);
363                 if (r)
364                         fail = r;
365         }
366         return fail ? fail : 0;
367 }
368
369 //static int swap_reclaim_memcg(struct swap_status_msg msg)
370 static int swap_reclaim_memcg(char *path)
371 {
372         int r;
373
374         if (!path)
375                 return -EINVAL;
376
377         r = swap_compact_in_module();
378         if (r) {
379                 if (r == -ENOSPC) {
380                         /*
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.
384                          */
385                         r = cgroup_read_node_int32(path,
386                                 MEMCG_SWAPPINESS, &current_swappiness);
387                         if (r)
388                                 return r;
389
390                         r = cgroup_write_node_uint32(path,
391                                 MEMCG_SWAPPINESS, SWAP_MIN_SWAPPINESS);
392                 }
393                 return r;
394         }
395
396         return swap_start_reclaim(path);
397 }
398
399 static int gen_urandom_string(char *buf, size_t len)
400 {
401         _cleanup_close_ int fd = -1;
402         ssize_t l;
403
404         fd = open("/dev/urandom", O_RDONLY);
405         if (fd < 0)
406                 return -errno;
407
408         l = read(fd, buf, len);
409         if (l < 0)
410                 return -errno;
411
412         return 0;
413 }
414
415 static int swap_losetup(struct swap_module_ops *swap,
416                                 char *crypt_type,
417                                 char *swapfile)
418 {
419         char swapdevice[MAX_NAME_LENGTH];
420         char passwd[LO_KEY_SIZE] = "";
421         int r;
422
423         if (!is_empty(crypt_type)) {
424                 r = gen_urandom_string(passwd, LO_KEY_SIZE);
425                 if (r < 0) {
426                         _E("Failed to generate random passwd: %m");
427                         return r;
428                 }
429         }
430
431         r = find_loop_device(swapfile, swapdevice);
432         if (r < 0) {
433                 if (r == -EEXIST) {
434                         _I("'%s' is already setuped to '%s'", swapfile, swapdevice);
435                         goto finish;
436                 } else
437                         _E("Failed to find available loop device.");
438                 return r;
439         }
440
441         r = losetup(swapdevice, swapfile, 0, 0,
442                     crypt_type, passwd, false);
443
444         if (r < 0) {
445                 _E("Failed to setup loop: %d", r);
446                 return r;
447         }
448
449 finish:
450         swap->path = strdup(swapdevice);
451         if (!swap->path)
452                 return -ENOMEM;
453         return r;
454 }
455
456 int swap_set_file(char *filename, struct swap_module_ops *swap, char *crypt_type)
457 {
458         int r;
459
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);
464                 if (r > 0) {
465                         _E("Failed to create swap file(%s), exit code: %d",
466                                         filename, r);
467                         return -1;
468                 } else if (r < 0) {
469                         _E("Failed to create swap file(%s): %d",
470                                         filename, r);
471                         return r;
472                 }
473                 _I("SwapFile is created: %s", filename);
474         } else if (r != 0) {
475                 _E("Failed to access swap file(%s): %m", filename);
476                 return -errno;
477         }
478
479         r = swap_losetup(swap, crypt_type, filename);
480         if (r < 0)
481                 return r;
482
483         if (!swap->path)
484                 return -ENOENT;
485
486         r = do_mkswap(swap->path);
487         if (r > 0) {
488                 _E("Failed to make swap device(%s), exit code: %d", swap->path, r);
489                 return -EBUSY;
490         } else if (r < 0) {
491                 _E("Failed to make swap device(%s): %d", swap->path, r);
492         }
493         return r;
494 }
495
496 bool swap_is_on(const char *name)
497 {
498         _cleanup_proc_swaps_free_ struct proc_swaps **swaps = NULL;
499         int n, i;
500
501         n = proc_get_swaps(&swaps);
502         if (n <= 0 || !swaps)
503                 return false;
504
505         for (i = 0; i < n; i++) {
506                 if (streq(swaps[i]->filename, name))
507                         return true;
508         }
509
510         return false;
511 }
512
513 static void swap_activate_in_module(void)
514 {
515         int r;
516         GSList *iter;
517         struct swap_module_ops *swaps;
518         static bool early_reclaim;
519
520         r = cgroup_read_node_int32(MEMCG_PATH,
521                 MEMCG_SWAPPINESS, &current_swappiness);
522         if (r)
523                 return;
524
525         if (swap_get_state() == SWAP_ON)
526                 return;
527
528         gslist_for_each_item(iter, swap_module) {
529                 int flags = SWAP_FLAG_DISCARD;
530
531                 swaps = (struct swap_module_ops *)iter->data;
532
533                 if (!swaps->activate)
534                         continue;
535
536                 r = swaps->activate(swaps);
537                 if (r != 0) {
538                         if (r != -EEXIST) {
539                                 _E("%s activate failed", swaps->name);
540                                 swap_remove(swaps);
541                         }
542                         swap_set_state(SWAP_ON);
543                         continue;
544                 }
545
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;
550                 }
551 #endif
552                 r = swapon(swaps->path, flags);
553                 if (r < 0) {
554                         _E("Failed to turn on swap device(%s): %m", swaps->path);
555                         continue;
556                 }
557                 _I("swap device(%s) was turned on: %s", swaps->name, swaps->path);
558
559                 /*
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.
565                  */
566                 if (!early_reclaim) {
567                         int try = arg_swap_at_boot_maxtry;
568                         unsigned int usage, prev_usage = 0;
569
570                         r = cgroup_read_node_uint32(MEMCG_PATH,
571                                 MEMCG_SWAP_USAGE, &prev_usage);
572                         if (r)
573                                 prev_usage = UINT_MAX;
574
575                         for (;;) {
576                                 try--;
577                                 swap_start_reclaim(MEMCG_PATH);
578
579                                 r = cgroup_read_node_uint32(MEMCG_PATH,
580                                 MEMCG_SWAP_USAGE, &usage);
581                                 if (r) {
582                                         _E("Early reclaimed is aborted");
583                                         break;
584                                 }
585
586                                 /*
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
590                                  * reclaim once.
591                                  */
592                                 if (!try || prev_usage - usage < arg_swap_at_boot_threshold)
593                                         break;
594
595                                 prev_usage = usage;
596                                 /*
597                                  * To prevent continuous reclaim to harm entire system,
598                                  * having relaxation on each reclaim
599                                  */
600                                 sleep(arg_swap_at_boot_interval);
601                         }
602                         early_reclaim = true;
603                 }
604
605                 swap_set_state(SWAP_ON);
606         }
607 }
608
609 static void *swap_thread_main(void * data)
610 {
611         int is_empty;
612         struct swap_thread_bundle *bundle;
613
614         setpriority(PRIO_PROCESS, 0, SWAP_PRIORITY);
615
616         while (1) {
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);
622                 if (is_empty) {
623                         /* The queue is empty, wait for thread signal */
624                         pthread_cond_wait(&swap_cond, &swap_mutex);
625                 }
626
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);
631
632                 if (!bundle)
633                         goto unlock_out;
634
635                 switch (bundle->op) {
636                 /* Swap activation operttion: mkswap, swapon etc. */
637                 case SWAP_OP_ACTIVATE:
638                         swap_activate_in_module();
639                         break;
640                 /* Swap reclaim opertation: move to swap, force_reclaim */
641                 case SWAP_OP_RECLAIM:
642                         swap_reclaim_memcg(bundle->msg.path);
643                         break;
644                 /* Swap compact operation of zsmalloc. */
645                 case SWAP_OP_COMPACT:
646                         swap_compact_in_module();
647                         break;
648                 /* Move inactive procesess to swap, and reclaim after that. */
649                 case SWAP_OP_END:
650                 default:
651                         _D("wrong swap thread operation selected");
652                 }
653
654                 free(bundle);
655 unlock_out:
656                 pthread_mutex_unlock(&swap_mutex);
657         }
658         return NULL;
659 }
660
661 static int swap_communicate_thread(struct swap_thread_bundle *bundle)
662 {
663         int ret;
664
665         if (!bundle)
666                 return RESOURCED_ERROR_NO_DATA;
667
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);
671         if (ret == 0) {
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;
679         }
680
681         _E("pthread_mutex_trylock fail: %d, errno: %d", ret, errno);
682         return RESOURCED_ERROR_FAIL;
683 }
684
685 static int swap_start_handler(void *data)
686 {
687         int ret;
688         struct swap_thread_bundle *bundle;
689
690         if (!data) {
691                 _E("data is NULL");
692                 return RESOURCED_ERROR_NO_DATA;
693         }
694
695         bundle = malloc(sizeof(struct swap_thread_bundle));
696         if (!bundle)
697                 return RESOURCED_ERROR_OUT_OF_MEMORY;
698
699         bundle->op = SWAP_OP_RECLAIM;
700         memcpy(bundle->msg.path, data, sizeof(struct swap_status_msg));
701         ret = swap_communicate_thread(bundle);
702         return ret;
703 }
704
705 static int swap_internal_bundle_sender(enum swap_thread_op operation)
706 {
707         int ret;
708         struct swap_thread_bundle *bundle;
709
710         bundle = malloc(sizeof(struct swap_thread_bundle));
711         if (!bundle)
712                 return RESOURCED_ERROR_OUT_OF_MEMORY;
713         bundle->op = operation;
714         ret = swap_communicate_thread(bundle);
715         return ret;
716 }
717
718 static int swap_activate_handler(void *data)
719 {
720         return swap_internal_bundle_sender(SWAP_OP_ACTIVATE);
721 }
722
723 static gboolean swap_activate_timer_cb(gpointer data)
724 {
725         _I("Starting an " EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN);
726         swap_activating_timer = NULL;
727         swap_internal_bundle_sender(SWAP_OP_ACTIVATE);
728         return false;
729 }
730
731 static int swap_booting_done(void *data)
732 {
733         if (!arg_swap_at_boot) {
734                 _D(EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN " is disabled");
735                 return RESOURCED_ERROR_NONE;
736         }
737
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;
745         }
746
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);
751
752         return RESOURCED_ERROR_NONE;
753 }
754
755 static int swap_compact_handler(void *data)
756 {
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);
760 }
761
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)
767 {
768         int ret;
769         struct memcg_info *mi = (struct memcg_info *)data;
770
771         if (!mi) {
772                 _E("memory cgroup information is NULL");
773                 return RESOURCED_ERROR_INVALID_PARAMETER;
774         }
775
776         if (swap_node == SWAP_NODE_FORCE_RECLAIM)
777                 return RESOURCED_ERROR_NONE;
778
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);
783         else
784                 _D("changed hard limit of %s cgroup to -1", mi->name);
785
786         return ret;
787 }
788
789 static void swap_start_pid_dbus_signal_handler(GVariant *params)
790 {
791         pid_t pid;
792         struct cgroup *cgroup_swap;
793 //      struct swap_status_msg ss_msg;
794
795         do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &pid);
796         if (pid <= 0) {
797                 _D("Invalid parameter");
798                 return;
799         }
800
801         cgroup_swap = get_cgroup_tree(CGROUP_LOW);
802         if (!cgroup_swap)
803                 return;
804         swap_move_to_cgroup_by_pid(CGROUP_LOW, pid);
805 /*      ss_msg.pid = 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);
810 }
811
812
813 static const struct d_bus_signal dbus_signals[] = {
814         /* RESOURCED DBUS */
815         {RESOURCED_PATH_SWAP, RESOURCED_INTERFACE_SWAP,
816             SIGNAL_NAME_SWAP_START_PID, swap_start_pid_dbus_signal_handler, NULL},
817 };
818
819 static void swap_dbus_init(void)
820 {
821         d_bus_register_signals(dbus_signals, ARRAY_SIZE(dbus_signals));
822 }
823
824 static int config_parse_swap_types(
825                                   const char *rvalue,
826                                   void *data)
827 {
828         enum swap_type *type = data;
829         char *word, *state;
830         size_t l;
831
832         if (is_empty(rvalue))
833                 return 0;
834
835         *type = 0;
836
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;
844                 else
845                         return -EINVAL;
846         }
847
848         return 0;
849 }
850
851 static void print_swap_conf(void)
852 {
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);
856
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);
861         }
862 }
863
864 static int swap_parse_config_file(void)
865 {
866         int r = RESOURCED_ERROR_NONE;
867         GSList *iter;
868         struct swap_module_ops *swaps;
869         struct swap_conf *swap_conf = get_swap_conf();
870         if (!swap_conf) {
871                 _E("Swap configuration should not be NULL");
872                 return RESOURCED_ERROR_FAIL;
873         }
874
875         arg_swap_enable = swap_conf->enable;
876         if (arg_swap_enable == false)
877                 goto free_swap_conf;
878
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;
883         }
884
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]); 
890         }
891
892         gslist_for_each_item(iter, swap_module) {
893                 swaps = (struct swap_module_ops *)iter->data;
894
895                 if (!swaps->conf)
896                         continue;
897
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);
904         }
905
906 free_swap_conf:
907         free_swap_conf();
908         print_swap_conf();
909
910         return r;
911 }
912
913 /*static int swap_parse_config_file(void)
914 {
915         const ConfigTableItem items[] = {
916                 { "SWAP",       "Enable",               config_parse_bool,
917                         0,      &arg_swap_enable        },
918                 { "SWAP",       "Type",                 config_parse_swap_types,
919                         0,      &arg_swap_type  },
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 },
930                 { NULL,         NULL,                   NULL,
931                         0,      NULL    }
932         };
933
934         int r;
935
936         r = config_parse_new(SWAP_CONF_FILE, (void*) items);
937         if (r < 0) {
938                 _E("Failed to parse configuration file: %d", r);
939                 return r;
940         }
941
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);
944                 return -EINVAL;
945         }
946
947         return 0;
948 }*/
949
950 static int swap_thread_create(void)
951 {
952         int ret = 0;
953         pthread_t pth;
954
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();
959
960         if (!swap_thread_queue.queue) {
961                 _E("fail to allocate swap thread queue");
962                 return RESOURCED_ERROR_FAIL;
963         }
964
965         ret = pthread_create(&pth, NULL, &swap_thread_main, (void *)NULL);
966         if (ret) {
967                 _E("pthread creation for swap_thread failed\n");
968                 return ret;
969         } else {
970                 pthread_detach(pth);
971         }
972
973         return RESOURCED_ERROR_NONE;
974 }
975
976 static int swap_init(void)
977 {
978         int r;
979         GSList *iter, *next;
980         struct swap_module_ops *swaps = NULL;
981         int swap_pri = SWAP_PRI_DEFAULT;
982
983         r = swap_parse_config_file();
984         if (r < 0)
985                 return r;
986
987         if (!arg_swap_enable)
988                 return -ENODEV;
989
990         memcg_write_optimizer_params();
991
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)) {
995                         swap_remove(swaps);
996                         continue;
997                 }
998
999                 if (!swaps->init)
1000                         continue;
1001
1002                 /*
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.
1007                  */
1008                 if (swap_pri == SWAP_PRI_DISABLE) {
1009                         swap_remove(swaps);
1010                         _E("don't allow other %s module", swaps->name);
1011                         continue;
1012                 }
1013                 swap_pri = swaps->priority;
1014
1015                 r = swaps->init(swaps);
1016                 if (r != 0) {
1017                         _E("%s module init failed", swaps->name);
1018                         swap_remove(swaps);
1019                 }
1020         }
1021
1022         r = swap_thread_create();
1023         if (r) {
1024                 _E("swap thread create failed");
1025                 return r;
1026         }
1027         swap_dbus_init();
1028
1029         return r;
1030 }
1031
1032 static int swap_check_node(char *path)
1033 {
1034         _cleanup_fclose_ FILE *fp = NULL;
1035
1036         fp = fopen(path, "w");
1037         if (fp == NULL) {
1038                 _E("%s open failed", path);
1039                 return RESOURCED_ERROR_NO_DATA;
1040         }
1041         return RESOURCED_ERROR_NONE;
1042 }
1043
1044 static int resourced_swap_check_runtime_support(void *data)
1045 {
1046         int r;
1047         uint32_t usage;
1048
1049         /*
1050          * Check whether CONFIG_SWAP is enabled in kernel.
1051          */
1052         if (access("/proc/swaps", R_OK) != 0)
1053                 return -ENOENT;
1054
1055         /*
1056          * Check whether kernel is supporting MEMCG_SWAP.
1057          */
1058         r = cgroup_read_node_uint32(MEMCG_PATH,
1059                                 MEMCG_SWAP_USAGE, &usage);
1060         if (r)
1061                 return -ENOENT;
1062
1063         return r;
1064 }
1065
1066 /*
1067  * Quote from: kernel Documentation/cgroups/memory.txt
1068  *
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.
1073  *
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.
1087  * quote end.
1088  *
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.
1096  */
1097 static void resourced_swap_change_memcg_settings(enum cgroup_type type)
1098 {
1099         int ret;
1100         struct cgroup *cgroup_swap = NULL;
1101         char buf[MAX_PATH_LENGTH];
1102
1103         cgroup_swap = get_cgroup_tree(type);
1104         if (!cgroup_swap)
1105                 return;
1106
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);
1113         } else {
1114                 swap_node = SWAP_NODE_HARD_LIMIT;
1115                 _I("use %s node for swapping memory", MEMCG_LIMIT_BYTE);
1116         }
1117 }
1118
1119 static int resourced_swap_init(void *data)
1120 {
1121         int ret;
1122
1123         resourced_swap_change_memcg_settings(CGROUP_LOW);
1124         swap_set_state(SWAP_OFF);
1125
1126         ret = swap_init();
1127         if (ret != RESOURCED_ERROR_NONE)
1128                 return ret;
1129
1130         if (!resourced_restarted()) {
1131                 register_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, swap_booting_done);
1132         } else {
1133                 _I("Assuming swap is already set up. To reconfigure, reboot the device.");
1134         }
1135
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);
1140
1141         return ret;
1142 }
1143
1144 static int resourced_swap_finalize(void *data)
1145 {
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);
1151
1152         g_queue_free(swap_thread_queue.queue);
1153
1154         return RESOURCED_ERROR_NONE;
1155 }
1156
1157 static struct module_ops swap_modules_ops = {
1158         .priority = MODULE_PRIORITY_NORMAL,
1159         .name = "swap",
1160         .init = resourced_swap_init,
1161         .exit = resourced_swap_finalize,
1162         .check_runtime_support = resourced_swap_check_runtime_support,
1163 };
1164
1165 MODULE_REGISTER(&swap_modules_ops)