swap: add new module for zswap 04/187504/4
authorByungSoo Kim <bs1770.kim@samsung.com>
Tue, 13 Jun 2017 04:39:27 +0000 (13:39 +0900)
committerPaweł Szewczyk <p.szewczyk@samsung.com>
Mon, 24 Sep 2018 12:58:34 +0000 (14:58 +0200)
zswap is similar with zram+file swap.
But it has own pool size named zpool and requires "CONFIG_ZSWAP" kernel configuration.
And it uses SWAP_PRI_DISABLE priority
so it will be enabled alone in spite of declaring multiple swap devices
in config file.
Moreover duplicated functions with fileswap move common swap code.

Change-Id: Id35a30f59fe072ea22a8a5be6504e4836ddceaa1
Signed-off-by: ByungSoo Kim <bs1770.kim@samsung.com>
Signed-off-by: Paweł Szewczyk <p.szewczyk@samsung.com>
src/common/swap-common.h
src/swap/fileswap.c
src/swap/swap.c
src/swap/swap.conf
src/swap/zswap.c [new file with mode: 0644]

index 302b7d3..75402e9 100644 (file)
@@ -44,6 +44,7 @@ enum swap_type {
        SWAP_TYPE_NONE = 0x0,
        SWAP_TYPE_ZRAM = 0x1,
        SWAP_TYPE_FILE = 0x2,
+       SWAP_TYPE_ZSWAP = 0x4,
        SWAP_TYPE_MAX,
 };
 
@@ -96,10 +97,11 @@ struct swap_module_ops {
        int (*reclaim)(void *data);
 };
 
+
+int swap_set_file(char *file, struct swap_module_ops *swap, char *crypt_type);
 int do_mkswap(const char *device);
 int do_dd(char *input, char *output, unsigned int size, unsigned int count);
 
-int swap_losetup(struct swap_module_ops *swap, char *crypt_type, char *swapfile);
 bool swap_is_on(const char *name);
 
 void swap_add(const struct swap_module_ops *swap);
index 7515dea..f7aa028 100644 (file)
@@ -48,48 +48,11 @@ static struct swap_file_control file_control = {
 static int swap_file_activate(void *data)
 {
        struct swap_module_ops *swap = (struct swap_module_ops *)data;
-       int r;
 
        file_control.swap_reclaim_bytes =
                        file_control.swap_file_size * FILESWAP_FULLNESS_RATIO;
 
-       r = access(file_control.swapfile, F_OK);
-       if (r < 0 && errno == ENOENT) {
-               r = do_dd("/dev/zero", file_control.swapfile, PAGE_SIZE,
-                         KBYTE_TO_BYTE(swap->k_size) >> PAGE_SHIFT);
-               if (r > 0) {
-                       _E("Failed to create swap file(%s), exit code: %d",
-                                       file_control.swapfile, r);
-                       return -1;
-               } else if (r < 0) {
-                       _E("Failed to create swap file(%s): %s",
-                                       file_control.swapfile, strerror(-r));
-                       return r;
-               }
-               _I("SwapFile is created: %s", file_control.swapfile);
-       } else if (r != 0) {
-               _E("Failed to access swap file(%s): %m",
-                               file_control.swapfile);
-               return -errno;
-       }
-
-       r = swap_losetup(swap, file_control.crypt_type, file_control.swapfile);
-       if (r < 0)
-               return r;
-
-       if (!swap->path)
-               return -ENOENT;
-
-       r = do_mkswap(swap->path);
-       if (r > 0) {
-               _E("Failed to make swap device(%s), exit code: %d", swap->path, r);
-               return -EBUSY;
-       } else if (r < 0) {
-               _E("Failed to make swap device(%s): %s", swap->path, strerror(-r));
-               return r;
-       }
-
-       return 0;
+       return swap_set_file(file_control.swapfile, swap, file_control.crypt_type);
 }
 
 static int swap_file_reclaim(void *data)
index 9da5ddb..cd33fa0 100644 (file)
@@ -480,7 +480,7 @@ static int gen_urandom_string(char *buf, size_t len)
        return 0;
 }
 
