Commit cb3bee03 authored by Geliang Tang's avatar Geliang Tang Committed by Kees Cook

pstore: Use crypto compress API

In the pstore compression part, we use zlib/lzo/lz4/lz4hc/842
compression algorithm API to implement pstore compression backends. But
there are many repeat codes in these implementations. This patch uses
crypto compress API to simplify these codes.

1) rewrite allocate_buf_for_compression, free_buf_for_compression,
pstore_compress, pstore_decompress functions using crypto compress API.
2) drop compress, decompress, allocate, free functions in pstore_zbackend,
and add zbufsize function to get each different compress buffer size.
3) use late_initcall to call ramoops_init later, to make sure the crypto
subsystem has already initialized.
4) use 'unsigned int' type instead of 'size_t' in pstore_compress,
pstore_decompress functions' length arguments.
5) rename 'zlib' to 'deflate' to follow the crypto API's name convention.
Signed-off-by: default avatarGeliang Tang <geliangtang@gmail.com>
[kees: tweaked error messages on allocation failures and Kconfig help]
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
parent f2531f19
...@@ -12,51 +12,47 @@ config PSTORE ...@@ -12,51 +12,47 @@ config PSTORE
If you don't have a platform persistent store driver, If you don't have a platform persistent store driver,
say N. say N.
config PSTORE_ZLIB_COMPRESS config PSTORE_DEFLATE_COMPRESS
bool "ZLIB compression" bool "DEFLATE (ZLIB) compression"
default y default y
depends on PSTORE depends on PSTORE
select ZLIB_DEFLATE select CRYPTO_DEFLATE
select ZLIB_INFLATE
help help
This option enables ZLIB compression algorithm support. This option enables DEFLATE (also known as ZLIB) compression
algorithm support.
config PSTORE_LZO_COMPRESS config PSTORE_LZO_COMPRESS
bool "LZO compression" bool "LZO compression"
depends on PSTORE depends on PSTORE
select LZO_COMPRESS select CRYPTO_LZO
select LZO_DECOMPRESS
help help
This option enables LZO compression algorithm support. This option enables LZO compression algorithm support.
config PSTORE_LZ4_COMPRESS config PSTORE_LZ4_COMPRESS
bool "LZ4 compression" bool "LZ4 compression"
depends on PSTORE depends on PSTORE
select LZ4_COMPRESS select CRYPTO_LZ4
select LZ4_DECOMPRESS
help help
This option enables LZ4 compression algorithm support. This option enables LZ4 compression algorithm support.
config PSTORE_LZ4HC_COMPRESS config PSTORE_LZ4HC_COMPRESS
bool "LZ4HC compression" bool "LZ4HC compression"
depends on PSTORE depends on PSTORE
select LZ4HC_COMPRESS select CRYPTO_LZ4HC
select LZ4_DECOMPRESS
help help
This option enables LZ4HC (high compression) mode algorithm. This option enables LZ4HC (high compression) mode algorithm.
config PSTORE_842_COMPRESS config PSTORE_842_COMPRESS
bool "842 compression" bool "842 compression"
depends on PSTORE depends on PSTORE
select 842_COMPRESS select CRYPTO_842
select 842_DECOMPRESS
help help
This option enables 842 compression algorithm support. This option enables 842 compression algorithm support.
config PSTORE_COMPRESS config PSTORE_COMPRESS
def_bool y def_bool y
depends on PSTORE depends on PSTORE
depends on PSTORE_ZLIB_COMPRESS || PSTORE_LZO_COMPRESS || \ depends on PSTORE_DEFLATE_COMPRESS || PSTORE_LZO_COMPRESS || \
PSTORE_LZ4_COMPRESS || PSTORE_LZ4HC_COMPRESS || \ PSTORE_LZ4_COMPRESS || PSTORE_LZ4HC_COMPRESS || \
PSTORE_842_COMPRESS PSTORE_842_COMPRESS
...@@ -69,12 +65,12 @@ choice ...@@ -69,12 +65,12 @@ choice
the kernel command line. the kernel command line.
Currently, pstore has support for 5 compression algorithms: Currently, pstore has support for 5 compression algorithms:
zlib, lzo, lz4, lz4hc and 842. deflate, lzo, lz4, lz4hc and 842.
The default compression algorithm is zlib. The default compression algorithm is deflate.
config PSTORE_ZLIB_COMPRESS_DEFAULT config PSTORE_DEFLATE_COMPRESS_DEFAULT
bool "zlib" if PSTORE_ZLIB_COMPRESS=y bool "deflate" if PSTORE_DEFLATE_COMPRESS=y
config PSTORE_LZO_COMPRESS_DEFAULT config PSTORE_LZO_COMPRESS_DEFAULT
bool "lzo" if PSTORE_LZO_COMPRESS=y bool "lzo" if PSTORE_LZO_COMPRESS=y
...@@ -93,7 +89,7 @@ endchoice ...@@ -93,7 +89,7 @@ endchoice
config PSTORE_COMPRESS_DEFAULT config PSTORE_COMPRESS_DEFAULT
string string
depends on PSTORE_COMPRESS depends on PSTORE_COMPRESS
default "zlib" if PSTORE_ZLIB_COMPRESS_DEFAULT default "deflate" if PSTORE_DEFLATE_COMPRESS_DEFAULT
default "lzo" if PSTORE_LZO_COMPRESS_DEFAULT default "lzo" if PSTORE_LZO_COMPRESS_DEFAULT
default "lz4" if PSTORE_LZ4_COMPRESS_DEFAULT default "lz4" if PSTORE_LZ4_COMPRESS_DEFAULT
default "lz4hc" if PSTORE_LZ4HC_COMPRESS_DEFAULT default "lz4hc" if PSTORE_LZ4HC_COMPRESS_DEFAULT
......
...@@ -28,18 +28,13 @@ ...@@ -28,18 +28,13 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pstore.h> #include <linux/pstore.h>
#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
#include <linux/zlib.h>
#endif
#ifdef CONFIG_PSTORE_LZO_COMPRESS #ifdef CONFIG_PSTORE_LZO_COMPRESS
#include <linux/lzo.h> #include <linux/lzo.h>
#endif #endif
#if defined(CONFIG_PSTORE_LZ4_COMPRESS) || defined(CONFIG_PSTORE_LZ4HC_COMPRESS) #if defined(CONFIG_PSTORE_LZ4_COMPRESS) || defined(CONFIG_PSTORE_LZ4HC_COMPRESS)
#include <linux/lz4.h> #include <linux/lz4.h>
#endif #endif
#ifdef CONFIG_PSTORE_842_COMPRESS #include <linux/crypto.h>
#include <linux/sw842.h>
#endif
#include <linux/string.h> #include <linux/string.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -85,25 +80,10 @@ static char *compress = ...@@ -85,25 +80,10 @@ static char *compress =
#endif #endif
/* Compression parameters */ /* Compression parameters */
#ifdef CONFIG_PSTORE_ZLIB_COMPRESS static struct crypto_comp *tfm;
#define COMPR_LEVEL 6
#define WINDOW_BITS 12
#define MEM_LEVEL 4
static struct z_stream_s stream;
#endif
#if defined(CONFIG_PSTORE_LZO_COMPRESS) || \
defined(CONFIG_PSTORE_LZ4_COMPRESS) || \
defined(CONFIG_PSTORE_LZ4HC_COMPRESS) || \
defined(CONFIG_PSTORE_842_COMPRESS)
static unsigned char *workspace;
#endif
struct pstore_zbackend { struct pstore_zbackend {
int (*compress)(const void *in, void *out, size_t inlen, size_t outlen); int (*zbufsize)(size_t size);
int (*decompress)(void *in, void *out, size_t inlen, size_t outlen);
void (*allocate)(void);
void (*free)(void);
const char *name; const char *name;
}; };
...@@ -162,77 +142,12 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason) ...@@ -162,77 +142,12 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
} }
EXPORT_SYMBOL_GPL(pstore_cannot_block_path); EXPORT_SYMBOL_GPL(pstore_cannot_block_path);
#ifdef CONFIG_PSTORE_ZLIB_COMPRESS #ifdef CONFIG_PSTORE_DEFLATE_COMPRESS
/* Derived from logfs_compress() */ static int zbufsize_deflate(size_t size)
static int compress_zlib(const void *in, void *out, size_t inlen, size_t outlen)
{
int err, ret;
ret = -EIO;
err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
MEM_LEVEL, Z_DEFAULT_STRATEGY);
if (err != Z_OK)
goto error;
stream.next_in = in;
stream.avail_in = inlen;
stream.total_in = 0;
stream.next_out = out;
stream.avail_out = outlen;
stream.total_out = 0;
err = zlib_deflate(&stream, Z_FINISH);
if (err != Z_STREAM_END)
goto error;
err = zlib_deflateEnd(&stream);
if (err != Z_OK)
goto error;
if (stream.total_out >= stream.total_in)
goto error;
ret = stream.total_out;
error:
return ret;
}
/* Derived from logfs_uncompress */
static int decompress_zlib(void *in, void *out, size_t inlen, size_t outlen)
{
int err, ret;
ret = -EIO;
err = zlib_inflateInit2(&stream, WINDOW_BITS);
if (err != Z_OK)
goto error;
stream.next_in = in;
stream.avail_in = inlen;
stream.total_in = 0;
stream.next_out = out;
stream.avail_out = outlen;
stream.total_out = 0;
err = zlib_inflate(&stream, Z_FINISH);
if (err != Z_STREAM_END)
goto error;
err = zlib_inflateEnd(&stream);
if (err != Z_OK)
goto error;
ret = stream.total_out;
error:
return ret;
}
static void allocate_zlib(void)
{ {
size_t size;
size_t cmpr; size_t cmpr;
switch (psinfo->bufsize) { switch (size) {
/* buffer range for efivars */ /* buffer range for efivars */
case 1000 ... 2000: case 1000 ... 2000:
cmpr = 56; cmpr = 56;
...@@ -252,287 +167,61 @@ static void allocate_zlib(void) ...@@ -252,287 +167,61 @@ static void allocate_zlib(void)
break; break;
} }
big_oops_buf_sz = (psinfo->bufsize * 100) / cmpr; return (size * 100) / cmpr;
big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (big_oops_buf) {
size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
zlib_inflate_workspacesize());
stream.workspace = kmalloc(size, GFP_KERNEL);
if (!stream.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");
stream.workspace = NULL;
}
}
static void free_zlib(void)
{
kfree(stream.workspace);
stream.workspace = NULL;
kfree(big_oops_buf);
big_oops_buf = NULL;
big_oops_buf_sz = 0;
} }
#endif #endif
#ifdef CONFIG_PSTORE_LZO_COMPRESS #ifdef CONFIG_PSTORE_LZO_COMPRESS
static int compress_lzo(const void *in, void *out, size_t inlen, size_t outlen) static int zbufsize_lzo(size_t size)
{ {
int ret; return lzo1x_worst_compress(size);
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;
} }
#endif #endif
#if defined(CONFIG_PSTORE_LZ4_COMPRESS) || defined(CONFIG_PSTORE_LZ4HC_COMPRESS) #if defined(CONFIG_PSTORE_LZ4_COMPRESS) || defined(CONFIG_PSTORE_LZ4HC_COMPRESS)
static int decompress_lz4(void *in, void *out, size_t inlen, size_t outlen) static int zbufsize_lz4(size_t size)
{
int ret;
ret = LZ4_decompress_safe(in, out, inlen, outlen);
if (ret < 0) {
/*
* LZ4_decompress_safe will return an error code
* (< 0) if decompression failed
*/
pr_err("LZ4_decompress_safe error, ret = %d!\n", ret);
return -EIO;
}
return ret;
}
static void free_lz4(void)
{
kfree(workspace);
kfree(big_oops_buf);
big_oops_buf = NULL;
big_oops_buf_sz = 0;
}
#endif
#ifdef CONFIG_PSTORE_LZ4_COMPRESS
static int compress_lz4(const void *in, void *out, size_t inlen, size_t outlen)
{ {
int ret; return LZ4_compressBound(size);
ret = LZ4_compress_default(in, out, inlen, outlen, workspace);
if (!ret) {
pr_err("LZ4_compress_default error; compression failed!\n");
return -EIO;
}
return ret;
}
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;
}
}
#endif
#ifdef CONFIG_PSTORE_LZ4HC_COMPRESS
static int compress_lz4hc(const void *in, void *out,
size_t inlen, size_t outlen)
{
int ret;
ret = LZ4_compress_HC(in, out, inlen, outlen,
LZ4HC_DEFAULT_CLEVEL, workspace);
if (!ret) {
pr_err("LZ4_compress_HC error; compression failed!\n");
return -EIO;
}
return ret;
}
static void allocate_lz4hc(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(LZ4HC_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;
}
} }
#endif #endif
#ifdef CONFIG_PSTORE_842_COMPRESS #ifdef CONFIG_PSTORE_842_COMPRESS
static int compress_842(const void *in, void *out, size_t inlen, size_t outlen) static int zbufsize_842(size_t size)
{
int ret;
unsigned int size;
if (outlen > UINT_MAX)
return -EIO;
size = outlen;
ret = sw842_compress(in, inlen, out, &size, workspace);
if (ret) {
pr_err("sw842_compress error; compression failed!\n");
return ret;
}
return size;
}
static int decompress_842(void *in, void *out, size_t inlen, size_t outlen)
{ {
int ret;
unsigned int size;
if (outlen > UINT_MAX)
return -EIO;
size = outlen;
ret = sw842_decompress(in, inlen, out, &size);
if (ret) {
pr_err("sw842_decompress error, ret = %d!\n", ret);
return ret;
}
return size; return size;
} }
static void allocate_842(void)
{
big_oops_buf_sz = psinfo->bufsize;
big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (big_oops_buf) {
workspace = kmalloc(SW842_MEM_COMPRESS, GFP_KERNEL);
if (!workspace) {
kfree(big_oops_buf);
big_oops_buf = NULL;
}
} else {
pr_err("No memory for uncompressed data; skipping compression\n");
workspace = NULL;
}
}
static void free_842(void)
{
kfree(workspace);
kfree(big_oops_buf);
big_oops_buf = NULL;
big_oops_buf_sz = 0;
}
#endif #endif
static const struct pstore_zbackend *zbackend __ro_after_init; static const struct pstore_zbackend *zbackend __ro_after_init;
static const struct pstore_zbackend zbackends[] = { static const struct pstore_zbackend zbackends[] = {
#ifdef CONFIG_PSTORE_ZLIB_COMPRESS #ifdef CONFIG_PSTORE_DEFLATE_COMPRESS
{ {
.compress = compress_zlib, .zbufsize = zbufsize_deflate,
.decompress = decompress_zlib, .name = "deflate",
.allocate = allocate_zlib,
.free = free_zlib,
.name = "zlib",
}, },
#endif #endif
#ifdef CONFIG_PSTORE_LZO_COMPRESS #ifdef CONFIG_PSTORE_LZO_COMPRESS
{ {
.compress = compress_lzo, .zbufsize = zbufsize_lzo,
.decompress = decompress_lzo,
.allocate = allocate_lzo,
.free = free_lzo,
.name = "lzo", .name = "lzo",
}, },
#endif #endif
#ifdef CONFIG_PSTORE_LZ4_COMPRESS #ifdef CONFIG_PSTORE_LZ4_COMPRESS
{ {
.compress = compress_lz4, .zbufsize = zbufsize_lz4,
.decompress = decompress_lz4,
.allocate = allocate_lz4,
.free = free_lz4,
.name = "lz4", .name = "lz4",
}, },
#endif #endif
#ifdef CONFIG_PSTORE_LZ4HC_COMPRESS #ifdef CONFIG_PSTORE_LZ4HC_COMPRESS
{ {
.compress = compress_lz4hc, .zbufsize = zbufsize_lz4,
.decompress = decompress_lz4,
.allocate = allocate_lz4hc,
.free = free_lz4,
.name = "lz4hc", .name = "lz4hc",
}, },
#endif #endif
#ifdef CONFIG_PSTORE_842_COMPRESS #ifdef CONFIG_PSTORE_842_COMPRESS
{ {
.compress = compress_842, .zbufsize = zbufsize_842,
.decompress = decompress_842,
.allocate = allocate_842,
.free = free_842,
.name = "842", .name = "842",
}, },
#endif #endif
...@@ -540,37 +229,69 @@ static const struct pstore_zbackend zbackends[] = { ...@@ -540,37 +229,69 @@ static const struct pstore_zbackend zbackends[] = {
}; };
static int pstore_compress(const void *in, void *out, static int pstore_compress(const void *in, void *out,
size_t inlen, size_t outlen) unsigned int inlen, unsigned int outlen)
{ {
if (zbackend) int ret;
return zbackend->compress(in, out, inlen, outlen);
else ret = crypto_comp_compress(tfm, in, inlen, out, &outlen);
return -EIO; if (ret) {
pr_err("crypto_comp_compress failed, ret = %d!\n", ret);
return ret;
}
return outlen;
} }
static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen) static int pstore_decompress(void *in, void *out,
unsigned int inlen, unsigned int outlen)
{ {
if (zbackend) int ret;
return zbackend->decompress(in, out, inlen, outlen);
else ret = crypto_comp_decompress(tfm, in, inlen, out, &outlen);
return -EIO; if (ret) {
pr_err("crypto_comp_decompress failed, ret = %d!\n", ret);
return ret;
}
return outlen;
} }
static void allocate_buf_for_compression(void) static void allocate_buf_for_compression(void)
{ {
if (zbackend) { if (!zbackend)
zbackend->allocate(); return;
} else {
if (!crypto_has_comp(zbackend->name, 0, 0)) {
pr_err("No %s compression\n", zbackend->name);
return;
}
big_oops_buf_sz = zbackend->zbufsize(psinfo->bufsize);
if (big_oops_buf_sz <= 0)
return;
big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (!big_oops_buf) {
pr_err("allocate compression buffer error!\n"); pr_err("allocate compression buffer error!\n");
return;
}
tfm = crypto_alloc_comp(zbackend->name, 0, 0);
if (IS_ERR_OR_NULL(tfm)) {
kfree(big_oops_buf);
big_oops_buf = NULL;
pr_err("crypto_alloc_comp() failed!\n");
return;
} }
} }
static void free_buf_for_compression(void) static void free_buf_for_compression(void)
{ {
if (zbackend) if (!IS_ERR_OR_NULL(tfm))
zbackend->free(); crypto_free_comp(tfm);
else kfree(big_oops_buf);
pr_err("free compression buffer error!\n"); big_oops_buf = NULL;
big_oops_buf_sz = 0;
} }
/* /*
......
...@@ -938,7 +938,7 @@ static int __init ramoops_init(void) ...@@ -938,7 +938,7 @@ static int __init ramoops_init(void)
ramoops_register_dummy(); ramoops_register_dummy();
return platform_driver_register(&ramoops_driver); return platform_driver_register(&ramoops_driver);
} }
postcore_initcall(ramoops_init); late_initcall(ramoops_init);
static void __exit ramoops_exit(void) static void __exit ramoops_exit(void)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment