PM: hibernate: Support to select compression algorithm
authorNikhil V <quic_nprakash@quicinc.com>
Wed, 14 Feb 2024 07:39:32 +0000 (13:09 +0530)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 22 Feb 2024 19:03:21 +0000 (20:03 +0100)
Currently the default compression algorithm is selected based on
compile time options. Introduce a module parameter "hibernate.compressor"
to override this behaviour.

Different compression algorithms have different characteristics and
hibernation may benefit when it uses any of these algorithms, especially
when a secondary algorithm(LZ4) offers better decompression speeds over
a default algorithm(LZO), which in turn reduces hibernation image
restore time.

Users can override the default algorithm in two ways:

 1) Passing "hibernate.compressor" as kernel command line parameter.
    Usage:
     LZO: hibernate.compressor=lzo
     LZ4: hibernate.compressor=lz4

 2) Specifying the algorithm at runtime.
    Usage:
LZO: echo lzo > /sys/module/hibernate/parameters/compressor
LZ4: echo lz4 > /sys/module/hibernate/parameters/compressor

Currently LZO and LZ4 are the supported algorithms. LZO is the default
compression algorithm used with hibernation.

Signed-off-by: Nikhil V <quic_nprakash@quicinc.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Documentation/admin-guide/kernel-parameters.txt
kernel/power/hibernate.c

index 31b3a25680d08cfac3603d58b3d3783bbf1e34bb..8f7fb911b2cc2121b7d7656a9bdf26b8c2adf497 100644 (file)
                                (that will set all pages holding image data
                                during restoration read-only).
 
+       hibernate.compressor=   [HIBERNATION] Compression algorithm to be
+                               used with hibernation.
+                               Format: { lzo | lz4 }
+                               Default: lzo
+
+                               lzo: Select LZO compression algorithm to
+                               compress/decompress hibernation image.
+
+                               lz4: Select LZ4 compression algorithm to
+                               compress/decompress hibernation image.
+
        highmem=nn[KMG] [KNL,BOOT] forces the highmem zone to have an exact
                        size of <nn>. This works even on boxes that have no
                        highmem otherwise. This also works to reduce highmem
index 219191d6d0e84e650bc354e95dca051d3fcd479a..43b1a82e800c975a2de1e344ade85c3506c8b614 100644 (file)
@@ -47,7 +47,7 @@ dev_t swsusp_resume_device;
 sector_t swsusp_resume_block;
 __visible int in_suspend __nosavedata;
 
-static const char *default_compressor = CONFIG_HIBERNATION_DEF_COMP;
+static char hibernate_compressor[CRYPTO_MAX_ALG_NAME] = CONFIG_HIBERNATION_DEF_COMP;
 
 /*
  * Compression/decompression algorithm to be used while saving/loading
@@ -748,7 +748,7 @@ int hibernate(void)
         * Query for the compression algorithm support if compression is enabled.
         */
        if (!nocompress) {
-               strscpy(hib_comp_algo, default_compressor, sizeof(hib_comp_algo));
+               strscpy(hib_comp_algo, hibernate_compressor, sizeof(hib_comp_algo));
                if (crypto_has_comp(hib_comp_algo, 0, 0) != 1) {
                        pr_err("%s compression is not available\n", hib_comp_algo);
                        return -EOPNOTSUPP;
@@ -999,7 +999,7 @@ static int software_resume(void)
                if (swsusp_header_flags & SF_COMPRESSION_ALG_LZ4)
                        strscpy(hib_comp_algo, COMPRESSION_ALGO_LZ4, sizeof(hib_comp_algo));
                else
-                       strscpy(hib_comp_algo, default_compressor, sizeof(hib_comp_algo));
+                       strscpy(hib_comp_algo, COMPRESSION_ALGO_LZO, sizeof(hib_comp_algo));
                if (crypto_has_comp(hib_comp_algo, 0, 0) != 1) {
                        pr_err("%s compression is not available\n", hib_comp_algo);
                        error = -EOPNOTSUPP;
@@ -1422,6 +1422,57 @@ static int __init nohibernate_setup(char *str)
        return 1;
 }
 
+static const char * const comp_alg_enabled[] = {
+#if IS_ENABLED(CONFIG_CRYPTO_LZO)
+       COMPRESSION_ALGO_LZO,
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_LZ4)
+       COMPRESSION_ALGO_LZ4,
+#endif
+};
+
+static int hibernate_compressor_param_set(const char *compressor,
+               const struct kernel_param *kp)
+{
+       unsigned int sleep_flags;
+       int index, ret;
+
+       sleep_flags = lock_system_sleep();
+
+       index = sysfs_match_string(comp_alg_enabled, compressor);
+       if (index >= 0) {
+               ret = param_set_copystring(comp_alg_enabled[index], kp);
+               if (!ret)
+                       strscpy(hib_comp_algo, comp_alg_enabled[index],
+                               sizeof(hib_comp_algo));
+       } else {
+               ret = index;
+       }
+
+       unlock_system_sleep(sleep_flags);
+
+       if (ret)
+               pr_debug("Cannot set specified compressor %s\n",
+                        compressor);
+
+       return ret;
+}
+
+static const struct kernel_param_ops hibernate_compressor_param_ops = {
+       .set    = hibernate_compressor_param_set,
+       .get    = param_get_string,
+};
+
+static struct kparam_string hibernate_compressor_param_string = {
+       .maxlen = sizeof(hibernate_compressor),
+       .string = hibernate_compressor,
+};
+
+module_param_cb(compressor, &hibernate_compressor_param_ops,
+               &hibernate_compressor_param_string, 0644);
+MODULE_PARM_DESC(compressor,
+                "Compression algorithm to be used with hibernation");
+
 __setup("noresume", noresume_setup);
 __setup("resume_offset=", resume_offset_setup);
 __setup("resume=", resume_setup);