-int swap_losetup(struct swap_module_ops *swap,
+static int swap_losetup(struct swap_module_ops *swap,
                                char *crypt_type,
                                char *swapfile)
 {
@@ -521,6 +521,46 @@ finish:
        return r;
 }
 
+int swap_set_file(char *filename, struct swap_module_ops *swap, char *crypt_type)
+{
+       int r;
+
+       r = access(filename, F_OK);
+       if (r < 0 && errno == ENOENT) {
+               r = do_dd("/dev/zero", filename, PAGE_SIZE,
+                         KBYTE_TO_BYTE(swap->k_size) >> PAGE_SHIFT);
+               if (r > 0) {
+                       _E("Failed to create swap file(%s), exit code: %d",
+                                       filename, r);
+                       return -1;
+               } else if (r < 0) {
+                       _E("Failed to create swap file(%s): %s",
+                                       filename, strerror(-r));
+                       return r;
+               }
+               _I("SwapFile is created: %s", filename);
+       } else if (r != 0) {
+               _E("Failed to access swap file(%s): %m", filename);
+               return -errno;
+       }
+
+       r = swap_losetup(swap, crypt_type, filename);
+       if (r < 0)
+               return r;
+
+       if (!swap->path)
+               return -ENOENT;
+
+       r = do_mkswap(swap->path);
+       if (r > 0) {
+               _E("Failed to make swap device(%s), exit code: %d", swap->path, r);
+               return -EBUSY;
+       } else if (r < 0) {
+               _E("Failed to make swap device(%s): %s", swap->path, strerror(-r));
+       }
+       return r;
+}
+
 bool swap_is_on(const char *name)
 {
        _cleanup_proc_swaps_free_ struct proc_swaps **swaps = NULL;
@@ -795,6 +835,8 @@ static int config_parse_swap_types(const char *filename,
                        *type |= SWAP_TYPE_ZRAM;
                else if (strneq(word, "file", l))
                        *type |= SWAP_TYPE_FILE;
+               else if (strneq(word, "zswap", l))
+                       *type |= SWAP_TYPE_ZSWAP;
                else
                        return -EINVAL;
        }
index 447dec8..cc269a9 100644 (file)
@@ -19,3 +19,6 @@ RATIO=0.4
 CryptType=ase
 ## Maximum swap file size
 FileSize=30M
+
+[ZSWAP]
+PoolRatio=0.4
\ No newline at end of file
diff --git a/src/swap/zswap.c b/src/swap/zswap.c
new file mode 100644 (file)
index 0000000..c5eb6bb
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "macro.h"
+#include "module.h"
+#include "module-data.h"
+#include "trace.h"
+#include "util.h"
+#include "file-helper.h"
+#include "procfs.h"
+#include "swap-common.h"
+#include "memory-common.h"
+#include "config-parser.h"
+#include "lowmem-handler.h"
+
+#define DEFAULT_ZSWAP_POOL_RATIO ((double) 0.25)
+#define ZSWAP_FULLNESS_RATIO   0.8
+#define DEFAULT_ZSWAP_FILE_SIZE MBYTE_TO_BYTE(30)
+
+#define ZSWAP_POOL_SIZE        "/sys/module/zswap/parameters/max_pool_size"
+#define ZSWAP_WRITTEN_SIZE     "/sys/kernel/debug/zswap/written_back_pages"
+
+struct swap_zswap_control {
+       char crypt_type[MAX_TYPE_LENGTH];
+       char swapfile[64];
+       float zpool_ratio;
+       unsigned long zswap_file_size;
+       unsigned long zswap_reclaim_bytes;
+};
+
+static struct swap_zswap_control zswap_control = {
+       .crypt_type = "aes",
+       .swapfile = SWAP_FILE_NAME,
+       .zpool_ratio = DEFAULT_ZSWAP_POOL_RATIO,
+       .zswap_file_size = DEFAULT_ZSWAP_FILE_SIZE,
+       .zswap_reclaim_bytes = 0,
+};
+
+static int swap_zswap_activate(void *data)
+{
+       struct swap_module_ops *swap = (struct swap_module_ops *)data;
+       unsigned int max_pool_size;
+       int r;
+
+       zswap_control.zswap_reclaim_bytes =
+                       zswap_control.zswap_file_size * ZSWAP_FULLNESS_RATIO;
+
+       r = swap_set_file(zswap_control.swapfile, swap, zswap_control.crypt_type);
+       if (r < 0)
+               return r;
+
+       max_pool_size = lowmem_get_ktotalram() * zswap_control.zpool_ratio;
+       r = fwrite_int(ZSWAP_POOL_SIZE, max_pool_size);
+       if (r < 0) {
+               _E("fail to write max_pool_size : %d", max_pool_size);
+               return r;
+       }
+
+       return 0;
+}
+
+static int swap_zswap_reclaim(void *data)
+{
+       int r;
+       unsigned int swap_size;
+
+       r = fread_uint(ZSWAP_WRITTEN_SIZE, &swap_size);
+       if (r < 0) {
+               _E("fail to read written swap size");
+               return r;
+       }
+
+       swap_size <<= PAGE_SHIFT;
+       if (swap_size <= zswap_control.zswap_reclaim_bytes)
+               return 0;
+
+       return -ENOSPC;
+}
+
+static int swap_zswap_parse_config_file(void)
+{
+       ConfigTableItem items[] = {
+               { "FILE",               "CryptType",            config_parse_string,    0,      NULL    },
+               { "FILE",               "FileSize",                     config_parse_bytes,     0,      NULL    },
+               { "ZSWAP",      "PoolRatio",            config_parse_float,     0,      NULL    },
+               { NULL,         NULL,                   NULL,                           0,      NULL    }
+       };
+
+       int r;
+       _cleanup_free_ char *crypt_type = NULL;
+
+       items[0].data = &crypt_type;
+       items[1].data = &zswap_control.zswap_file_size;
+       items[2].data = &zswap_control.zpool_ratio;
+
+       r = config_parse_new(SWAP_CONF_FILE, (void*) items);
+       if (r < 0) {
+               _E("Failed to parse configuration file: %s", strerror(-r));
+               return r;
+       }
+
+       if (crypt_type)
+               strncpy(zswap_control.crypt_type, crypt_type, MAX_TYPE_LENGTH-1);
+
+       return 0;
+}
+
+static int swap_zswap_init(void *data)
+{
+       struct swap_module_ops *swap = (struct swap_module_ops *)data;
+       int r;
+
+       if (access(ZSWAP_POOL_SIZE, R_OK) != 0)
+               return -ENOENT;
+
+       r = swap_zswap_parse_config_file();
+       if (r < 0) {
+               _E("Failed to parse SwapFile config: %s", strerror(-r));
+               return r;
+       }
+
+       swap->k_size = BYTE_TO_KBYTE(zswap_control.zswap_file_size);
+       return 0;
+}
+
+static const struct swap_module_ops swap_zswap_ops = {
+       .name = "ZSWAP",
+       .type = SWAP_TYPE_ZSWAP,
+       .path = "",
+       .priority = SWAP_PRI_DISABLE,
+       .k_size = 0,
+       .init = swap_zswap_init,
+       .activate = swap_zswap_activate,
+       .reclaim = swap_zswap_reclaim,
+};
+SWAP_MODLE_REGISTER(&swap_zswap_ops)