2912160fc192d769fd40d34c46ae565f8f798b3b
[platform/core/system/resourced.git] / src / resource-optimizer / memory / swap / zswap.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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 #include "macro.h"
20 #include "module.h"
21 #include "module-data.h"
22 #include "trace.h"
23 #include "util.h"
24 #include "file-helper.h"
25 #include "procfs.h"
26 #include "swap-common.h"
27 #include "memory-cgroup.h"
28 #include "config-parser.h"
29 #include "lowmem-handler.h"
30 #include "losetup.h"
31
32 #define DEFAULT_ZSWAP_POOL_RATIO (25)
33 #define ZSWAP_FULLNESS_RATIO    0.8
34 #define DEFAULT_ZSWAP_FILE_SIZE MBYTE_TO_BYTE(30)
35
36 #define ZSWAP_POOL_PERCENT  "/sys/module/zswap/parameters/max_pool_percent"
37 #define ZSWAP_POOL_TYPE     "/sys/module/zswap/parameters/zpool"
38 #define ZSWAP_WRITTEN_SIZE  "/sys/kernel/debug/zswap/written_back_pages"
39 #define ZSWAP_ENABLED       "/sys/module/zswap/parameters/enabled"
40
41 struct swap_zswap_control {
42         char crypt_type[MAX_TYPE_LENGTH];
43         char swapfile[64];
44         float zpool_ratio;
45         long zswap_file_size;
46         unsigned long zswap_reclaim_bytes;
47         char zpool_type[MAX_TYPE_LENGTH];
48 };
49
50 static struct swap_zswap_control zswap_control = {
51         .crypt_type = "aes",
52         .swapfile = SWAP_FILE_NAME,
53         .zpool_ratio = DEFAULT_ZSWAP_POOL_RATIO,
54         .zswap_file_size = DEFAULT_ZSWAP_FILE_SIZE,
55         .zswap_reclaim_bytes = 0,
56         .zpool_type = "zbud",
57 };
58
59 static int swap_zswap_activate(void *data)
60 {
61         struct swap_module_ops *swap = (struct swap_module_ops *)data;
62         int r;
63
64         zswap_control.zswap_reclaim_bytes =
65                         zswap_control.zswap_file_size * ZSWAP_FULLNESS_RATIO;
66
67         r = swap_set_file(zswap_control.swapfile, swap, zswap_control.crypt_type);
68         if (r < 0)
69                 return r;
70
71         r = fwrite_int(ZSWAP_POOL_PERCENT, zswap_control.zpool_ratio);
72         if (r < 0) {
73                 _E("fail to write max_pool_percent: %.2f", zswap_control.zpool_ratio);
74                 return r;
75         }
76
77         r = fwrite_str(ZSWAP_POOL_TYPE, zswap_control.zpool_type);
78         if (r < 0)
79                 _E("fail to change zpool : %s use default", ZSWAP_POOL_TYPE);
80
81         r = fwrite_int(ZSWAP_ENABLED, true);
82         if (r < 0)
83                 _E("fail to enable zswap");
84
85         return 0;
86 }
87
88 static int swap_zswap_reclaim(void *data)
89 {
90         int r;
91         unsigned int swap_size;
92
93         r = fread_uint(ZSWAP_WRITTEN_SIZE, &swap_size);
94         if (r < 0) {
95                 _E("fail to read written swap size");
96                 return r;
97         }
98
99         swap_size <<= PAGE_SHIFT;
100         if (swap_size <= zswap_control.zswap_reclaim_bytes)
101                 return 0;
102
103         /*
104          * In this case, swap storage is almost full.
105          * It means that there are many background processes or
106          * some process makes memory leak.
107          * So, it requires to trigger proactive oom killer.
108          */
109
110         lowmem_trigger_swap_reclaim(CGROUP_ROOT, swap_size);
111         return -ENOSPC;
112 }
113
114 /*static int swap_zswap_parse_config_file(void)
115 {
116         ConfigTableItem items[] = {
117                 { "FILE",               "CryptType",      config_parse_string,  0,      NULL    },
118                 { "FILE",               "FileSize",       config_parse_bytes,   0,      NULL    },
119                 { "ZSWAP",              "PoolRatio",      config_parse_float,   0,      NULL    },
120                 { "ZSWAP",              "PoolType",       config_parse_string,  0,      NULL    },
121                 { NULL,         NULL,                   NULL,                           0,      NULL    }
122         };
123
124         int r;
125         _cleanup_free_ char *crypt_type = NULL;
126         _cleanup_free_ char *zpool_type = NULL;
127
128         items[0].data = &crypt_type;
129         items[1].data = &zswap_control.zswap_file_size;
130         items[2].data = &zswap_control.zpool_ratio;
131         items[3].data = &zpool_type;
132
133         r = config_parse_new(SWAP_CONF_FILE, (void*) items);
134         if (r < 0) {
135                 _E("Failed to parse configuration file: %d", r);
136                 return r;
137         }
138
139         if (check_valid_compressor(crypt_type) == RESOURCED_ERROR_NONE)
140                 strncpy(zswap_control.crypt_type, crypt_type, MAX_TYPE_LENGTH-1);
141         else
142                 memset(zswap_control.crypt_type, 0, MAX_TYPE_LENGTH);
143
144         if (zpool_type)
145                 strncpy(zswap_control.zpool_type, zpool_type, MAX_TYPE_LENGTH-1);
146         else
147                 memset(zswap_control.zpool_type, 0, MAX_TYPE_LENGTH);
148
149         return 0;
150 }*/
151
152 static int swap_zswap_init(void *data)
153 {
154         struct swap_module_ops *swap = (struct swap_module_ops *)data;
155
156         if (access(ZSWAP_POOL_PERCENT, R_OK) != 0)
157                 return -ENOENT;
158
159 /*      r = swap_zswap_parse_config_file();
160         if (r < 0) {
161                 _E("Failed to parse SwapFile config: %d", r);
162                 return r;
163         }*/
164
165         swap->k_size = BYTE_TO_KBYTE(zswap_control.zswap_file_size);
166         return 0;
167 }
168
169 static int swap_zswap_conf(void *data)
170 {
171         struct zswap_conf *zswap_conf = (struct zswap_conf *)data;
172         if (!zswap_conf) {
173                 _E("[DEBUG] Zswap configuration should not be NULL");
174                 return RESOURCED_ERROR_FAIL;
175         }
176
177         if (check_valid_compressor(zswap_conf->type) == RESOURCED_ERROR_NONE)
178                 strncpy(zswap_control.crypt_type, zswap_conf->type, MAX_TYPE_LENGTH-1);
179
180         if (zswap_conf->filesize > 0)
181                 zswap_control.zswap_file_size = zswap_conf->filesize;
182                 
183         if (zswap_conf->pool_ratio > 0.0)
184                 zswap_control.zpool_ratio = zswap_conf->pool_ratio;
185
186         if (!is_empty(zswap_conf->pool_type))
187                 strncpy(zswap_control.zpool_type, zswap_conf->pool_type, MAX_TYPE_LENGTH-1);
188         else
189                 memset(zswap_control.zpool_type, 0, MAX_TYPE_LENGTH);
190
191         _I("[DEBUG] zswap type = %s", zswap_control.crypt_type);
192         _I("[DEBUG] zswap filesize = %ld", zswap_control.zswap_file_size);
193         _I("[DEBUG] zswap pool ratio = %f", zswap_control.zpool_ratio);
194         _I("[DEBUG] zswap pool type = %s", zswap_control.zpool_type);
195
196         return RESOURCED_ERROR_NONE;
197
198 }
199
200 static struct swap_module_ops swap_zswap_ops = {
201         .name = "ZSWAP",
202         .type = SWAP_TYPE_ZSWAP,
203         .path = "",
204         .priority = SWAP_PRI_DISABLE,
205         .k_size = 0,
206         .init = swap_zswap_init,
207         .activate = swap_zswap_activate,
208         .reclaim = swap_zswap_reclaim,
209         .conf = swap_zswap_conf,
210 };
211 SWAP_MODULE_REGISTER(&swap_zswap_ops)