4 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
29 #include <sys/types.h>
32 #include <sys/sysinfo.h>
34 #include <sys/resource.h>
35 #include <memory-cgroup.h>
36 #include <linux/loop.h>
44 #include "module-data.h"
45 #include "dedup-common.h"
46 #include "config-parser.h"
47 #include "lowmem-handler.h"
50 #include "file-helper.h"
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
58 enum dedup_thread_op {
66 struct dedup_thread_bundle {
67 enum dedup_thread_op op;
68 enum ksm_scan_mode mode;
71 static struct module_ops dedup_module_ops;
73 //static enum dedup_state dedup_state; /* see src/common/dedup-common.h */
74 static bool dedup_activated = false;
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;
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;
86 static GSource *dedup_activating_timer = NULL;
87 static GSource *dedup_scanning_timer = NULL;
88 static GSource *dedup_stat_timer = NULL;
90 static int dedup_do_scan(enum ksm_scan_mode);
91 static int dedup_do_stat(void);
93 /* dedup module parameters */
95 DEDUP_PARAM_ENABLE = 0,
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,
105 /* ksm param types & value ranges & pathes */
107 KSM_PARAM_PAGES_TO_SCAN = 0,
108 KSM_PARAM_SLEEP_MSECS,
109 KSM_PARAM_FULL_SCAN_INTERVAL,
110 KSM_PARAM_SCAN_BOOST,
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 */
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",
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",
137 enum ksm_sysfs_state_val {
138 DEDUP_SYSFS_STOP = 0,
140 DEDUP_SYSFS_ONE_SHOT = 8,
143 static inline int dedup_set_ksm_state(enum dedup_state state)
147 if (state == DEDUP_ON)
148 val = DEDUP_SYSFS_RUN;
149 else if (state == DEDUP_ONE_SHOT)
150 val = DEDUP_SYSFS_ONE_SHOT;
152 val = DEDUP_SYSFS_STOP;
153 /* write value to /sys/kernel/mm/ksm/run */
154 return fwrite_int(DEDUP_SYSFS_KSM_RUN, val);
157 static inline int dedup_set_ksm_param(int param_num, unsigned int value)
159 return fwrite_uint(ksm_param_path[param_num], value);
162 static void dedup_set_ksm_params(void)
165 for (i = KSM_PARAM_PAGES_TO_SCAN; i < KSM_PARAM_MAX; i++)
166 dedup_set_ksm_param(i, ksm_params[i]);
169 static int dedup_check_and_scanning_once(enum ksm_scan_mode mode)
172 fread_int(DEDUP_SYSFS_KSM_ONESHOT, &val);
173 if (val == KSM_SCAN_NONE)
174 return fwrite_int(DEDUP_SYSFS_KSM_ONESHOT, mode);
178 static int dedup_scanning_once(enum ksm_scan_mode mode)
181 _D("[DEDUP] Invoke scanning once to KSM (mode: %d)", mode);
182 ret = dedup_check_and_scanning_once(mode);
187 unsigned int dedup_get_ksm_stat(enum ksm_stat stat_type)
190 if (stat_type < KSM_STAT_PAGES_SHARING || stat_type >= KSM_STAT_MAX)
192 last = (ksm_stat_window == 0) ? KSM_STAT_WINDOW_MAX - 1 : ksm_stat_window - 1;
193 return ksm_stats[stat_type][last];
196 static int dedup_record_stat(void)
200 ret = fread_int(ksm_stat_path[KSM_STAT_PAGES_SHARING], &val);
202 ksm_stats[KSM_STAT_PAGES_SHARING][ksm_stat_window] = val;
203 ret = fread_int(ksm_stat_path[KSM_STAT_PAGES_SHARED], &val);
205 ksm_stats[KSM_STAT_PAGES_SHARED][ksm_stat_window] = val;
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;
214 static gboolean dedup_scanning_timer_cb(gpointer data)
216 dedup_scanning_timer = NULL;
217 if (dedup_get_state() == DEDUP_ONE_SHOT)
218 dedup_do_scan(KSM_SCAN_FULL);
222 static gboolean dedup_stat_timer_cb(gpointer data)
224 dedup_stat_timer = NULL;
229 static void dedup_reset_scanning_timer(void)
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);
239 static void dedup_reset_stat_timer(void)
241 _D("reset stat-timer %d seconds", dedup_stat_interval);
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);
249 static void dedup_deactivate_in_module(void)
251 if (dedup_activating_timer) {
252 g_source_destroy(dedup_activating_timer);
253 dedup_activating_timer = NULL;
256 if (dedup_scanning_timer) {
257 g_source_destroy(dedup_scanning_timer);
258 dedup_scanning_timer = NULL;
261 if (dedup_stat_timer) {
262 g_source_destroy(dedup_stat_timer);
263 dedup_stat_timer = NULL;
266 _D("stop KSM thread");
268 dedup_set_ksm_state(DEDUP_OFF);
271 static enum dedup_state parse_dedup_state(enum dedup_mode mode)
273 if (mode == DEDUP_MODE_PERIODIC)
275 else if (mode == DEDUP_MODE_ONESHOT)
276 return DEDUP_ONE_SHOT;
281 static void dedup_activate_in_module(void)
283 enum dedup_state state;
285 if (dedup_get_state() == DEDUP_ON
286 || dedup_get_state() == DEDUP_ONE_SHOT)
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");
299 if (dedup_activating_timer) {
300 g_source_destroy(dedup_activating_timer);
301 dedup_activating_timer = NULL;
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);
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);
314 dedup_activated = true;
317 /* translations for ms -> ns and s -> ns */
318 #define DEDUP_ACT_STOMS 1000
319 #define DEDUP_ACT_MSTONS 1000000
321 static bool dedup_check_scan_interval
322 (struct timespec *now, struct timespec *old, unsigned long interval)
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);
330 /* used in dedup_do_scan */
331 static struct timespec now, partial_begin, full_begin;
334 static int dedup_do_scan(enum ksm_scan_mode scan_mode)
336 enum ksm_scan_mode mode = KSM_SCAN_NONE;
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
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;
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();
363 dedup_scanning_once(mode);
365 if (mode == KSM_SCAN_FULL)
371 return RESOURCED_ERROR_NONE;
374 static int dedup_do_stat(void)
377 dedup_reset_stat_timer();
378 return RESOURCED_ERROR_NONE;
381 static int dedup_start_handler(void *data)
384 return RESOURCED_ERROR_NO_DATA;
386 dedup_activate_in_module();
388 return RESOURCED_ERROR_NONE;
391 static int dedup_scan_handler(void *data)
395 if (dedup_get_state() != DEDUP_ONE_SHOT)
398 if (dedup_scanning_timer) {
399 g_source_destroy(dedup_scanning_timer);
400 dedup_scanning_timer = NULL;
404 return dedup_do_scan(*scan_mode);
407 static int dedup_stop_handler(void *data)
410 return RESOURCED_ERROR_NO_DATA;
412 dedup_deactivate_in_module();
414 return RESOURCED_ERROR_NONE;
417 static gboolean dedup_activate_timer_cb(gpointer data)
419 dedup_activating_timer = NULL;
420 _D("[DEDUP] dedup activating callback called");
421 dedup_activate_in_module();
425 static int dedup_booting_done(void *data)
428 return RESOURCED_ERROR_NONE;
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);
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);
445 return RESOURCED_ERROR_NONE;
448 /*static int config_parse_dedup_modes(const char *filename,
456 enum dedup_mode *mode = data;
460 if (is_empty(rvalue))
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;
477 static int config_parse_param(const char *filename,
485 int val, *var = data;
494 if (!strncmp(section, DEDUP_SECTION, sizeof(DEDUP_SECTION))) {
495 if (val >= dedup_param_ranges[ltype][0] &&
496 val < dedup_param_ranges[ltype][1]) {
498 _I("[DEDUP] Success to parse parameters, val: %d of %s in %s section",
499 val, lvalue, section);
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]) {
507 _I("[DEDUP] Success to parse parameters, val: %d of %s in %s section",
508 val, lvalue, section);
510 _E("[DEDUP] Failed to parse parameters, ignoring: %s of %s in %s section",
511 rvalue, lvalue, section);
513 _E("[DEDUP] Unknown section: %s", section);
517 static int dedup_parse_config_file(void)
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;
525 const ConfigTableItem items[] = {
526 { "DEDUP", "Enable", config_parse_bool,
529 { "DEDUP", "DedupAtBoot", config_parse_bool,
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,
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,
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,
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 },
565 ret = config_parse_new(DEDUP_CONF_FILE, (void*) items);
567 _E("[DEDUP] Failed to parse configuration file: %d", ret);
571 _I("[DEDUP] dedup init");
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;
578 dedup_at_boot_delay /= 1000;
579 dedup_stat_interval /= 1000;
580 dedup_partial_scan_interval /= 1000;
581 dedup_full_scan_interval /= 1000;
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);
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);
599 static int dedup_parse_config_file(void)
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;
606 struct dedup_conf *dedup_conf = get_dedup_conf();
608 _E("Dedup configuration should not be NULL");
609 return RESOURCED_ERROR_FAIL;
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;
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;
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;
625 ksm_params[KSM_PARAM_PAGES_TO_SCAN] = arg_ksm_pages_to_scan;
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;
631 ksm_params[KSM_PARAM_SCAN_BOOST] = arg_ksm_scan_boost;
633 ksm_params[KSM_PARAM_SLEEP_MSECS] = arg_ksm_sleep;
634 ksm_params[KSM_PARAM_FULL_SCAN_INTERVAL] = arg_ksm_full_scan_interval;
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);
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]);
651 return RESOURCED_ERROR_NONE;
654 static inline void init_dedup_stat(void)
657 for (i = KSM_STAT_PAGES_SHARING; i < KSM_STAT_MAX; i++)
658 for (j = 0; j < KSM_STAT_WINDOW_MAX; j++)
663 static int dedup_init(void)
668 ret = dedup_parse_config_file();
675 /* initialize time variables */
676 if (!clock_gettime(CLOCK_MONOTONIC, &now)) {
680 _I("Time initialization failed");
681 memset(&partial_begin, 0, sizeof(struct timespec));
682 memset(&full_begin, 0, sizeof(struct timespec));
688 static int resourced_dedup_check_runtime_support(void *data)
691 * Check whether CONFIG_LKSM is enabled in kernel.
693 if (access("/sys/kernel/mm/ksm/run", R_OK) != 0) {
694 _W("the kernel don't support KSM, please check kernel configuration");
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");
705 static int resourced_dedup_init(void *data)
709 dedup_set_state(DEDUP_OFF);
712 if (ret != RESOURCED_ERROR_NONE)
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);
723 static int resourced_dedup_finalize(void *data)
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);
730 dedup_deactivate_in_module();
732 _I("dedup module will be finalized");
734 return RESOURCED_ERROR_NONE;
737 static struct module_ops dedup_module_ops = {
738 .priority = MODULE_PRIORITY_NORMAL,
740 .init = resourced_dedup_init,
741 .exit = resourced_dedup_finalize,
742 .check_runtime_support = resourced_dedup_check_runtime_support,
745 MODULE_REGISTER(&dedup_module_ops)