aa4a1a5f246f118264363594d1792f59a0d3bbc6
[platform/core/system/resourced.git] / src / resource-optimizer / memory / dedup / dedup.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2020 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 dedup.c
22  * @desc dedup 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 <linux/loop.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <time.h>
40
41 #include "macro.h"
42 #include "util.h"
43 #include "module.h"
44 #include "module-data.h"
45 #include "dedup-common.h"
46 #include "config-parser.h"
47 #include "lowmem-handler.h"
48 #include "notifier.h"
49 #include "const.h"
50 #include "file-helper.h"
51
52 #define DEDUP_PRIORITY                  20
53 #define DEDUP_ON_BOOT_TIME                      60
54 #define DEDUP_FULL_SCAN_INTERVAL        60
55 #define DEDUP_INIT_SCAN_INTERVAL        300
56 #define DEDUP_STAT_INTERVAL                     60
57
58 enum dedup_thread_op {
59         DEDUP_OP_ACTIVATE,
60         DEDUP_OP_SCANONCE,
61         DEDUP_OP_STAT,
62         DEDUP_OP_DEACTIVATE,
63         DEDUP_OP_MAX,
64 };
65
66 struct dedup_thread_bundle {
67         enum dedup_thread_op op;
68         enum ksm_scan_mode mode;
69 };
70
71 static struct module_ops dedup_module_ops;
72
73 //static enum dedup_state dedup_state; /* see src/common/dedup-common.h */
74 static bool dedup_activated = false;
75
76 static bool dedup_enable = false;
77 static bool dedup_at_boot_enable = false;
78 static enum dedup_mode dedup_mode = DEDUP_MODE_PERIODIC;
79 static bool dedup_on_lowmem = false;
80
81 static int dedup_at_boot_delay = 60000;
82 static int dedup_full_scan_interval = 600000;
83 static int dedup_stat_interval = 60000;
84 static int dedup_partial_scan_interval = 60000;
85
86 static GSource *dedup_activating_timer = NULL;
87 static GSource *dedup_scanning_timer = NULL;
88 static GSource *dedup_stat_timer = NULL;
89
90 static int dedup_do_scan(enum ksm_scan_mode);
91 static int dedup_do_stat(void);
92
93 /* dedup module parameters */
94 enum dedup_param {
95         DEDUP_PARAM_ENABLE = 0,
96         DEDUP_PARAM_AT_BOOT,
97         DEDUP_PARAM_AT_BOOT_DELAY,
98         DEDUP_PARAM_ON_LOWMEM,
99         DEDUP_PARAM_STAT_INTERVAL,
100         DEDUP_PARAM_FULL_SCAN_INTERVAL,
101         DEDUP_PARAM_PARTIAL_SCAN_INTERVAL,
102         DEDUP_PARAM_MAX,
103 };
104
105 /* ksm param types & value ranges & pathes */
106 enum ksm_param {
107         KSM_PARAM_PAGES_TO_SCAN = 0,
108         KSM_PARAM_SLEEP_MSECS,
109         KSM_PARAM_FULL_SCAN_INTERVAL,
110         KSM_PARAM_SCAN_BOOST,
111         KSM_PARAM_MAX,
112 };
113
114 static int ksm_param_ranges[KSM_PARAM_MAX][2] = {
115         {0, 10000}, /* KSM_PARAM_PAGES_TO_SCAN */
116         {0, 1000}, /* KSM_PARAM_SLEEP_MSECS */
117         {0, INT_MAX}, /* KSM_PARAM_FULL_SCAN_INTERVAL */
118         {100, 10000}, /* KSM_PARAM_SCAN_BOOST */
119 };
120 static unsigned int ksm_params[KSM_PARAM_MAX];
121 static const char *ksm_param_path[KSM_PARAM_MAX] = {
122         "/sys/kernel/mm/ksm/pages_to_scan",
123         "/sys/kernel/mm/ksm/sleep_millisecs",
124         "/sys/kernel/mm/ksm/full_scan_interval",
125         "/sys/kernel/mm/ksm/scan_boost",
126 };
127
128 /* ksm statistics */
129 #define KSM_STAT_WINDOW_MAX 10
130 static int ksm_stat_window;
131 static unsigned int ksm_stats[KSM_STAT_MAX][KSM_STAT_WINDOW_MAX];
132 static const char *ksm_stat_path[2] = {
133         "/sys/kernel/mm/ksm/pages_sharing",
134         "/sys/kernel/mm/ksm/pages_shared",
135 };
136
137 enum ksm_sysfs_state_val {
138         DEDUP_SYSFS_STOP  = 0,
139         DEDUP_SYSFS_RUN = 1,
140         DEDUP_SYSFS_ONE_SHOT = 8,
141 };
142
143 static inline int dedup_set_ksm_state(enum dedup_state state)
144 {
145         int val;
146
147         if (state == DEDUP_ON)
148                 val = DEDUP_SYSFS_RUN;
149         else if (state == DEDUP_ONE_SHOT)
150                 val = DEDUP_SYSFS_ONE_SHOT;
151         else
152                 val = DEDUP_SYSFS_STOP;
153         /* write value to /sys/kernel/mm/ksm/run */
154         return fwrite_int(DEDUP_SYSFS_KSM_RUN, val);
155 }
156
157 static inline int dedup_set_ksm_param(int param_num, unsigned int value)
158 {
159         return fwrite_uint(ksm_param_path[param_num], value);
160 }
161
162 static void dedup_set_ksm_params(void)
163 {
164         int i;
165         for (i = KSM_PARAM_PAGES_TO_SCAN; i < KSM_PARAM_MAX; i++)
166                 dedup_set_ksm_param(i, ksm_params[i]);
167 }
168
169 static int dedup_check_and_scanning_once(enum ksm_scan_mode mode)
170 {
171         int val;
172         fread_int(DEDUP_SYSFS_KSM_ONESHOT, &val);
173         if (val == KSM_SCAN_NONE)
174                 return fwrite_int(DEDUP_SYSFS_KSM_ONESHOT, mode);
175         return 0;
176 }
177
178 static int dedup_scanning_once(enum ksm_scan_mode mode)
179 {
180         int ret;
181         _D("[DEDUP] Invoke scanning once to KSM (mode: %d)", mode);
182         ret = dedup_check_and_scanning_once(mode);
183
184         return ret;
185 }
186
187 unsigned int dedup_get_ksm_stat(enum ksm_stat stat_type)
188 {
189         int last;
190         if (stat_type < KSM_STAT_PAGES_SHARING || stat_type >= KSM_STAT_MAX)
191                 return 0;
192         last = (ksm_stat_window == 0) ? KSM_STAT_WINDOW_MAX - 1 : ksm_stat_window - 1;
193         return ksm_stats[stat_type][last];
194 }
195
196 static int dedup_record_stat(void)
197 {
198         int val, ret;
199
200         ret = fread_int(ksm_stat_path[KSM_STAT_PAGES_SHARING], &val);
201         if (!ret)
202                 ksm_stats[KSM_STAT_PAGES_SHARING][ksm_stat_window] = val;
203         ret = fread_int(ksm_stat_path[KSM_STAT_PAGES_SHARED], &val);
204         if (!ret)
205                 ksm_stats[KSM_STAT_PAGES_SHARED][ksm_stat_window] = val;
206
207         _I("read ksm stat: pages_sharing: %d pages_shared: %d",
208                 ksm_stats[KSM_STAT_PAGES_SHARING][ksm_stat_window],
209                 ksm_stats[KSM_STAT_PAGES_SHARED][ksm_stat_window]);
210         ksm_stat_window = (ksm_stat_window + 1) % KSM_STAT_WINDOW_MAX;
211         return RESOURCED_ERROR_NONE;
212 }
213
214 static gboolean dedup_scanning_timer_cb(gpointer data)
215 {
216         dedup_scanning_timer = NULL;
217         if (dedup_get_state() == DEDUP_ONE_SHOT)
218                 dedup_do_scan(KSM_SCAN_FULL);
219         return false;
220 }
221
222 static gboolean dedup_stat_timer_cb(gpointer data)
223 {
224         dedup_stat_timer = NULL;
225         dedup_do_stat();
226         return false;
227 }
228
229 static void dedup_reset_scanning_timer(void)
230 {
231         _D("reset scan-timer %d seconds", dedup_full_scan_interval);
232         dedup_scanning_timer =
233                 g_timeout_source_new_seconds(dedup_full_scan_interval);
234         g_source_set_callback(dedup_scanning_timer,
235                         dedup_scanning_timer_cb, NULL, NULL);
236         g_source_attach(dedup_scanning_timer, NULL);
237 }
238
239 static void dedup_reset_stat_timer(void)
240 {
241         _D("reset stat-timer %d seconds", dedup_stat_interval);
242         dedup_stat_timer =
243                 g_timeout_source_new_seconds(dedup_stat_interval);
244         g_source_set_callback(dedup_stat_timer,
245                         dedup_stat_timer_cb, NULL, NULL);
246         g_source_attach(dedup_stat_timer, NULL);
247 }
248
249 static void dedup_deactivate_in_module(void)
250 {
251         if (dedup_activating_timer) {
252                 g_source_destroy(dedup_activating_timer);
253                 dedup_activating_timer = NULL;
254         }
255
256         if (dedup_scanning_timer) {
257                 g_source_destroy(dedup_scanning_timer);
258                 dedup_scanning_timer = NULL;
259         }
260
261         if (dedup_stat_timer) {
262                 g_source_destroy(dedup_stat_timer);
263                 dedup_stat_timer = NULL;
264         }
265
266         _D("stop KSM thread");
267
268         dedup_set_ksm_state(DEDUP_OFF);
269 }
270
271 static enum dedup_state parse_dedup_state(enum dedup_mode mode)
272 {
273         if (mode == DEDUP_MODE_PERIODIC)
274                 return DEDUP_ON;
275         else if (mode == DEDUP_MODE_ONESHOT)
276                 return DEDUP_ONE_SHOT;
277         else
278                 return DEDUP_OFF;
279 }
280
281 static void dedup_activate_in_module(void)
282 {
283         enum dedup_state state;
284
285         if (dedup_get_state() == DEDUP_ON
286                         || dedup_get_state() == DEDUP_ONE_SHOT)
287                 return;
288
289         if (dedup_activated)
290                 return;
291
292         /* make ksm activate */
293         state = parse_dedup_state(dedup_mode);
294         dedup_set_state(state);
295         dedup_set_ksm_params();
296         dedup_set_ksm_state(state);
297         _I("kernel deduplication thread is enabled");
298
299         if (dedup_activating_timer) {
300                 g_source_destroy(dedup_activating_timer);
301                 dedup_activating_timer = NULL;
302         }
303
304         if (!dedup_on_lowmem) {
305                 dedup_scanning_timer = g_timeout_source_new_seconds(dedup_full_scan_interval);
306                 g_source_set_callback(dedup_scanning_timer, dedup_scanning_timer_cb, NULL, NULL);
307                 g_source_attach(dedup_scanning_timer, NULL);
308         }
309
310         dedup_stat_timer = g_timeout_source_new_seconds(dedup_stat_interval);
311         g_source_set_callback(dedup_stat_timer, dedup_stat_timer_cb, NULL, NULL);
312         g_source_attach(dedup_stat_timer, NULL);
313
314         dedup_activated = true;
315 }
316
317 /* translations for ms -> ns and s -> ns */
318 #define DEDUP_ACT_STOMS         1000
319 #define DEDUP_ACT_MSTONS        1000000
320
321 static bool dedup_check_scan_interval
322 (struct timespec *now, struct timespec *old, unsigned long interval)
323 {
324         unsigned long diff;
325         diff = (now->tv_sec - old->tv_sec) * DEDUP_ACT_STOMS;
326         diff += (now->tv_nsec - old->tv_nsec) / DEDUP_ACT_MSTONS;
327         return (diff >= interval);
328 }
329
330 /* used in dedup_do_scan */
331 static struct timespec now, partial_begin, full_begin;
332 static int nr_dedup;
333
334 static int dedup_do_scan(enum ksm_scan_mode scan_mode)
335 {
336         enum ksm_scan_mode mode = KSM_SCAN_NONE;
337
338         clock_gettime(CLOCK_MONOTONIC, &now);
339         if (scan_mode == KSM_SCAN_FULL) {
340                 /* if full scan is requested frequently, it can be
341                  * substituted by partial scan
342                  */
343                 if (dedup_check_scan_interval(&now, &full_begin,
344                                 dedup_full_scan_interval))
345                         mode = KSM_SCAN_FULL;
346                 else if (dedup_on_lowmem &&
347                                 dedup_check_scan_interval(&now, &partial_begin,
348                                 dedup_partial_scan_interval))
349                         mode = KSM_SCAN_PARTIAL;
350         } else if (scan_mode == KSM_SCAN_PARTIAL) {
351                 if (dedup_check_scan_interval(&now, &partial_begin,
352                                 dedup_partial_scan_interval))
353                         mode = KSM_SCAN_PARTIAL;
354         }
355
356         if (mode != KSM_SCAN_NONE) {
357                 _I("[DEDUP] dedup: %d-th %s deduplication triggering", nr_dedup++,
358                                 (mode == KSM_SCAN_FULL ? "FULL" : "PARTIAL"));
359                 if (!dedup_on_lowmem) {
360                         dedup_scanning_once(KSM_SCAN_FULL);
361                         dedup_reset_scanning_timer();
362                 } else
363                         dedup_scanning_once(mode);
364
365                 if (mode == KSM_SCAN_FULL)
366                         full_begin = now;
367                 else
368                         partial_begin = now;
369         }
370
371         return RESOURCED_ERROR_NONE;
372 }
373
374 static int dedup_do_stat(void)
375 {
376         dedup_record_stat();
377         dedup_reset_stat_timer();
378         return RESOURCED_ERROR_NONE;
379 }
380
381 static int dedup_start_handler(void *data)
382 {
383         if (!data)
384                 return RESOURCED_ERROR_NO_DATA;
385
386         dedup_activate_in_module();
387
388         return RESOURCED_ERROR_NONE;
389 }
390
391 static int dedup_scan_handler(void *data)
392 {
393         int *scan_mode;
394
395         if (dedup_get_state() != DEDUP_ONE_SHOT)
396                 return 0;
397
398         if (dedup_scanning_timer) {
399                 g_source_destroy(dedup_scanning_timer);
400                 dedup_scanning_timer = NULL;
401         }
402
403         scan_mode = data;
404         return dedup_do_scan(*scan_mode);
405 }
406
407 static int dedup_stop_handler(void *data)
408 {
409         if (!data)
410                 return RESOURCED_ERROR_NO_DATA;
411
412         dedup_deactivate_in_module();
413
414         return RESOURCED_ERROR_NONE;
415 }
416
417 static gboolean dedup_activate_timer_cb(gpointer data)
418 {
419         dedup_activating_timer = NULL;
420         _D("[DEDUP] dedup activating callback called");
421         dedup_activate_in_module();
422         return false;
423 }
424
425 static int dedup_booting_done(void *data)
426 {
427         if (dedup_activated)
428                 return RESOURCED_ERROR_NONE;
429
430         if (dedup_at_boot_enable) {
431                 /* if dedup_at_boot_enable is disabled,
432                  * other daemon should activate dedup */
433                 _D("[DEDUP] dedup booting done is called");
434                 if (dedup_at_boot_delay > 0)
435                         dedup_activating_timer =
436                                 g_timeout_source_new_seconds(dedup_at_boot_delay);
437                 else
438                         dedup_activating_timer =
439                                 g_timeout_source_new_seconds(DEDUP_ON_BOOT_TIME);
440                 g_source_set_callback(dedup_activating_timer,
441                         dedup_activate_timer_cb, NULL, NULL);
442                 g_source_attach(dedup_activating_timer, NULL);
443         }
444
445         return RESOURCED_ERROR_NONE;
446 }
447
448 /*static int config_parse_dedup_modes(const char *filename,
449                                   unsigned line,
450                                   const char *section,
451                                   const char *lvalue,
452                                   int ltype,
453                                   const char *rvalue,
454                                   void *data)
455 {
456         enum dedup_mode *mode = data;
457         char *word, *state;
458         size_t l;
459
460         if (is_empty(rvalue))
461                 return 0;
462
463         *mode = 0;
464
465         FOREACH_WORD(word, l, rvalue, state) {
466                 if (strneq(word, "oneshot", l))
467                         *mode = DEDUP_MODE_ONESHOT;
468                 else if (strneq(word, "periodic", l))
469                         *mode = DEDUP_MODE_PERIODIC;
470                 else
471                         return -EINVAL;
472         }
473
474         return 0;
475 }
476
477 static int config_parse_param(const char *filename,
478                         unsigned line,
479                         const char *section,
480                         const char *lvalue,
481                         int ltype,
482                         const char *rvalue,
483                         void *data)
484 {
485         int val, *var = data;
486
487         assert(filename);
488         assert(lvalue);
489         assert(rvalue);
490         assert(data);
491         assert(section);
492
493         val = atoi(rvalue);
494         if (!strncmp(section, DEDUP_SECTION, sizeof(DEDUP_SECTION))) {
495                 if (val >= dedup_param_ranges[ltype][0] &&
496                                 val < dedup_param_ranges[ltype][1]) {
497                         *var = val;
498                         _I("[DEDUP] Success to parse parameters, val: %d of %s in %s section",
499                                         val, lvalue, section);
500                 } else
501                         _E("[DEDUP] Failed to parse parameters, ignoring: %s of %s in %s section",
502                                         rvalue, lvalue, section);
503         } else if (!strncmp(section, KSM_SECTION, sizeof(KSM_SECTION))) {
504                 if (val >= ksm_param_ranges[ltype][0] &&
505                                 val < ksm_param_ranges[ltype][1]) {
506                         *var = val;
507                         _I("[DEDUP] Success to parse parameters, val: %d of %s in %s section",
508                                         val, lvalue, section);
509                 } else
510                         _E("[DEDUP] Failed to parse parameters, ignoring: %s of %s in %s section",
511                                         rvalue, lvalue, section);
512         } else
513                 _E("[DEDUP] Unknown section: %s", section);
514         return 0;
515 }
516
517 static int dedup_parse_config_file(void)
518 {
519         int ret;
520         int arg_ksm_pages_to_scan = 100;
521         int arg_ksm_sleep = 20; // 20 msecs 
522         int arg_ksm_full_scan_interval = 60000; // 60 seconds
523         int arg_ksm_scan_boost = 100;
524
525         const ConfigTableItem items[] = {
526                 { "DEDUP",      "Enable", config_parse_bool,
527                         DEDUP_PARAM_ENABLE,
528                         &dedup_enable },
529                 { "DEDUP",      "DedupAtBoot", config_parse_bool,
530                         DEDUP_PARAM_AT_BOOT,
531                         &dedup_at_boot_enable },
532                 { "DEDUP",      "DedupAtBootDelayMs", config_parse_param,
533                         DEDUP_PARAM_AT_BOOT_DELAY,
534                         &dedup_at_boot_delay },
535                 { "DEDUP",  "ScanOnLowmem", config_parse_bool,
536                         DEDUP_PARAM_ON_LOWMEM,
537                         &dedup_on_lowmem },
538                 { "DEDUP",      "StatIntervalMs", config_parse_param,
539                         DEDUP_PARAM_STAT_INTERVAL,
540                         &dedup_stat_interval },
541                 { "DEDUP",      "FullScanIntervalMs", config_parse_param,
542                         DEDUP_PARAM_FULL_SCAN_INTERVAL,
543                         &dedup_full_scan_interval },
544                 { "DEDUP",      "PartialScanIntervalMs", config_parse_param,
545                         DEDUP_PARAM_PARTIAL_SCAN_INTERVAL,
546                         &dedup_partial_scan_interval },
547                 { "KSM",        "Mode", config_parse_dedup_modes,
548                         0,      &dedup_mode     },
549                 { "KSM",        "PagesToScan", config_parse_param,
550                         KSM_PARAM_PAGES_TO_SCAN,
551                         &arg_ksm_pages_to_scan },
552                 { "KSM",        "SleepMs", config_parse_param,
553                         KSM_PARAM_SLEEP_MSECS,
554                         &arg_ksm_sleep },
555                 { "KSM",        "FullScanIntervalMs",   config_parse_param,
556                         KSM_PARAM_FULL_SCAN_INTERVAL,
557                         &arg_ksm_full_scan_interval     },
558                 { "KSM",        "ScanBoost", config_parse_param,
559                         KSM_PARAM_SCAN_BOOST,
560                         &arg_ksm_scan_boost },
561                 { NULL,         NULL,                   NULL,
562                         0,      NULL    }
563         };
564
565         ret = config_parse_new(DEDUP_CONF_FILE, (void*) items);
566         if (ret < 0) {
567                 _E("[DEDUP] Failed to parse configuration file: %d", ret);
568                 return ret;
569         }
570
571         _I("[DEDUP] dedup init");
572
573         ksm_params[KSM_PARAM_PAGES_TO_SCAN] = arg_ksm_pages_to_scan;
574         ksm_params[KSM_PARAM_SLEEP_MSECS] = arg_ksm_sleep;
575         ksm_params[KSM_PARAM_FULL_SCAN_INTERVAL] = arg_ksm_full_scan_interval;
576         ksm_params[KSM_PARAM_SCAN_BOOST] = arg_ksm_scan_boost;
577
578         dedup_at_boot_delay /= 1000;
579         dedup_stat_interval /= 1000;
580         dedup_partial_scan_interval /= 1000;
581         dedup_full_scan_interval /= 1000;
582
583         _I("[DEDUP] deduplication mode: %s", dedup_mode == DEDUP_MODE_PERIODIC ?
584                         "kernel-managed" : "resourced-triggered");
585         _I("[DEDUP] deduplication on boot: %s", dedup_at_boot_enable ? "true" : "false");
586         _I("[DEDUP] scanning is invoked by %s", dedup_on_lowmem ?
587                         "LOWMEM event" : "periodic timer");
588         _I("[DEDUP] full scan interval: %d sec", dedup_full_scan_interval);
589         _I("[DEDUP] stat monitoring interval: %d sec", dedup_stat_interval);
590
591         _I("[DEDUP] ksm pages to scan: %d", arg_ksm_pages_to_scan);
592         _I("[DEDUP] ksm sleep time: %d", arg_ksm_sleep);
593         _I("[DEDUP] ksm full scan interval: %d", arg_ksm_full_scan_interval);
594         _I("[DEDUP] ksm scan boost: %d", arg_ksm_scan_boost);
595
596         return 0;
597 }*/
598
599 static int dedup_parse_config_file(void)
600 {
601         int arg_ksm_pages_to_scan = 100;
602         int arg_ksm_sleep = 20; // 20 msecs 
603         int arg_ksm_full_scan_interval = 60000; // 60 seconds
604         int arg_ksm_scan_boost = 100;
605
606         struct dedup_conf *dedup_conf = get_dedup_conf();
607         if (!dedup_conf) {
608                 _E("Dedup configuration should not be NULL");
609                 return RESOURCED_ERROR_FAIL;
610         }
611
612         dedup_enable = dedup_conf->enable;
613         dedup_at_boot_enable = dedup_conf->boot_dedup_enable;
614         dedup_on_lowmem = dedup_conf->scan_on_lowmem;
615
616         if (!strncmp(dedup_conf->ksm.mode, "oneshot", 8))
617                 dedup_mode = DEDUP_MODE_ONESHOT;
618         else if(!strncmp(dedup_conf->ksm.mode, "periodic", 9))
619                 dedup_mode = DEDUP_MODE_PERIODIC;
620
621         if (dedup_conf->ksm.pages > ksm_param_ranges[KSM_PARAM_PAGES_TO_SCAN][0] &&
622                 dedup_conf->ksm.pages <= ksm_param_ranges[KSM_PARAM_PAGES_TO_SCAN][1])
623                 ksm_params[KSM_PARAM_PAGES_TO_SCAN] = dedup_conf->ksm.pages;
624         else 
625                 ksm_params[KSM_PARAM_PAGES_TO_SCAN] = arg_ksm_pages_to_scan;
626
627         if (dedup_conf->ksm.boost_pages > ksm_param_ranges[KSM_PARAM_SCAN_BOOST][0] &&
628             dedup_conf->ksm.boost_pages <= ksm_param_ranges[KSM_PARAM_SCAN_BOOST][1])
629                 ksm_params[KSM_PARAM_SCAN_BOOST] = dedup_conf->ksm.boost_pages;
630         else
631                 ksm_params[KSM_PARAM_SCAN_BOOST] = arg_ksm_scan_boost;
632
633         ksm_params[KSM_PARAM_SLEEP_MSECS] = arg_ksm_sleep;
634         ksm_params[KSM_PARAM_FULL_SCAN_INTERVAL] = arg_ksm_full_scan_interval;
635
636         _I("[DEDUP] deduplication mode: %s", dedup_mode == DEDUP_MODE_PERIODIC ?
637                         "kernel-managed" : "resourced-triggered");
638         _I("[DEDUP] deduplication on boot: %s", dedup_at_boot_enable ? "true" : "false");
639         _I("[DEDUP] scanning is invoked by %s", dedup_on_lowmem ?
640                         "LOWMEM event" : "periodic timer");
641         _I("[DEDUP] full scan interval: %d sec", dedup_full_scan_interval);
642         _I("[DEDUP] stat monitoring interval: %d sec", dedup_stat_interval);
643
644         _I("[DEDUP] ksm pages to scan: %d", ksm_params[KSM_PARAM_PAGES_TO_SCAN]);
645         _I("[DEDUP] ksm sleep time: %d", ksm_params[KSM_PARAM_SLEEP_MSECS]);
646         _I("[DEDUP] ksm full scan interval: %d", ksm_params[KSM_PARAM_FULL_SCAN_INTERVAL]);
647         _I("[DEDUP] ksm scan boost: %d", ksm_params[KSM_PARAM_SCAN_BOOST]);
648
649         free_dedup_conf();
650
651         return RESOURCED_ERROR_NONE;
652 }
653
654 static inline void init_dedup_stat(void)
655 {
656         int i, j;
657         for (i = KSM_STAT_PAGES_SHARING; i < KSM_STAT_MAX; i++)
658                 for (j = 0; j < KSM_STAT_WINDOW_MAX; j++)
659                         ksm_stats[i][j] = 0;
660         ksm_stat_window = 0;
661 }
662
663 static int dedup_init(void)
664 {
665         int ret;
666
667         init_dedup_stat();
668         ret = dedup_parse_config_file();
669         if (ret < 0)
670                 return ret;
671
672         if (!dedup_enable)
673                 return -ENODEV;
674
675         /* initialize time variables */
676         if (!clock_gettime(CLOCK_MONOTONIC, &now)) {
677                 partial_begin = now;
678                 full_begin = now;
679         } else {
680                 _I("Time initialization failed");
681                 memset(&partial_begin, 0, sizeof(struct timespec));
682                 memset(&full_begin, 0, sizeof(struct timespec));
683         }
684
685         return ret;
686 }
687
688 static int resourced_dedup_check_runtime_support(void *data)
689 {
690         /*
691          * Check whether CONFIG_LKSM is enabled in kernel.
692          */
693         if (access("/sys/kernel/mm/ksm/run", R_OK) != 0) {
694                 _W("the kernel don't support KSM, please check kernel configuration");
695                 return -ENOENT;
696         }
697         if (access("/sys/kernel/mm/ksm/one_shot_scanning", R_OK) != 0) {
698                 _W("the kernel support KSM but not LKSM, please check kernel configuration");
699                 return -ENOENT;
700         }
701
702         return 0;
703 }
704
705 static int resourced_dedup_init(void *data)
706 {
707         int ret;
708
709         dedup_set_state(DEDUP_OFF);
710
711         ret = dedup_init();
712         if (ret != RESOURCED_ERROR_NONE)
713                 return ret;
714         _I("resourced dedup module is initialized");
715         register_notifier(RESOURCED_NOTIFIER_DEDUP_START, dedup_start_handler);
716         register_notifier(RESOURCED_NOTIFIER_DEDUP_SCAN, dedup_scan_handler);
717         register_notifier(RESOURCED_NOTIFIER_DEDUP_STOP, dedup_stop_handler);
718         register_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, dedup_booting_done);
719
720         return ret;
721 }
722
723 static int resourced_dedup_finalize(void *data)
724 {
725         unregister_notifier(RESOURCED_NOTIFIER_DEDUP_START, dedup_start_handler);
726         unregister_notifier(RESOURCED_NOTIFIER_DEDUP_SCAN, dedup_scan_handler);
727         unregister_notifier(RESOURCED_NOTIFIER_DEDUP_STOP, dedup_stop_handler);
728         unregister_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, dedup_booting_done);
729
730         dedup_deactivate_in_module();
731
732         _I("dedup module will be finalized");
733
734         return RESOURCED_ERROR_NONE;
735 }
736
737 static struct module_ops dedup_module_ops = {
738         .priority = MODULE_PRIORITY_NORMAL,
739         .name = "dedup",
740         .init = resourced_dedup_init,
741         .exit = resourced_dedup_finalize,
742         .check_runtime_support = resourced_dedup_check_runtime_support,
743 };
744
745 MODULE_REGISTER(&dedup_module_ops)