Skip to content
Snippets Groups Projects
Commit 69824bcc authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull pstore updates from Kees Cook:
 "This cycle was almost entirely improvements to the pstore compression
  options, noted below:

   - Add lz4hc and 842 to pstore compression options (Geliang Tang)

   - Refactor to use crypto compression API (Geliang Tang)

   - Fix up Kconfig dependencies for compression (Arnd Bergmann)

   - Allow for run-time compression selection

   - Remove stack VLA usage"

* tag 'pstore-v4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  pstore: fix crypto dependencies
  pstore: Use crypto compress API
  pstore/ram: Do not use stack VLA for parity workspace
  pstore: Select compression at runtime
  pstore: Avoid size casts for 842 compression
  pstore: Add lz4hc and 842 compression support
parents 3b54765c 58eb5b67
Branches
No related tags found
No related merge requests found
config PSTORE config PSTORE
tristate "Persistent store support" tristate "Persistent store support"
select CRYPTO if PSTORE_COMPRESS
default n default n
help help
This option enables generic access to platform level This option enables generic access to platform level
...@@ -12,35 +13,89 @@ config PSTORE ...@@ -12,35 +13,89 @@ 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.
choice config PSTORE_DEFLATE_COMPRESS
prompt "Choose compression algorithm" tristate "DEFLATE (ZLIB) compression"
default y
depends on PSTORE depends on PSTORE
default PSTORE_ZLIB_COMPRESS select CRYPTO_DEFLATE
help
This option chooses compression algorithm.
config PSTORE_ZLIB_COMPRESS
bool "ZLIB"
select ZLIB_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" tristate "LZO compression"
select LZO_COMPRESS depends on PSTORE
select LZO_DECOMPRESS select CRYPTO_LZO
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" tristate "LZ4 compression"
select LZ4_COMPRESS depends on PSTORE
select LZ4_DECOMPRESS select CRYPTO_LZ4
help help
This option enables LZ4 compression algorithm support. 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_COMPRESS
def_bool y
depends on PSTORE
depends on PSTORE_DEFLATE_COMPRESS || PSTORE_LZO_COMPRESS || \
PSTORE_LZ4_COMPRESS || PSTORE_LZ4HC_COMPRESS || \
PSTORE_842_COMPRESS
choice
prompt "Default pstore compression algorithm"
depends on PSTORE_COMPRESS
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 5 compression algorithms:
deflate, lzo, lz4, lz4hc and 842.
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
endchoice 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
config PSTORE_CONSOLE config PSTORE_CONSOLE
bool "Log kernel console messages" bool "Log kernel console messages"
depends on PSTORE depends on PSTORE
......
...@@ -486,6 +486,8 @@ static int __init init_pstore_fs(void) ...@@ -486,6 +486,8 @@ static int __init init_pstore_fs(void)
{ {
int err; int err;
pstore_choose_compression();
/* Create a convenient mount point for people to access pstore */ /* Create a convenient mount point for people to access pstore */
err = sysfs_create_mount_point(fs_kobj, "pstore"); err = sysfs_create_mount_point(fs_kobj, "pstore");
if (err) if (err)
......
...@@ -37,4 +37,7 @@ extern bool pstore_is_mounted(void); ...@@ -37,4 +37,7 @@ extern bool pstore_is_mounted(void);
extern void pstore_record_init(struct pstore_record *record, extern void pstore_record_init(struct pstore_record *record,
struct pstore_info *psi); struct pstore_info *psi);
/* Called during module_init() */
extern void __init pstore_choose_compression(void);
#endif #endif
...@@ -28,15 +28,13 @@ ...@@ -28,15 +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 #if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
#include <linux/zlib.h>
#endif
#ifdef CONFIG_PSTORE_LZO_COMPRESS
#include <linux/lzo.h> #include <linux/lzo.h>
#endif #endif
#ifdef CONFIG_PSTORE_LZ4_COMPRESS #if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS) || IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
#include <linux/lz4.h> #include <linux/lz4.h>
#endif #endif
#include <linux/crypto.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -74,23 +72,18 @@ static DEFINE_SPINLOCK(pstore_lock); ...@@ -74,23 +72,18 @@ static DEFINE_SPINLOCK(pstore_lock);
struct pstore_info *psinfo; struct pstore_info *psinfo;
static char *backend; static char *backend;
static char *compress =
/* Compression parameters */ #ifdef CONFIG_PSTORE_COMPRESS_DEFAULT
#ifdef CONFIG_PSTORE_ZLIB_COMPRESS CONFIG_PSTORE_COMPRESS_DEFAULT;
#define COMPR_LEVEL 6
#define WINDOW_BITS 12
#define MEM_LEVEL 4
static struct z_stream_s stream;
#else #else
static unsigned char *workspace; NULL;
#endif #endif
struct pstore_zbackend { /* Compression parameters */
int (*compress)(const void *in, void *out, size_t inlen, size_t outlen); static struct crypto_comp *tfm;
int (*decompress)(void *in, void *out, size_t inlen, size_t outlen);
void (*allocate)(void);
void (*free)(void);
struct pstore_zbackend {
int (*zbufsize)(size_t size);
const char *name; const char *name;
}; };
...@@ -149,77 +142,12 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason) ...@@ -149,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 #if IS_ENABLED(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;
...@@ -239,212 +167,131 @@ static void allocate_zlib(void) ...@@ -239,212 +167,131 @@ 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;
}
} }
#endif
static void free_zlib(void) #if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
static int zbufsize_lzo(size_t size)
{ {
kfree(stream.workspace); return lzo1x_worst_compress(size);
stream.workspace = NULL;
kfree(big_oops_buf);
big_oops_buf = NULL;
big_oops_buf_sz = 0;
} }
static const struct pstore_zbackend backend_zlib = {
.compress = compress_zlib,
.decompress = decompress_zlib,
.allocate = allocate_zlib,
.free = free_zlib,
.name = "zlib",
};
#endif #endif
#ifdef CONFIG_PSTORE_LZO_COMPRESS #if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS) || IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
static int compress_lzo(const void *in, void *out, size_t inlen, size_t outlen) static int zbufsize_lz4(size_t size)
{ {
int ret; return LZ4_compressBound(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;
} }
#endif
static int decompress_lzo(void *in, void *out, size_t inlen, size_t outlen) #if IS_ENABLED(CONFIG_PSTORE_842_COMPRESS)
static int zbufsize_842(size_t size)
{ {
int ret; return size;
ret = lzo1x_decompress_safe(in, inlen, out, &outlen);
if (ret != LZO_E_OK) {
pr_err("lzo_decompress error, ret = %d!\n", ret);
return -EIO;
} }
#endif
return outlen; static const struct pstore_zbackend *zbackend __ro_after_init;
}
static void allocate_lzo(void) static const struct pstore_zbackend zbackends[] = {
#if IS_ENABLED(CONFIG_PSTORE_DEFLATE_COMPRESS)
{ {
big_oops_buf_sz = lzo1x_worst_compress(psinfo->bufsize); .zbufsize = zbufsize_deflate,
big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); .name = "deflate",
if (big_oops_buf) { },
workspace = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); #endif
if (!workspace) { #if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
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); .zbufsize = zbufsize_lzo,
kfree(big_oops_buf);
big_oops_buf = NULL;
big_oops_buf_sz = 0;
}
static const struct pstore_zbackend backend_lzo = {
.compress = compress_lzo,
.decompress = decompress_lzo,
.allocate = allocate_lzo,
.free = free_lzo,
.name = "lzo", .name = "lzo",
}; },
#endif
#if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS)
{
.zbufsize = zbufsize_lz4,
.name = "lz4",
},
#endif #endif
#if IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
{
.zbufsize = zbufsize_lz4,
.name = "lz4hc",
},
#endif
#if IS_ENABLED(CONFIG_PSTORE_842_COMPRESS)
{
.zbufsize = zbufsize_842,
.name = "842",
},
#endif
{ }
};
#ifdef CONFIG_PSTORE_LZ4_COMPRESS static int pstore_compress(const void *in, void *out,
static int compress_lz4(const void *in, void *out, size_t inlen, size_t outlen) unsigned int inlen, unsigned int outlen)
{ {
int ret; int ret;
ret = LZ4_compress_default(in, out, inlen, outlen, workspace); ret = crypto_comp_compress(tfm, in, inlen, out, &outlen);
if (!ret) { if (ret) {
pr_err("LZ4_compress_default error; compression failed!\n"); pr_err("crypto_comp_compress failed, ret = %d!\n", ret);
return -EIO; return ret;
} }
return ret; return outlen;
} }
static int decompress_lz4(void *in, void *out, size_t inlen, size_t outlen) static int pstore_decompress(void *in, void *out,
unsigned int inlen, unsigned int outlen)
{ {
int ret; int ret;
ret = LZ4_decompress_safe(in, out, inlen, outlen); ret = crypto_comp_decompress(tfm, in, inlen, out, &outlen);
if (ret < 0) { if (ret) {
/* pr_err("crypto_comp_decompress failed, ret = %d!\n", ret);
* 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; return ret;
} }
static void allocate_lz4(void) return outlen;
{
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) static void allocate_buf_for_compression(void)
{ {
kfree(workspace); if (!zbackend)
kfree(big_oops_buf); return;
big_oops_buf = NULL;
big_oops_buf_sz = 0;
}
static const struct pstore_zbackend backend_lz4 = {
.compress = compress_lz4,
.decompress = decompress_lz4,
.allocate = allocate_lz4,
.free = free_lz4,
.name = "lz4",
};
#endif
static const 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, if (!crypto_has_comp(zbackend->name, 0, 0)) {
size_t inlen, size_t outlen) pr_err("No %s compression\n", zbackend->name);
{ return;
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) big_oops_buf_sz = zbackend->zbufsize(psinfo->bufsize);
{ if (big_oops_buf_sz <= 0)
if (zbackend) return;
return zbackend->decompress(in, out, inlen, outlen);
else
return -EIO;
}
static void allocate_buf_for_compression(void) big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
{ if (!big_oops_buf) {
if (zbackend) {
pr_info("using %s compression\n", zbackend->name);
zbackend->allocate();
} else {
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;
} }
/* /*
...@@ -901,5 +748,24 @@ static void pstore_timefunc(struct timer_list *unused) ...@@ -901,5 +748,24 @@ static void pstore_timefunc(struct timer_list *unused)
jiffies + msecs_to_jiffies(pstore_update_ms)); jiffies + msecs_to_jiffies(pstore_update_ms));
} }
void __init pstore_choose_compression(void)
{
const struct pstore_zbackend *step;
if (!compress)
return;
for (step = zbackends; step->name; step++) {
if (!strcmp(compress, step->name)) {
zbackend = step;
pr_info("using %s compression\n", zbackend->name);
return;
}
}
}
module_param(compress, charp, 0444);
MODULE_PARM_DESC(compress, "Pstore compression to use");
module_param(backend, charp, 0444); module_param(backend, charp, 0444);
MODULE_PARM_DESC(backend, "Pstore backend to use"); MODULE_PARM_DESC(backend, "Pstore backend to use");
...@@ -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)
{ {
......
...@@ -98,24 +98,23 @@ static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz, ...@@ -98,24 +98,23 @@ static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
uint8_t *data, size_t len, uint8_t *ecc) uint8_t *data, size_t len, uint8_t *ecc)
{ {
int i; int i;
uint16_t par[prz->ecc_info.ecc_size];
/* Initialize the parity buffer */ /* Initialize the parity buffer */
memset(par, 0, sizeof(par)); memset(prz->ecc_info.par, 0,
encode_rs8(prz->rs_decoder, data, len, par, 0); prz->ecc_info.ecc_size * sizeof(prz->ecc_info.par[0]));
encode_rs8(prz->rs_decoder, data, len, prz->ecc_info.par, 0);
for (i = 0; i < prz->ecc_info.ecc_size; i++) for (i = 0; i < prz->ecc_info.ecc_size; i++)
ecc[i] = par[i]; ecc[i] = prz->ecc_info.par[i];
} }
static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz, static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
void *data, size_t len, uint8_t *ecc) void *data, size_t len, uint8_t *ecc)
{ {
int i; int i;
uint16_t par[prz->ecc_info.ecc_size];
for (i = 0; i < prz->ecc_info.ecc_size; i++) for (i = 0; i < prz->ecc_info.ecc_size; i++)
par[i] = ecc[i]; prz->ecc_info.par[i] = ecc[i];
return decode_rs8(prz->rs_decoder, data, par, len, return decode_rs8(prz->rs_decoder, data, prz->ecc_info.par, len,
NULL, 0, NULL, 0, NULL); NULL, 0, NULL, 0, NULL);
} }
...@@ -228,6 +227,15 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, ...@@ -228,6 +227,15 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
return -EINVAL; return -EINVAL;
} }
/* allocate workspace instead of using stack VLA */
prz->ecc_info.par = kmalloc_array(prz->ecc_info.ecc_size,
sizeof(*prz->ecc_info.par),
GFP_KERNEL);
if (!prz->ecc_info.par) {
pr_err("cannot allocate ECC parity workspace\n");
return -ENOMEM;
}
prz->corrected_bytes = 0; prz->corrected_bytes = 0;
prz->bad_blocks = 0; prz->bad_blocks = 0;
...@@ -514,6 +522,13 @@ void persistent_ram_free(struct persistent_ram_zone *prz) ...@@ -514,6 +522,13 @@ void persistent_ram_free(struct persistent_ram_zone *prz)
} }
prz->vaddr = NULL; prz->vaddr = NULL;
} }
if (prz->rs_decoder) {
free_rs(prz->rs_decoder);
prz->rs_decoder = NULL;
}
kfree(prz->ecc_info.par);
prz->ecc_info.par = NULL;
persistent_ram_free_old(prz); persistent_ram_free_old(prz);
kfree(prz); kfree(prz);
} }
......
...@@ -39,6 +39,7 @@ struct persistent_ram_ecc_info { ...@@ -39,6 +39,7 @@ struct persistent_ram_ecc_info {
int ecc_size; int ecc_size;
int symsize; int symsize;
int poly; int poly;
uint16_t *par;
}; };
struct persistent_ram_zone { struct persistent_ram_zone {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment