# SPDX-License-Identifier: GPL-2.0-only
 config PSTORE
        tristate "Persistent store support"
-       select CRYPTO if PSTORE_COMPRESS
        default n
        help
           This option enables generic access to platform level
          Defines default size of pstore kernel log storage.
          Can be enlarged if needed, not recommended to shrink it.
 
-config PSTORE_DEFLATE_COMPRESS
-       tristate "DEFLATE (ZLIB) compression"
-       default y
-       depends on PSTORE
-       select CRYPTO_DEFLATE
-       help
-         This option enables DEFLATE (also known as ZLIB) compression
-         algorithm support.
-
-config PSTORE_LZO_COMPRESS
-       tristate "LZO compression"
-       depends on PSTORE
-       select CRYPTO_LZO
-       help
-         This option enables LZO compression algorithm support.
-
-config PSTORE_LZ4_COMPRESS
-       tristate "LZ4 compression"
-       depends on PSTORE
-       select CRYPTO_LZ4
-       help
-         This option enables LZ4 compression algorithm support.
-
-config PSTORE_LZ4HC_COMPRESS
-       tristate "LZ4HC compression"
-       depends on PSTORE
-       select CRYPTO_LZ4HC
-       help
-         This option enables LZ4HC (high compression) mode algorithm.
-
-config PSTORE_842_COMPRESS
-       bool "842 compression"
-       depends on PSTORE
-       select CRYPTO_842
-       help
-         This option enables 842 compression algorithm support.
-
-config PSTORE_ZSTD_COMPRESS
-       bool "zstd compression"
-       depends on PSTORE
-       select CRYPTO_ZSTD
-       help
-         This option enables zstd compression algorithm support.
-
 config PSTORE_COMPRESS
-       def_bool y
+       bool "Pstore compression (deflate)"
        depends on PSTORE
-       depends on PSTORE_DEFLATE_COMPRESS || PSTORE_LZO_COMPRESS ||    \
-                  PSTORE_LZ4_COMPRESS || PSTORE_LZ4HC_COMPRESS ||      \
-                  PSTORE_842_COMPRESS || PSTORE_ZSTD_COMPRESS
-
-choice
-       prompt "Default pstore compression algorithm"
-       depends on PSTORE_COMPRESS
+       select ZLIB_INFLATE
+       select ZLIB_DEFLATE
+       default y
        help
-         This option chooses the default active compression algorithm.
-         This change be changed at boot with "pstore.compress=..." on
-         the kernel command line.
-
-         Currently, pstore has support for 6 compression algorithms:
-         deflate, lzo, lz4, lz4hc, 842 and zstd.
-
-         The default compression algorithm is deflate.
-
-       config PSTORE_DEFLATE_COMPRESS_DEFAULT
-               bool "deflate" if PSTORE_DEFLATE_COMPRESS
-
-       config PSTORE_LZO_COMPRESS_DEFAULT
-               bool "lzo" if PSTORE_LZO_COMPRESS
-
-       config PSTORE_LZ4_COMPRESS_DEFAULT
-               bool "lz4" if PSTORE_LZ4_COMPRESS
-
-       config PSTORE_LZ4HC_COMPRESS_DEFAULT
-               bool "lz4hc" if PSTORE_LZ4HC_COMPRESS
-
-       config PSTORE_842_COMPRESS_DEFAULT
-               bool "842" if PSTORE_842_COMPRESS
-
-       config PSTORE_ZSTD_COMPRESS_DEFAULT
-               bool "zstd" if PSTORE_ZSTD_COMPRESS
-
-endchoice
-
-config PSTORE_COMPRESS_DEFAULT
-       string
-       depends on PSTORE_COMPRESS
-       default "deflate" if PSTORE_DEFLATE_COMPRESS_DEFAULT
-       default "lzo" if PSTORE_LZO_COMPRESS_DEFAULT
-       default "lz4" if PSTORE_LZ4_COMPRESS_DEFAULT
-       default "lz4hc" if PSTORE_LZ4HC_COMPRESS_DEFAULT
-       default "842" if PSTORE_842_COMPRESS_DEFAULT
-       default "zstd" if PSTORE_ZSTD_COMPRESS_DEFAULT
+         Whether pstore records should be compressed before being written to
+         the backing store. This is implemented using the zlib 'deflate'
+         algorithm, using the library implementation instead of using the full
+         blown crypto API. This reduces the risk of secondary oopses or other
+         problems while pstore is recording panic metadata.
 
 config PSTORE_CONSOLE
        bool "Log kernel console messages"
 
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/pstore.h>
-#include <linux/crypto.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/jiffies.h>
+#include <linux/vmalloc.h>
 #include <linux/workqueue.h>
+#include <linux/zlib.h>
 
 #include "internal.h"
 
 module_param(backend, charp, 0444);
 MODULE_PARM_DESC(backend, "specific backend to use");
 
-static char *compress =
-#ifdef CONFIG_PSTORE_COMPRESS_DEFAULT
-               CONFIG_PSTORE_COMPRESS_DEFAULT;
-#else
-               NULL;
-#endif
+/*
+ * pstore no longer implements compression via the crypto API, and only
+ * supports zlib deflate compression implemented using the zlib library
+ * interface. This removes additional complexity which is hard to justify for a
+ * diagnostic facility that has to operate in conditions where the system may
+ * have become unstable. Zlib deflate is comparatively small in terms of code
+ * size, and compresses ASCII text comparatively well. In terms of compression
+ * speed, deflate is not the best performer but for recording the log output on
+ * a kernel panic, this is not considered critical.
+ *
+ * The only remaining arguments supported by the compress= module parameter are
+ * 'deflate' and 'none'. To retain compatibility with existing installations,
+ * all other values are logged and replaced with 'deflate'.
+ */
+static char *compress = "deflate";
 module_param(compress, charp, 0444);
 MODULE_PARM_DESC(compress, "compression to use");
 
 module_param(kmsg_bytes, ulong, 0444);
 MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");
 
-/* Compression parameters */
-static struct crypto_comp *tfm;
+static void *compress_workspace;
 
 static char *big_oops_buf;
 
 static int pstore_compress(const void *in, void *out,
                           unsigned int inlen, unsigned int outlen)
 {
+       struct z_stream_s zstream = {
+               .next_in        = in,
+               .avail_in       = inlen,
+               .next_out       = out,
+               .avail_out      = outlen,
+               .workspace      = compress_workspace,
+       };
        int ret;
 
        if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS))
                return -EINVAL;
 
-       ret = crypto_comp_compress(tfm, in, inlen, out, &outlen);
-       if (ret) {
-               pr_err("crypto_comp_compress failed, ret = %d!\n", ret);
-               return ret;
-       }
+       ret = zlib_deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+                               -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+       if (ret != Z_OK)
+               return -EINVAL;
 
-       return outlen;
+       ret = zlib_deflate(&zstream, Z_FINISH);
+       if (ret != Z_STREAM_END)
+               return -EINVAL;
+
+       ret = zlib_deflateEnd(&zstream);
+       if (ret != Z_OK)
+               pr_warn_once("zlib_deflateEnd() failed: %d\n", ret);
+
+       return zstream.total_out;
 }
 
 static void allocate_buf_for_compression(void)
 {
-       struct crypto_comp *ctx;
        char *buf;
 
-       /* Skip if not built-in or compression backend not selected yet. */
-       if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !compress)
-               return;
-
-       /* Skip if no pstore backend yet or compression init already done. */
-       if (!psinfo || tfm)
+       /* Skip if not built-in or compression disabled. */
+       if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !compress ||
+           !strcmp(compress, "none")) {
+               compress = NULL;
                return;
+       }
 
