Add unit(in variable) & fix bugs
[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(20)
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_sec = 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 long arg_swap_at_boot_threshold_bytes = SWAP_EARLYRECLAIM_THRESHOLD_DEFAULT;
116 static int arg_swap_at_boot_maxtry = SWAP_EARLYRECLAIM_MAXTRY;
117 static int arg_swap_at_boot_interval_sec = 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         swap_module = g_slist_insert_sorted(swap_module,
128                                         (gpointer)ops,
129                                         (GCompareFunc) swap_sort_func);
130 }
131
132 void swap_remove(const struct swap_module_ops *ops)
133 {
134         swap_module = g_slist_remove(swap_module, (gpointer)ops);
135 }
136
137 int do_mkswap(const char *device)
138 {
139         const char *argv[3] = { "/sbin/mkswap", NULL, NULL };
140
141         argv[1] = (char *) device;
142
143         return exec_cmd(ARRAY_SIZE(argv), argv);
144 }
145
146 int do_dd(char *input, char *output, unsigned int size, unsigned int count)
147 {
148         const char *argv[6] = { "/bin/dd", NULL, NULL, NULL, NULL, NULL };
149         _cleanup_free_ char *if_arg = NULL, *of_arg = NULL;
150         _cleanup_free_ char *bs_arg = NULL, *count_arg = NULL;
151
152         if (asprintf(&if_arg, "if=%s", input) < 0 ||
153             asprintf(&of_arg, "of=%s", output) < 0 ||
154             asprintf(&bs_arg, "bs=%u", size) < 0 ||
155             asprintf(&count_arg, "count=%u", count) < 0)
156                 return -ENOMEM;
157
158         argv[1] = if_arg;
159         argv[2] = of_arg;
160         argv[3] = bs_arg;
161         argv[4] = count_arg;
162
163         return exec_cmd(ARRAY_SIZE(argv), argv);
164 }
165
166 static const char *compact_reason_to_str(enum swap_compact_reason reason)
167 {
168         static const char *reasons_table[] = {"lowmem: critical", "lowmem: oom",
169                         "swap: zram full"};
170         if (reason >= SWAP_COMPACT_MEM_LEVEL_CRITICAL && reason < SWAP_COMPACT_RESASON_MAX)
171                 return reasons_table[reason];
172         return "";
173 }
174
175 static inline unsigned long long swap_calculate_hard_limit_in_bytes(unsigned long long mem_subcg_usage_bytes)
176 {
177         return (unsigned long long)((double)mem_subcg_usage_bytes * swap_hard_limit_fraction);
178 }
179
180 static inline void swap_add_bundle(struct swap_thread_bundle *bundle)
181 {
182         pthread_mutex_lock(&swap_thread_queue.lock);
183         g_queue_push_tail(swap_thread_queue.queue, bundle);
184         pthread_mutex_unlock(&swap_thread_queue.lock);
185 }
186
187 static int swap_move_to_cgroup_by_pid(enum cgroup_type type, pid_t pid)
188 {
189         int error;
190         int oom_score_adj;
191         int lowest_oom_score_adj;
192         struct proc_app_info *pai = find_app_info(pid);
193         GSList *iter_child = NULL;
194
195         error = proc_get_oom_score_adj(pid, &oom_score_adj);
196         if (error) {
197                 _E("Cannot get oom_score_adj of pid (%d)", pid);
198                 return RESOURCED_ERROR_FAIL;
199         }
200
201         lowest_oom_score_adj = cgroup_get_lowest_oom_score_adj(type);
202
203         if (oom_score_adj < lowest_oom_score_adj)
204                 oom_score_adj = lowest_oom_score_adj;
205
206         if (!pai)
207                 return proc_set_oom_score_adj(pid, oom_score_adj, pai);
208
209         proc_set_oom_score_adj(pai->main_pid, oom_score_adj, pai);
210
211         if (!pai->childs)
212                 return RESOURCED_ERROR_NONE;
213
214         gslist_for_each_item(iter_child, pai->childs) {
215                 pid_t child = GPOINTER_TO_PID(iter_child->data);
216                 error = proc_set_oom_score_adj(child, oom_score_adj, pai);
217         }
218
219         return error;
220 }
221
222 static int swap_use_hard_limit(char *memcg)
223 {
224         int ret;
225         unsigned long long usage_bytes, memcg_limit_bytes;
226
227         ret = cgroup_read_node_ulonglong(memcg, MEMCG_USAGE, &usage_bytes);
228         if (ret != RESOURCED_ERROR_NONE)
229                 usage_bytes = 0;
230
231         memcg_limit_bytes = swap_calculate_hard_limit_in_bytes(usage_bytes);
232         _D("[SWAP] Swap request: %s cgroup usage is %llu bytes, hard limit set to %llu bytes (hard limit fraction %f)",
233                         memcg, usage_bytes, memcg_limit_bytes, swap_hard_limit_fraction);
234         if (memcg_limit_bytes != 0)
235                 ret = check_oom_and_set_limit(memcg, memcg_limit_bytes);
236         else {
237                 /* If the group is empty don't set the limit to enable adding processes. */
238                 ret = cgroup_write_node_int32(memcg, MEMCG_SWAP_LIMIT_BYTE, -1);
239                 ret = cgroup_write_node_int32(memcg, MEMCG_LIMIT_BYTE, -1);
240         }
241
242         if (ret != RESOURCED_ERROR_NONE)
243                 _E("Not able to set hard limit of %s memory cgroup", memcg);
244
245         return ret;
246 }
247
248 static int swap_use_force_reclaim(char *memcg)
249 {
250         int ret, len;
251         unsigned long long usage_bytes;
252         int try = SWAP_FORCE_RECLAIM_NUM_MAX;
253         unsigned int nr_to_reclaim;
254         unsigned int total_reclaim_pages = 0;
255         bool root_memcg = false;
256
257         /*
258          * In case of MEMCG_PATH,
259          * it is no necessary to check anon usage of memcg
260          * because it doesn't include all memory usage.
261          * But instead, try to swap memory as much as possible.
262          * It will be happend only once after booting done.
263          */
264         len = strlen(memcg);
265         if (!strncmp(memcg, MEMCG_PATH, len))
266                 root_memcg = true;
267
268         do {
269                 /*
270                  * Currently, we only move only anonymous pages to swap memcg by
271                  * setting move_charge_at_immigrate as 0. However, there might
272                  * be a little of inactive file pages in swap memcg.
273                  * For this reason it's better to use '.stat' and calculate only
274                  * anoynymous memory usage.
275                  */
276                 if (root_memcg)
277                         ret = cgroup_read_node_ulonglong(memcg, MEMCG_USAGE, &usage_bytes);
278                 else
279                         ret = memcg_get_anon_usage(memcg, &usage_bytes);
280
281
282                 if (ret != RESOURCED_ERROR_NONE)
283                         usage_bytes = 0;
284
285                 nr_to_reclaim = BYTE_TO_PAGE(usage_bytes);
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_pages += 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("[SWAP] FORCE_RECLAIM tried %u pages from %s", total_reclaim_pages, 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(char *path)
370 {
371         int r;
372
373         if (!path)
374                 return -EINVAL;
375
376         r = swap_compact_in_module();
377         if (r) {
378                 if (r == -ENOSPC) {
379                         /*
380                          * If swap space is not enough, swap module will trigger the proactive LMK.
381                          * While saving swap space again,
382                          * swap will be blocked with minimum swappiness.
383                          */
384                         r = cgroup_read_node_int32(path,
385                                 MEMCG_SWAPPINESS, &current_swappiness);
386                         if (r)
387                                 return r;
388
389                         r = cgroup_write_node_uint32(path,
390                                 MEMCG_SWAPPINESS, SWAP_MIN_SWAPPINESS);
391                 }
392                 return r;
393         }
394
395         return swap_start_reclaim(path);
396 }
397
398 static int gen_urandom_string(char *buf, size_t len)
399 {
400         _cleanup_close_ int fd = -1;
401         ssize_t l;
402
403         fd = open("/dev/urandom", O_RDONLY);
404         if (fd < 0)
405                 return -errno;
406
407         l = read(fd, buf, len);
408         if (l < 0)
409                 return -errno;
410
411         return 0;
412 }
413
414 static int swap_losetup(struct swap_module_ops *swap,
415                                 char *crypt_type,
416                                 char *swapfile)
417 {
418         char swapdevice[MAX_NAME_LENGTH];
419         char passwd[LO_KEY_SIZE] = "";
420         int r;
421
422         if (!is_empty(crypt_type)) {
423                 r = gen_urandom_string(passwd, LO_KEY_SIZE);
424                 if (r < 0) {
425                         _E("Failed to generate random passwd: %m");
426                         return r;
427                 }
428         }
429
430         r = find_loop_device(swapfile, swapdevice);
431         if (r < 0) {
432                 if (r == -EEXIST) {
433                         _I("'%s' is already setuped to '%s'", swapfile, swapdevice);
434                         goto finish;
435                 } else
436                         _E("Failed to find available loop device.");
437                 return r;
438         }
439
440         r = losetup(swapdevice, swapfile, 0, 0,
441                     crypt_type, passwd, false);
442
443         if (r < 0) {
444                 _E("Failed to setup loop: %d", r);
445                 return r;
446         }
447
448 finish:
449         swap->path = strdup(swapdevice);
450         if (!swap->path)
451                 return -ENOMEM;
452         return r;
453 }
454
455 int swap_set_file(char *filename, struct swap_module_ops *swap, char *crypt_type)
456 {
457         int r;
458
459         r = access(filename, F_OK);
460         if (r < 0 && errno == ENOENT) {
461                 r = do_dd("/dev/zero", filename, PAGE_SIZE,
462                           KBYTE_TO_BYTE(swap->k_size) >> PAGE_SHIFT);
463                 if (r > 0) {
464                         _E("Failed to create swap file(%s), exit code: %d",
465                                         filename, r);
466                         return -1;
467                 } else if (r < 0) {
468                         _E("Failed to create swap file(%s): %d",
469                                         filename, r);
470                         return r;
471                 }
472                 _I("SwapFile is created: %s", filename);
473         } else if (r != 0) {
474                 _E("Failed to access swap file(%s): %m", filename);
475                 return -errno;
476         }
477
478         r = swap_losetup(swap, crypt_type, filename);
479         if (r < 0)
480                 return r;
481
482         if (!swap->path)
483                 return -ENOENT;
484
485         r = do_mkswap(swap->path);
486         if (r > 0) {
487                 _E("Failed to make swap device(%s), exit code: %d", swap->path, r);
488                 return -EBUSY;
489         } else if (r < 0) {
490                 _E("Failed to make swap device(%s): %d", swap->path, r);
491         }
492         return r;
493 }
494
495 bool swap_is_on(const char *name)
496 {
497         _cleanup_proc_swaps_free_ struct proc_swaps **swaps = NULL;
498         int n, i;
499
500         n = proc_get_swaps(&swaps);
501         if (n <= 0 || !swaps)
502                 return false;
503
504         for (i = 0; i < n; i++) {
505                 if (streq(swaps[i]->filename, name))
506                         return true;
507         }
508
509         return false;
510 }
511
512 static void swap_activate_in_module(void)
513 {
514         int r;
515         GSList *iter;
516         struct swap_module_ops *swaps;
517         static bool early_reclaim;
518
519         r = cgroup_read_node_int32(MEMCG_PATH,
520                 MEMCG_SWAPPINESS, &current_swappiness);
521         if (r)
522                 return;
523
524         if (swap_get_state() == SWAP_ON)
525                 return;
526
527         gslist_for_each_item(iter, swap_module) {
528                 int flags = SWAP_FLAG_DISCARD;
529
530                 swaps = (struct swap_module_ops *)iter->data;
531
532                 if (!swaps->activate)
533                         continue;
534
535                 r = swaps->activate(swaps);
536                 if (r != 0) {
537                         if (r != -EEXIST) {
538                                 _E("%s activate failed", swaps->name);
539                                 swap_remove(swaps);
540                         }
541                         swap_set_state(SWAP_ON);
542                         continue;
543                 }
544
545 #ifdef SWAP_FLAG_PREFER
546                 if (swaps->priority >= 0) {
547                         flags |= SWAP_FLAG_PREFER |
548                                 (swaps->priority & SWAP_FLAG_PRIO_MASK) << SWAP_FLAG_PRIO_SHIFT;
549                 }
550 #endif
551                 r = swapon(swaps->path, flags);
552                 if (r < 0) {
553                         _E("Failed to turn on swap device(%s): %m", swaps->path);
554                         continue;
555                 }
556                 _I("swap device(%s) was turned on: %s", swaps->name, swaps->path);
557
558                 /*
559                  * Most system daemons use much memory for intializing own process.
560                  * but there is little change to reuse it while running.
561                  * So early reclaiming moves unused system memory to swap device.
562                  * If multiple swap devices are available,
563                  * first swap with the lowest priority will start reclaiming.
564                  */
565                 if (!early_reclaim) {
566                         int try = arg_swap_at_boot_maxtry;
567                         unsigned long long usage_bytes, prev_usage_bytes = 0;
568
569                         r = cgroup_read_node_ulonglong(MEMCG_PATH,
570                                 MEMCG_SWAP_USAGE, &prev_usage_bytes);
571                         if (r)
572                                 prev_usage_bytes = ULONG_MAX;
573
574                         for (;;) {
575                                 try--;
576                                 swap_start_reclaim(MEMCG_PATH);
577
578                                 r = cgroup_read_node_ulonglong(MEMCG_PATH,
579                                                 MEMCG_SWAP_USAGE, &usage_bytes);
580                                 if (r) {
581                                         _E("Early reclaimed is aborted");
582                                         break;
583                                 }
584
585                                 /*
586                                  * Continue to reclaim memory at boot time until
587                                  * there is no more saving or trial reaches maximum.
588                                  * The default threshold is very large, so it may
589                                  * reclaim once.
590                                  */
591                                 if (!try || prev_usage_bytes - usage_bytes < arg_swap_at_boot_threshold_bytes)
592                                         break;
593
594                                 prev_usage_bytes = usage_bytes;
595                                 /*
596                                  * To prevent continuous reclaim to harm entire system,
597                                  * having relaxation on each reclaim
598                                  */
599                                 sleep(arg_swap_at_boot_interval_sec);
600                         }
601                         early_reclaim = true;
602                 }
603
604                 swap_set_state(SWAP_ON);
605         }
606 }
607
608 static void *swap_thread_main(void * data)
609 {
610         int is_empty;
611         struct swap_thread_bundle *bundle;
612
613         setpriority(PRIO_PROCESS, 0, SWAP_PRIORITY);
614
615         while (1) {
616                 pthread_mutex_lock(&swap_mutex);
617                 /* THREAD: WAIT FOR START */
618                 pthread_mutex_lock(&swap_thread_queue.lock);
619                 is_empty = g_queue_is_empty(swap_thread_queue.queue);
620                 pthread_mutex_unlock(&swap_thread_queue.lock);
621                 if (is_empty) {
622                         /* The queue is empty, wait for thread signal */
623                         pthread_cond_wait(&swap_cond, &swap_mutex);
624                 }
625
626                 /* We're in swap thread, now it's time to dispatch bundles */
627                 pthread_mutex_lock(&swap_thread_queue.lock);
628                 bundle = g_queue_pop_head(swap_thread_queue.queue);
629                 pthread_mutex_unlock(&swap_thread_queue.lock);
630
631                 if (!bundle)
632                         goto unlock_out;
633
634                 switch (bundle->op) {
635                 /* Swap activation operttion: mkswap, swapon etc. */
636                 case SWAP_OP_ACTIVATE:
637                         swap_activate_in_module();
638                         break;
639                 /* Swap reclaim opertation: move to swap, force_reclaim */
640                 case SWAP_OP_RECLAIM:
641                         swap_reclaim_memcg(bundle->msg.path);
642                         break;
643                 /* Swap compact operation of zsmalloc. */
644                 case SWAP_OP_COMPACT:
645                         swap_compact_in_module();
646                         break;
647                 /* Move inactive procesess to swap, and reclaim after that. */
648                 case SWAP_OP_END:
649                 default:
650                         _D("wrong swap thread operation selected");
651                 }
652
653                 free(bundle);
654 unlock_out:
655                 pthread_mutex_unlock(&swap_mutex);
656         }
657         return NULL;
658 }
659
660 static int swap_communicate_thread(struct swap_thread_bundle *bundle)
661 {
662         int ret;
663
664         if (!bundle)
665                 return RESOURCED_ERROR_NO_DATA;
666
667         swap_add_bundle(bundle);
668         /* Try to signal swap thread, that there is some work to do */
669         ret = pthread_mutex_trylock(&swap_mutex);
670         if (ret == 0) {
671                 pthread_cond_signal(&swap_cond);
672                 pthread_mutex_unlock(&swap_mutex);
673                 _I("send signal to swap thread");
674                 return RESOURCED_ERROR_NONE;
675         } else if (ret == EBUSY) {
676                 _D("swap thread already active");
677                 return RESOURCED_ERROR_NONE;
678         }
679
680         _E("pthread_mutex_trylock fail: %d, errno: %d", ret, errno);
681         return RESOURCED_ERROR_FAIL;
682 }
683
684 static int swap_start_handler(void *data)
685 {
686         int ret;
687         struct swap_thread_bundle *bundle;
688
689         if (!data) {
690                 _E("data is NULL");
691                 return RESOURCED_ERROR_NO_DATA;
692         }
693
694         bundle = malloc(sizeof(struct swap_thread_bundle));
695         if (!bundle)
696                 return RESOURCED_ERROR_OUT_OF_MEMORY;
697
698         bundle->op = SWAP_OP_RECLAIM;
699         memcpy(bundle->msg.path, data, sizeof(struct swap_status_msg));
700         ret = swap_communicate_thread(bundle);
701         return ret;
702 }
703
704 static int swap_internal_bundle_sender(enum swap_thread_op operation)
705 {
706         int ret;
707         struct swap_thread_bundle *bundle;
708
709         bundle = malloc(sizeof(struct swap_thread_bundle));
710         if (!bundle)
711                 return RESOURCED_ERROR_OUT_OF_MEMORY;
712         bundle->op = operation;
713         ret = swap_communicate_thread(bundle);
714         return ret;
715 }
716
717 static int swap_activate_handler(void *data)
718 {
719         return swap_internal_bundle_sender(SWAP_OP_ACTIVATE);
720 }
721
722 static gboolean swap_activate_timer_cb(gpointer data)
723 {
724         _I("Starting an " EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN);
725         swap_activating_timer = NULL;
726         swap_internal_bundle_sender(SWAP_OP_ACTIVATE);
727         return false;
728 }
729
730 static int swap_booting_done(void *data)
731 {
732         if (!arg_swap_at_boot) {
733                 _D(EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN " is disabled");
734                 return RESOURCED_ERROR_NONE;
735         }
736
737         /* No need to involve the timer mechanism when the delay is 0,
738          * partially to keep things simple but primarily because it can
739          * introduce an artificial delay since the timer is ran async
740          * in another thread. */
741         if (arg_timer_swap_at_boot_sec == 0) {
742                 swap_activate_timer_cb(NULL);
743                 return RESOURCED_ERROR_NONE;
744         }
745
746         _D("booting done; starting up a timer to perform an " EARLYRECLAIM_WITH_AN_EXPLANATION_FOR_LAYMEN " %ds from now", arg_timer_swap_at_boot_sec);
747         swap_activating_timer = g_timeout_source_new_seconds((guint) arg_timer_swap_at_boot_sec);
748         g_source_set_callback(swap_activating_timer, swap_activate_timer_cb, NULL, NULL);
749         g_source_attach(swap_activating_timer, NULL);
750
751         return RESOURCED_ERROR_NONE;
752 }
753
754 static int swap_compact_handler(void *data)
755 {
756         _I("compaction request. Reason: %s",
757                         compact_reason_to_str((enum swap_compact_reason)data));
758         return swap_internal_bundle_sender(SWAP_OP_COMPACT);
759 }
760
761 /* This function is callback function for the notifier RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT.
762  * This notifier is notified from normal_act function of vmpressure module whenever the
763  * memory state changes to normal.
764  * This function resets the hard limit of the swap subcgroup to -1 (unlimited) */
765 static int swap_cgroup_reset_limit(void *data)
766 {
767         int ret;
768         struct memcg_info *mi = (struct memcg_info *)data;
769
770         if (!mi) {
771                 _E("memory cgroup information is NULL");
772                 return RESOURCED_ERROR_INVALID_PARAMETER;
773         }
774
775         if (swap_node == SWAP_NODE_FORCE_RECLAIM)
776                 return RESOURCED_ERROR_NONE;
777
778         ret = check_oom_and_set_limit(mi->name, mi->limit_bytes);
779         if (ret != RESOURCED_ERROR_NONE)
780                 _E("Failed to change hard limit of %s cgroup to -1", mi->name);
781         else
782                 _D("changed hard limit of %s cgroup to -1", mi->name);
783
784         return ret;
785 }
786
787 static void swap_start_pid_dbus_signal_handler(GVariant *params)
788 {
789         pid_t pid;
790         struct cgroup *cgroup_swap;
791
792         do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &pid);
793         if (pid <= 0) {
794                 _D("Invalid parameter");
795                 return;
796         }
797
798         cgroup_swap = get_cgroup_tree(CGROUP_LOW);
799         if (!cgroup_swap)
800                 return;
801         swap_move_to_cgroup_by_pid(CGROUP_LOW, pid);
802         swap_start_handler(cgroup_swap->memcg_info->name);
803         _I("swap cgroup entered : pid : %d", (int)pid);
804 }
805
806
807 static const struct d_bus_signal dbus_signals[] = {
808         /* RESOURCED DBUS */
809         {RESOURCED_PATH_SWAP, RESOURCED_INTERFACE_SWAP,
810             SIGNAL_NAME_SWAP_START_PID, swap_start_pid_dbus_signal_handler, NULL},
811 };
812
813 static void swap_dbus_init(void)
814 {
815         d_bus_register_signals(dbus_signals, ARRAY_SIZE(dbus_signals));
816 }
817
818
819 static void print_swap_conf(void)
820 {
821         _I("[SWAP] swap %s", arg_swap_enable == true ? "enable" : "disable");
822         _I("[SWAP] swap at boot %s", arg_swap_at_boot == true ? "enable" : "disable");
823         _I("[SWAP] swap type = %d", arg_swap_type);
824
825         for(int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) {
826                 _I("[SWAP] cgroup (%s) swapiness = %d", cgroup == CGROUP_VIP ? "vip" :
827                                 cgroup == CGROUP_HIGH ? "high" :
828                                 cgroup == CGROUP_MEDIUM ? "medium" : "lowest", get_memcg_info(cgroup)->swappiness);
829         }
830 }
831
832 static int swap_parse_config_file(void)
833 {
834         int r = RESOURCED_ERROR_NONE;
835         GSList *iter;
836         struct swap_module_ops *swaps;
837         struct swap_conf *swap_conf = get_swap_conf();
838         if (!swap_conf) {
839                 _E("Swap configuration should not be NULL");
840                 return RESOURCED_ERROR_FAIL;
841         }
842
843         arg_swap_enable = swap_conf->enable;
844         if (arg_swap_enable == false)
845                 goto free_swap_conf;
846
847         arg_swap_at_boot = swap_conf->boot_reclaim_enable;
848         arg_swap_type = swap_conf->swap_type;
849
850         for(int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) {
851                 if (swap_conf->swappiness[cgroup] >= 0 &&
852                                 swap_conf->swappiness[cgroup] <= 100)
853                         memcg_info_set_swappiness(get_memcg_info(cgroup),
854                                         swap_conf->swappiness[cgroup]);
855         }
856
857         gslist_for_each_item(iter, swap_module) {
858                 swaps = (struct swap_module_ops *)iter->data;
859
860                 if (!swaps->conf)
861                         continue;
862
863                 if (!strncmp(swaps->name, "ZRAM", 5))
864                         r = swaps->conf(&swap_conf->zram);
865                 else if (!strncmp(swaps->name, "ZSWAP", 6))
866                         r = swaps->conf(&swap_conf->zswap);
867                 else if (!strncmp(swaps->name, "FILESWAP", 9))
868                         r = swaps->conf(NULL);
869         }
870
871 free_swap_conf:
872         free_swap_conf();
873         print_swap_conf();
874
875         return r;
876 }
877
878 static int swap_thread_create(void)
879 {
880         int ret = 0;
881         pthread_t pth;
882
883         pthread_mutex_init(&swap_mutex, NULL);
884         pthread_cond_init(&swap_cond, NULL);
885         pthread_mutex_init(&(swap_thread_queue.lock), NULL);
886         swap_thread_queue.queue = g_queue_new();
887
888         if (!swap_thread_queue.queue) {
889                 _E("fail to allocate swap thread queue");
890                 return RESOURCED_ERROR_FAIL;
891         }
892
893         ret = pthread_create(&pth, NULL, &swap_thread_main, (void *)NULL);
894         if (ret) {
895                 _E("pthread creation for swap_thread failed\n");
896                 return ret;
897         } else {
898                 pthread_detach(pth);
899         }
900
901         return RESOURCED_ERROR_NONE;
902 }
903
904 static int swap_init(void)
905 {
906         int r;
907         GSList *iter, *next;
908         struct swap_module_ops *swaps = NULL;
909         int swap_pri = SWAP_PRI_DEFAULT;
910
911         r = swap_parse_config_file();
912         if (r < 0)
913                 return r;
914
915         if (!arg_swap_enable)
916                 return -ENODEV;
917
918         memcg_write_optimizer_params();
919
920         gslist_for_each_safe(swap_module, iter, next, swaps) {
921                 swaps = (struct swap_module_ops *)iter->data;
922                 if (!CHECK_BIT(arg_swap_type, swaps->type)) {
923                         swap_remove(swaps);
924                         continue;
925                 }
926
927                 if (!swaps->init)
928                         continue;
929
930                 /*
931                  * swap_pri has a priority of previous swaps.
932                  * If swaps has SWAP_PRI_DISABLE,
933                  * swap will be supported with only one module.
934                  * After that, other modules should be removed.
935                  */
936                 if (swap_pri == SWAP_PRI_DISABLE) {
937                         swap_remove(swaps);
938                         _E("don't allow other %s module", swaps->name);
939                         continue;
940                 }
941                 swap_pri = swaps->priority;
942
943                 r = swaps->init(swaps);
944                 if (r != 0) {
945                         _E("%s module init failed", swaps->name);
946                         swap_remove(swaps);
947                 }
948         }
949
950         r = swap_thread_create();
951         if (r) {
952                 _E("swap thread create failed");
953                 return r;
954         }
955         swap_dbus_init();
956
957         return r;
958 }
959
960 static int swap_check_node(char *path)
961 {
962         _cleanup_fclose_ FILE *fp = NULL;
963
964         fp = fopen(path, "w");
965         if (fp == NULL) {
966                 _E("%s open failed", path);
967                 return RESOURCED_ERROR_NO_DATA;
968         }
969         return RESOURCED_ERROR_NONE;
970 }
971
972 static int resourced_swap_check_runtime_support(void *data)
973 {
974         int r;
975         unsigned long long usage_bytes;
976
977         /*
978          * Check whether CONFIG_SWAP is enabled in kernel.
979          */
980         if (access("/proc/swaps", R_OK) != 0)
981                 return -ENOENT;
982
983         /*
984          * Check whether kernel is supporting MEMCG_SWAP.
985          */
986         r = cgroup_read_node_ulonglong(MEMCG_PATH,
987                                 MEMCG_SWAP_USAGE, &usage_bytes);
988         if (r)
989                 return -ENOENT;
990
991         return r;
992 }
993
994 /*
995  * Quote from: kernel Documentation/cgroups/memory.txt
996  *
997  * Each bit in move_charge_at_immigrate has its own meaning about what type of
998  * charges should be moved. But in any case, it must be noted that an account of
999  * a page or a swap can be moved only when it is charged to the task's current
1000  * (old) memory cgroup.
1001  *
1002  *  bit | what type of charges would be moved ?
1003  * -----+------------------------------------------------------------------------
1004  *   0  | A charge of an anonymous page (or swap of it) used by the target task.
1005  *      | You must enable Swap Extension (see 2.4) to enable move of swap charges.
1006  * -----+------------------------------------------------------------------------
1007  *   1  | A charge of file pages (normal file, tmpfs file (e.g. ipc shared memory)
1008  *      | and swaps of tmpfs file) mmapped by the target task. Unlike the case of
1009  *      | anonymous pages, file pages (and swaps) in the range mmapped by the task
1010  *      | will be moved even if the task hasn't done page fault, i.e. they might
1011  *      | not be the task's "RSS", but other task's "RSS" that maps the same file.
1012  *      | And mapcount of the page is ignored (the page can be moved even if
1013  *      | page_mapcount(page) > 1). You must enable Swap Extension (see 2.4) to
1014  *      | enable move of swap charges.
1015  * quote end.
1016  *
1017  * In our case it's better to set only the bit number 0 to charge only
1018  * anon pages. Therefore file pages etc. will be managed directly by
1019  * kernel reclaim mechanisms.
1020  * That will help focus us only on swapping the memory that we actually
1021  * can swap - anonymous pages.
1022  * This will prevent from flushing file pages from memory - causing
1023  * slowdown when re-launching applications.
1024  */
1025 static void resourced_swap_change_memcg_settings(enum cgroup_type type)
1026 {
1027         int ret;
1028         struct cgroup *cgroup_swap = NULL;
1029         char buf[MAX_PATH_LENGTH];
1030
1031         cgroup_swap = get_cgroup_tree(type);
1032         if (!cgroup_swap)
1033                 return;
1034
1035         cgroup_write_node_uint32(cgroup_swap->memcg_info->name, MEMCG_MOVE_CHARGE, 1);
1036         snprintf(buf, sizeof(buf), "%s/%s", MEMCG_PATH, MEMCG_FORCE_RECLAIM);
1037         ret = swap_check_node(buf);
1038         if (ret == RESOURCED_ERROR_NONE) {
1039                 swap_node = SWAP_NODE_FORCE_RECLAIM;
1040                 _I("use %s node for swapping memory", MEMCG_FORCE_RECLAIM);
1041         } else {
1042                 swap_node = SWAP_NODE_HARD_LIMIT;
1043                 _I("use %s node for swapping memory", MEMCG_LIMIT_BYTE);
1044         }
1045 }
1046
1047 static int resourced_swap_init(void *data)
1048 {
1049         int ret;
1050
1051         resourced_swap_change_memcg_settings(CGROUP_LOW);
1052         swap_set_state(SWAP_OFF);
1053
1054         ret = swap_init();
1055         if (ret != RESOURCED_ERROR_NONE)
1056                 return ret;
1057
1058         if (!resourced_restarted()) {
1059                 register_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, swap_booting_done);
1060         } else {
1061                 _I("Assuming swap is already set up. To reconfigure, reboot the device.");
1062         }
1063
1064         register_notifier(RESOURCED_NOTIFIER_SWAP_START, swap_start_handler);
1065         register_notifier(RESOURCED_NOTIFIER_SWAP_ACTIVATE, swap_activate_handler);
1066         register_notifier(RESOURCED_NOTIFIER_SWAP_COMPACT, swap_compact_handler);
1067         register_notifier(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, swap_cgroup_reset_limit);
1068
1069         return ret;
1070 }
1071
1072 static int resourced_swap_finalize(void *data)
1073 {
1074         unregister_notifier(RESOURCED_NOTIFIER_SWAP_START, swap_start_handler);
1075         unregister_notifier(RESOURCED_NOTIFIER_SWAP_ACTIVATE, swap_activate_handler);
1076         unregister_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, swap_booting_done);
1077         unregister_notifier(RESOURCED_NOTIFIER_SWAP_COMPACT, swap_compact_handler);
1078         unregister_notifier(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, swap_cgroup_reset_limit);
1079
1080         g_queue_free(swap_thread_queue.queue);
1081
1082         return RESOURCED_ERROR_NONE;
1083 }
1084
1085 static struct module_ops swap_modules_ops = {
1086         .priority = MODULE_PRIORITY_NORMAL,
1087         .name = "swap",
1088         .init = resourced_swap_init,
1089         .exit = resourced_swap_finalize,
1090         .check_runtime_support = resourced_swap_check_runtime_support,
1091 };
1092
1093 MODULE_REGISTER(&swap_modules_ops)