|
@@ -28,7 +28,15 @@
|
|
|
#include <linux/console.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/pstore.h>
|
|
|
+#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
|
|
|
#include <linux/zlib.h>
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_PSTORE_LZO_COMPRESS
|
|
|
+#include <linux/lzo.h>
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_PSTORE_LZ4_COMPRESS
|
|
|
+#include <linux/lz4.h>
|
|
|
+#endif
|
|
|
#include <linux/string.h>
|
|
|
#include <linux/timer.h>
|
|
|
#include <linux/slab.h>
|
|
@@ -69,10 +77,23 @@ struct pstore_info *psinfo;
|
|
|
static char *backend;
|
|
|
|
|
|
/* Compression parameters */
|
|
|
+#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
|
|
|
#define COMPR_LEVEL 6
|
|
|
#define WINDOW_BITS 12
|
|
|
#define MEM_LEVEL 4
|
|
|
static struct z_stream_s stream;
|
|
|
+#else
|
|
|
+static unsigned char *workspace;
|
|
|
+#endif
|
|
|
+
|
|
|
+struct pstore_zbackend {
|
|
|
+ int (*compress)(const void *in, void *out, size_t inlen, size_t outlen);
|
|
|
+ int (*decompress)(void *in, void *out, size_t inlen, size_t outlen);
|
|
|
+ void (*allocate)(void);
|
|
|
+ void (*free)(void);
|
|
|
+
|
|
|
+ const char *name;
|
|
|
+};
|
|
|
|
|
|
static char *big_oops_buf;
|
|
|
static size_t big_oops_buf_sz;
|
|
@@ -129,9 +150,9 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(pstore_cannot_block_path);
|
|
|
|
|
|
+#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
|
|
|
/* Derived from logfs_compress() */
|
|
|
-static int pstore_compress(const void *in, void *out, size_t inlen,
|
|
|
- size_t outlen)
|
|
|
+static int compress_zlib(const void *in, void *out, size_t inlen, size_t outlen)
|
|
|
{
|
|
|
int err, ret;
|
|
|
|
|
@@ -165,7 +186,7 @@ error:
|
|
|
}
|
|
|
|
|
|
/* Derived from logfs_uncompress */
|
|
|
-static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen)
|
|
|
+static int decompress_zlib(void *in, void *out, size_t inlen, size_t outlen)
|
|
|
{
|
|
|
int err, ret;
|
|
|
|
|
@@ -194,7 +215,7 @@ error:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void allocate_buf_for_compression(void)
|
|
|
+static void allocate_zlib(void)
|
|
|
{
|
|
|
size_t size;
|
|
|
size_t cmpr;
|
|
@@ -237,12 +258,190 @@ static void allocate_buf_for_compression(void)
|
|
|
|
|
|
}
|
|
|
|
|
|
-static void free_buf_for_compression(void)
|
|
|
+static void free_zlib(void)
|
|
|
{
|
|
|
kfree(stream.workspace);
|
|
|
stream.workspace = NULL;
|
|
|
kfree(big_oops_buf);
|
|
|
big_oops_buf = NULL;
|
|
|
+ big_oops_buf_sz = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct pstore_zbackend backend_zlib = {
|
|
|
+ .compress = compress_zlib,
|
|
|
+ .decompress = decompress_zlib,
|
|
|
+ .allocate = allocate_zlib,
|
|
|
+ .free = free_zlib,
|
|
|
+ .name = "zlib",
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_PSTORE_LZO_COMPRESS
|
|
|
+static int compress_lzo(const void *in, void *out, size_t inlen, size_t outlen)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = lzo1x_1_compress(in, inlen, out, &outlen, workspace);
|
|
|
+ if (ret != LZO_E_OK) {
|
|
|
+ pr_err("lzo_compress error, ret = %d!\n", ret);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ return outlen;
|
|
|
+}
|
|
|
+
|
|
|
+static int decompress_lzo(void *in, void *out, size_t inlen, size_t outlen)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = lzo1x_decompress_safe(in, inlen, out, &outlen);
|
|
|
+ if (ret != LZO_E_OK) {
|
|
|
+ pr_err("lzo_decompress error, ret = %d!\n", ret);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ return outlen;
|
|
|
+}
|
|
|
+
|
|
|
+static void allocate_lzo(void)
|
|
|
+{
|
|
|
+ big_oops_buf_sz = lzo1x_worst_compress(psinfo->bufsize);
|
|
|
+ big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
|
|
|
+ if (big_oops_buf) {
|
|
|
+ workspace = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
|
|
|
+ if (!workspace) {
|
|
|
+ pr_err("No memory for compression workspace; skipping compression\n");
|
|
|
+ kfree(big_oops_buf);
|
|
|
+ big_oops_buf = NULL;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ pr_err("No memory for uncompressed data; skipping compression\n");
|
|
|
+ workspace = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void free_lzo(void)
|
|
|
+{
|
|
|
+ kfree(workspace);
|
|
|
+ kfree(big_oops_buf);
|
|
|
+ big_oops_buf = NULL;
|
|
|
+ big_oops_buf_sz = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct pstore_zbackend backend_lzo = {
|
|
|
+ .compress = compress_lzo,
|
|
|
+ .decompress = decompress_lzo,
|
|
|
+ .allocate = allocate_lzo,
|
|
|
+ .free = free_lzo,
|
|
|
+ .name = "lzo",
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_PSTORE_LZ4_COMPRESS
|
|
|
+static int compress_lz4(const void *in, void *out, size_t inlen, size_t outlen)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = lz4_compress(in, inlen, out, &outlen, workspace);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("lz4_compress error, ret = %d!\n", ret);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ return outlen;
|
|
|
+}
|
|
|
+
|
|
|
+static int decompress_lz4(void *in, void *out, size_t inlen, size_t outlen)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = lz4_decompress_unknownoutputsize(in, inlen, out, &outlen);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("lz4_decompress error, ret = %d!\n", ret);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ return outlen;
|
|
|
+}
|
|
|
+
|
|
|
+static void allocate_lz4(void)
|
|
|
+{
|
|
|
+ big_oops_buf_sz = lz4_compressbound(psinfo->bufsize);
|
|
|
+ big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
|
|
|
+ if (big_oops_buf) {
|
|
|
+ workspace = kmalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
|
|
|
+ if (!workspace) {
|
|
|
+ pr_err("No memory for compression workspace; skipping compression\n");
|
|
|
+ kfree(big_oops_buf);
|
|
|
+ big_oops_buf = NULL;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ pr_err("No memory for uncompressed data; skipping compression\n");
|
|
|
+ workspace = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void free_lz4(void)
|
|
|
+{
|
|
|
+ kfree(workspace);
|
|
|
+ kfree(big_oops_buf);
|
|
|
+ big_oops_buf = NULL;
|
|
|
+ big_oops_buf_sz = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct pstore_zbackend backend_lz4 = {
|
|
|
+ .compress = compress_lz4,
|
|
|
+ .decompress = decompress_lz4,
|
|
|
+ .allocate = allocate_lz4,
|
|
|
+ .free = free_lz4,
|
|
|
+ .name = "lz4",
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
+static struct pstore_zbackend *zbackend =
|
|
|
+#if defined(CONFIG_PSTORE_ZLIB_COMPRESS)
|
|
|
+ &backend_zlib;
|
|
|
+#elif defined(CONFIG_PSTORE_LZO_COMPRESS)
|
|
|
+ &backend_lzo;
|
|
|
+#elif defined(CONFIG_PSTORE_LZ4_COMPRESS)
|
|
|
+ &backend_lz4;
|
|
|
+#else
|
|
|
+ NULL;
|
|
|
+#endif
|
|
|
+
|
|
|
+static int pstore_compress(const void *in, void *out,
|
|
|
+ size_t inlen, size_t outlen)
|
|
|
+{
|
|
|
+ if (zbackend)
|
|
|
+ return zbackend->compress(in, out, inlen, outlen);
|
|
|
+ else
|
|
|
+ return -EIO;
|
|
|
+}
|
|
|
+
|
|
|
+static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen)
|
|
|
+{
|
|
|
+ if (zbackend)
|
|
|
+ return zbackend->decompress(in, out, inlen, outlen);
|
|
|
+ else
|
|
|
+ return -EIO;
|
|
|
+}
|
|
|
+
|
|
|
+static void allocate_buf_for_compression(void)
|
|
|
+{
|
|
|
+ if (zbackend) {
|
|
|
+ pr_info("using %s compression\n", zbackend->name);
|
|
|
+ zbackend->allocate();
|
|
|
+ } else {
|
|
|
+ pr_err("allocate compression buffer error!\n");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void free_buf_for_compression(void)
|
|
|
+{
|
|
|
+ if (zbackend)
|
|
|
+ zbackend->free();
|
|
|
+ else
|
|
|
+ pr_err("free compression buffer error!\n");
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -522,6 +721,7 @@ void pstore_get_records(int quiet)
|
|
|
int failed = 0, rc;
|
|
|
bool compressed;
|
|
|
int unzipped_len = -1;
|
|
|
+ ssize_t ecc_notice_size = 0;
|
|
|
|
|
|
if (!psi)
|
|
|
return;
|
|
@@ -531,7 +731,7 @@ void pstore_get_records(int quiet)
|
|
|
goto out;
|
|
|
|
|
|
while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed,
|
|
|
- psi)) > 0) {
|
|
|
+ &ecc_notice_size, psi)) > 0) {
|
|
|
if (compressed && (type == PSTORE_TYPE_DMESG)) {
|
|
|
if (big_oops_buf)
|
|
|
unzipped_len = pstore_decompress(buf,
|
|
@@ -539,6 +739,9 @@ void pstore_get_records(int quiet)
|
|
|
big_oops_buf_sz);
|
|
|
|
|
|
if (unzipped_len > 0) {
|
|
|
+ if (ecc_notice_size)
|
|
|
+ memcpy(big_oops_buf + unzipped_len,
|
|
|
+ buf + size, ecc_notice_size);
|
|
|
kfree(buf);
|
|
|
buf = big_oops_buf;
|
|
|
size = unzipped_len;
|
|
@@ -550,7 +753,8 @@ void pstore_get_records(int quiet)
|
|
|
}
|
|
|
}
|
|
|
rc = pstore_mkfile(type, psi->name, id, count, buf,
|
|
|
- compressed, (size_t)size, time, psi);
|
|
|
+ compressed, size + ecc_notice_size,
|
|
|
+ time, psi);
|
|
|
if (unzipped_len < 0) {
|
|
|
/* Free buffer other than big oops */
|
|
|
kfree(buf);
|