-       if (!crypto_has_comp(compress, 0, 0)) {
-               pr_err("Unknown compression: %s\n", compress);
-               return;
+       if (strcmp(compress, "deflate")) {
+               pr_err("Unsupported compression '%s', falling back to deflate\n",
+                      compress);
+               compress = "deflate";
        }
 
        /*
                return;
        }
 
-       ctx = crypto_alloc_comp(compress, 0, 0);
-       if (IS_ERR_OR_NULL(ctx)) {
+       compress_workspace =
+               vmalloc(zlib_deflate_workspacesize(MAX_WBITS, DEF_MEM_LEVEL));
+       if (!compress_workspace) {
+               pr_err("Failed to allocate zlib deflate workspace\n");
                kfree(buf);
-               pr_err("crypto_alloc_comp('%s') failed: %ld\n", compress,
-                      PTR_ERR(ctx));
                return;
        }
 
        /* A non-NULL big_oops_buf indicates compression is available. */
-       tfm = ctx;
        big_oops_buf = buf;
 
        pr_info("Using crash dump compression: %s\n", compress);
 
 static void free_buf_for_compression(void)
 {
-       if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && tfm) {
-               crypto_free_comp(tfm);
-               tfm = NULL;
+       if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && compress_workspace) {
+               vfree(compress_workspace);
+               compress_workspace = NULL;
        }
+
        kfree(big_oops_buf);
        big_oops_buf = NULL;
 }
 }
 EXPORT_SYMBOL_GPL(pstore_unregister);
 
-static void decompress_record(struct pstore_record *record)
+static void decompress_record(struct pstore_record *record,
+                             struct z_stream_s *zstream)
 {
        int ret;
        int unzipped_len;
        }
 
        /* Missing compression buffer means compression was not initialized. */
-       if (!big_oops_buf) {
+       if (!zstream->workspace) {
                pr_warn("no decompression method initialized!\n");
                return;
        }
 
+       ret = zlib_inflateReset(zstream);
+       if (ret != Z_OK) {
+               pr_err("zlib_inflateReset() failed, ret = %d!\n", ret);
+               return;
+       }
+
        /* Allocate enough space to hold max decompression and ECC. */
        workspace = kmalloc(psinfo->bufsize + record->ecc_notice_size,
                            GFP_KERNEL);
        if (!workspace)
                return;
 
-       /* After decompression "unzipped_len" is almost certainly smaller. */
-       ret = crypto_comp_decompress(tfm, record->buf, record->size,
-                                         workspace, &unzipped_len);
-       if (ret) {
-               pr_err("crypto_comp_decompress failed, ret = %d!\n", ret);
+       zstream->next_in        = record->buf;
+       zstream->avail_in       = record->size;
+       zstream->next_out       = workspace;
+       zstream->avail_out      = psinfo->bufsize;
+
+       ret = zlib_inflate(zstream, Z_FINISH);
+       if (ret != Z_STREAM_END) {
+               pr_err("zlib_inflate() failed, ret = %d!\n", ret);
                kfree(workspace);
                return;
        }
 
+       unzipped_len = zstream->total_out;
+
        /* Append ECC notice to decompressed buffer. */
        memcpy(workspace + unzipped_len, record->buf + record->size,
               record->ecc_notice_size);
 {
        int failed = 0;
        unsigned int stop_loop = 65536;
+       struct z_stream_s zstream = {};
 
        if (!psi || !root)
                return;
 
+       if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && compress) {
+               zstream.workspace = kvmalloc(zlib_inflate_workspacesize(),
+                                            GFP_KERNEL);
+               zlib_inflateInit2(&zstream, -DEF_WBITS);
+       }
+
        mutex_lock(&psi->read_mutex);
        if (psi->open && psi->open(psi))
                goto out;
                        break;
                }
 
-               decompress_record(record);
+               decompress_record(record, &zstream);
                rc = pstore_mkfile(root, record);
                if (rc) {
                        /* pstore_mkfile() did not take record, so free it. */
 out:
        mutex_unlock(&psi->read_mutex);
 
+       if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && compress) {
+               if (zlib_inflateEnd(&zstream) != Z_OK)
+                       pr_warn("zlib_inflateEnd() failed\n");
+               kvfree(zstream.workspace);
+       }
+
        if (failed)
                pr_warn("failed to create %d record(s) from '%s'\n",
                        failed, psi->name);
 {
        int ret;
 
-       /*
-        * Check if any pstore backends registered earlier but did not
-        * initialize compression because crypto was not ready. If so,
-        * initialize compression now.
-        */
-       allocate_buf_for_compression();
-
        ret = pstore_init_fs();
        if (ret)
                free_buf_for_compression();