Commit 5b07aaca authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pstore-v6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull pstore updates from Kees Cook:

 - Greatly simplify compression support (Ard Biesheuvel)

 - Avoid crashes for corrupted offsets when prz size is 0 (Enlin Mu)

 - Expand range of usable record sizes (Yuxiao Zhang)

 - Fix kernel-doc warning (Matthew Wilcox)

* tag 'pstore-v6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  pstore: Fix kernel-doc warning
  pstore: Support record sizes larger than kmalloc() limit
  pstore/ram: Check start of empty przs during init
  pstore: Replace crypto API compression with zlib_deflate library calls
  pstore: Remove worst-case compression size logic
parents 547635c6 af58740d
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
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
...@@ -22,99 +21,18 @@ config PSTORE_DEFAULT_KMSG_BYTES ...@@ -22,99 +21,18 @@ config PSTORE_DEFAULT_KMSG_BYTES
Defines default size of pstore kernel log storage. Defines default size of pstore kernel log storage.
Can be enlarged if needed, not recommended to shrink it. 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 config PSTORE_COMPRESS
def_bool y bool "Pstore compression (deflate)"
depends on PSTORE depends on PSTORE
depends on PSTORE_DEFLATE_COMPRESS || PSTORE_LZO_COMPRESS || \ select ZLIB_INFLATE
PSTORE_LZ4_COMPRESS || PSTORE_LZ4HC_COMPRESS || \ select ZLIB_DEFLATE
PSTORE_842_COMPRESS || PSTORE_ZSTD_COMPRESS default y
choice
prompt "Default pstore compression algorithm"
depends on PSTORE_COMPRESS
help help
This option chooses the default active compression algorithm. Whether pstore records should be compressed before being written to
This change be changed at boot with "pstore.compress=..." on the backing store. This is implemented using the zlib 'deflate'
the kernel command line. algorithm, using the library implementation instead of using the full
blown crypto API. This reduces the risk of secondary oopses or other
Currently, pstore has support for 6 compression algorithms: problems while pstore is recording panic metadata.
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
config PSTORE_CONSOLE config PSTORE_CONSOLE
bool "Log kernel console messages" bool "Log kernel console messages"
......
...@@ -54,7 +54,7 @@ static void free_pstore_private(struct pstore_private *private) ...@@ -54,7 +54,7 @@ static void free_pstore_private(struct pstore_private *private)
if (!private) if (!private)
return; return;
if (private->record) { if (private->record) {
kfree(private->record->buf); kvfree(private->record->buf);
kfree(private->record->priv); kfree(private->record->priv);
kfree(private->record); kfree(private->record);
} }
......
...@@ -14,24 +14,17 @@ ...@@ -14,24 +14,17 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kmsg_dump.h> #include <linux/kmsg_dump.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pstore.h> #include <linux/pstore.h>
#if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
#include <linux/lzo.h>
#endif
#if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS) || IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
#include <linux/lz4.h>
#endif
#if IS_ENABLED(CONFIG_PSTORE_ZSTD_COMPRESS)
#include <linux/zstd.h>
#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>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/zlib.h>
#include "internal.h" #include "internal.h"
...@@ -80,12 +73,21 @@ static char *backend; ...@@ -80,12 +73,21 @@ static char *backend;
module_param(backend, charp, 0444); module_param(backend, charp, 0444);
MODULE_PARM_DESC(backend, "specific backend to use"); MODULE_PARM_DESC(backend, "specific backend to use");
static char *compress = /*
#ifdef CONFIG_PSTORE_COMPRESS_DEFAULT * pstore no longer implements compression via the crypto API, and only
CONFIG_PSTORE_COMPRESS_DEFAULT; * supports zlib deflate compression implemented using the zlib library
#else * interface. This removes additional complexity which is hard to justify for a
NULL; * diagnostic facility that has to operate in conditions where the system may
#endif * 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_param(compress, charp, 0444);
MODULE_PARM_DESC(compress, "compression to use"); MODULE_PARM_DESC(compress, "compression to use");
...@@ -94,16 +96,9 @@ unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES; ...@@ -94,16 +96,9 @@ unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES;
module_param(kmsg_bytes, ulong, 0444); module_param(kmsg_bytes, ulong, 0444);
MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)"); MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");
/* Compression parameters */ static void *compress_workspace;
static struct crypto_comp *tfm;
struct pstore_zbackend {
int (*zbufsize)(size_t size);
const char *name;
};
static char *big_oops_buf; static char *big_oops_buf;
static size_t big_oops_buf_sz;
void pstore_set_kmsg_bytes(int bytes) void pstore_set_kmsg_bytes(int bytes)
{ {
...@@ -168,206 +163,89 @@ static bool pstore_cannot_block_path(enum kmsg_dump_reason reason) ...@@ -168,206 +163,89 @@ static bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
} }
} }
#if IS_ENABLED(CONFIG_PSTORE_DEFLATE_COMPRESS)
static int zbufsize_deflate(size_t size)
{
size_t cmpr;
switch (size) {
/* buffer range for efivars */
case 1000 ... 2000:
cmpr = 56;
break;
case 2001 ... 3000:
cmpr = 54;
break;
case 3001 ... 3999:
cmpr = 52;
break;
/* buffer range for nvram, erst */
case 4000 ... 10000:
cmpr = 45;
break;
default:
cmpr = 60;
break;
}
return (size * 100) / cmpr;
}
#endif
#if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
static int zbufsize_lzo(size_t size)
{
return lzo1x_worst_compress(size);
}
#endif
#if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS) || IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
static int zbufsize_lz4(size_t size)
{
return LZ4_compressBound(size);
}
#endif
#if IS_ENABLED(CONFIG_PSTORE_842_COMPRESS)
static int zbufsize_842(size_t size)
{
return size;
}
#endif
#if IS_ENABLED(CONFIG_PSTORE_ZSTD_COMPRESS)
static int zbufsize_zstd(size_t size)
{
return zstd_compress_bound(size);
}
#endif
static const struct pstore_zbackend *zbackend __ro_after_init;
static const struct pstore_zbackend zbackends[] = {
#if IS_ENABLED(CONFIG_PSTORE_DEFLATE_COMPRESS)
{
.zbufsize = zbufsize_deflate,
.name = "deflate",
},
#endif
#if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
{
.zbufsize = zbufsize_lzo,
.name = "lzo",
},
#endif
#if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS)
{
.zbufsize = zbufsize_lz4,
.name = "lz4",
},
#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
#if IS_ENABLED(CONFIG_PSTORE_ZSTD_COMPRESS)
{
.zbufsize = zbufsize_zstd,
.name = "zstd",
},
#endif
{ }
};
static int pstore_compress(const void *in, void *out, static int pstore_compress(const void *in, void *out,
unsigned int inlen, unsigned int outlen) 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; int ret;
if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS)) if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS))
return -EINVAL; return -EINVAL;
ret = crypto_comp_compress(tfm, in, inlen, out, &outlen); ret = zlib_deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
if (ret) { -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
pr_err("crypto_comp_compress failed, ret = %d!\n", ret); if (ret != Z_OK)
return ret; return -EINVAL;
}
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 outlen; return zstream.total_out;
} }
static void allocate_buf_for_compression(void) static void allocate_buf_for_compression(void)
{ {
struct crypto_comp *ctx;
int size;
char *buf; char *buf;
/* Skip if not built-in or compression backend not selected yet. */ /* Skip if not built-in or compression disabled. */
if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !zbackend) if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !compress ||
return; !strcmp(compress, "none")) {
compress = NULL;
/* Skip if no pstore backend yet or compression init already done. */
if (!psinfo || tfm)
return;
if (!crypto_has_comp(zbackend->name, 0, 0)) {
pr_err("Unknown compression: %s\n", zbackend->name);
return; return;
} }
size = zbackend->zbufsize(psinfo->bufsize); if (strcmp(compress, "deflate")) {
if (size <= 0) { pr_err("Unsupported compression '%s', falling back to deflate\n",
pr_err("Invalid compression size for %s: %d\n", compress);
zbackend->name, size); compress = "deflate";
return;
} }
buf = kmalloc(size, GFP_KERNEL); /*
* The compression buffer only needs to be as large as the maximum
* uncompressed record size, since any record that would be expanded by
* compression is just stored uncompressed.
*/
buf = kvzalloc(psinfo->bufsize, GFP_KERNEL);
if (!buf) { if (!buf) {
pr_err("Failed %d byte compression buffer allocation for: %s\n", pr_err("Failed %zu byte compression buffer allocation for: %s\n",
size, zbackend->name); psinfo->bufsize, compress);
return; return;
} }
ctx = crypto_alloc_comp(zbackend->name, 0, 0); compress_workspace =
if (IS_ERR_OR_NULL(ctx)) { vmalloc(zlib_deflate_workspacesize(MAX_WBITS, DEF_MEM_LEVEL));
kfree(buf); if (!compress_workspace) {
pr_err("crypto_alloc_comp('%s') failed: %ld\n", zbackend->name, pr_err("Failed to allocate zlib deflate workspace\n");
PTR_ERR(ctx)); kvfree(buf);
return; return;
} }
/* A non-NULL big_oops_buf indicates compression is available. */ /* A non-NULL big_oops_buf indicates compression is available. */
tfm = ctx;
big_oops_buf_sz = size;
big_oops_buf = buf; big_oops_buf = buf;
pr_info("Using crash dump compression: %s\n", zbackend->name); pr_info("Using crash dump compression: %s\n", compress);
} }
static void free_buf_for_compression(void) static void free_buf_for_compression(void)
{ {
if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && tfm) { if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && compress_workspace) {
crypto_free_comp(tfm); vfree(compress_workspace);
tfm = NULL; compress_workspace = NULL;
} }
kfree(big_oops_buf);
big_oops_buf = NULL;
big_oops_buf_sz = 0;
}
/* kvfree(big_oops_buf);
* Called when compression fails, since the printk buffer big_oops_buf = NULL;
* would be fetched for compression calling it again when
* compression fails would have moved the iterator of
* printk buffer which results in fetching old contents.
* Copy the recent messages from big_oops_buf to psinfo->buf
*/
static size_t copy_kmsg_to_buffer(int hsize, size_t len)
{
size_t total_len;
size_t diff;
total_len = hsize + len;
if (total_len > psinfo->bufsize) {
diff = total_len - psinfo->bufsize + hsize;
memcpy(psinfo->buf, big_oops_buf, hsize);
memcpy(psinfo->buf + hsize, big_oops_buf + diff,
psinfo->bufsize - hsize);
total_len = psinfo->bufsize;
} else
memcpy(psinfo->buf, big_oops_buf, total_len);
return total_len;
} }
void pstore_record_init(struct pstore_record *record, void pstore_record_init(struct pstore_record *record,
...@@ -426,13 +304,8 @@ static void pstore_dump(struct kmsg_dumper *dumper, ...@@ -426,13 +304,8 @@ static void pstore_dump(struct kmsg_dumper *dumper,
record.part = part; record.part = part;
record.buf = psinfo->buf; record.buf = psinfo->buf;
if (big_oops_buf) { dst = big_oops_buf ?: psinfo->buf;
dst = big_oops_buf; dst_size = psinfo->bufsize;
dst_size = big_oops_buf_sz;
} else {
dst = psinfo->buf;
dst_size = psinfo->bufsize;
}
/* Write dump header. */ /* Write dump header. */
header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why, header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why,
...@@ -453,8 +326,8 @@ static void pstore_dump(struct kmsg_dumper *dumper, ...@@ -453,8 +326,8 @@ static void pstore_dump(struct kmsg_dumper *dumper,
record.compressed = true; record.compressed = true;
record.size = zipped_len; record.size = zipped_len;
} else { } else {
record.size = copy_kmsg_to_buffer(header_size, record.size = header_size + dump_size;
dump_size); memcpy(psinfo->buf, dst, record.size);
} }
} else { } else {
record.size = header_size + dump_size; record.size = header_size + dump_size;
...@@ -549,7 +422,7 @@ static int pstore_write_user_compat(struct pstore_record *record, ...@@ -549,7 +422,7 @@ static int pstore_write_user_compat(struct pstore_record *record,
if (record->buf) if (record->buf)
return -EINVAL; return -EINVAL;
record->buf = memdup_user(buf, record->size); record->buf = vmemdup_user(buf, record->size);
if (IS_ERR(record->buf)) { if (IS_ERR(record->buf)) {
ret = PTR_ERR(record->buf); ret = PTR_ERR(record->buf);
goto out; goto out;
...@@ -557,7 +430,7 @@ static int pstore_write_user_compat(struct pstore_record *record, ...@@ -557,7 +430,7 @@ static int pstore_write_user_compat(struct pstore_record *record,
ret = record->psi->write(record); ret = record->psi->write(record);
kfree(record->buf); kvfree(record->buf);
out: out:
record->buf = NULL; record->buf = NULL;
...@@ -681,7 +554,8 @@ void pstore_unregister(struct pstore_info *psi) ...@@ -681,7 +554,8 @@ void pstore_unregister(struct pstore_info *psi)
} }
EXPORT_SYMBOL_GPL(pstore_unregister); 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 ret;
int unzipped_len; int unzipped_len;
...@@ -697,40 +571,50 @@ static void decompress_record(struct pstore_record *record) ...@@ -697,40 +571,50 @@ static void decompress_record(struct pstore_record *record)
} }
/* Missing compression buffer means compression was not initialized. */ /* Missing compression buffer means compression was not initialized. */
if (!big_oops_buf) { if (!zstream->workspace) {
pr_warn("no decompression method initialized!\n"); pr_warn("no decompression method initialized!\n");
return; 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. */ /* Allocate enough space to hold max decompression and ECC. */
unzipped_len = big_oops_buf_sz; workspace = kvzalloc(psinfo->bufsize + record->ecc_notice_size,
workspace = kmalloc(unzipped_len + record->ecc_notice_size, GFP_KERNEL);
GFP_KERNEL);
if (!workspace) if (!workspace)
return; return;
/* After decompression "unzipped_len" is almost certainly smaller. */ zstream->next_in = record->buf;
ret = crypto_comp_decompress(tfm, record->buf, record->size, zstream->avail_in = record->size;
workspace, &unzipped_len); zstream->next_out = workspace;
if (ret) { zstream->avail_out = psinfo->bufsize;
pr_err("crypto_comp_decompress failed, ret = %d!\n", ret);
kfree(workspace); ret = zlib_inflate(zstream, Z_FINISH);
if (ret != Z_STREAM_END) {
pr_err("zlib_inflate() failed, ret = %d!\n", ret);
kvfree(workspace);
return; return;
} }
unzipped_len = zstream->total_out;
/* Append ECC notice to decompressed buffer. */ /* Append ECC notice to decompressed buffer. */
memcpy(workspace + unzipped_len, record->buf + record->size, memcpy(workspace + unzipped_len, record->buf + record->size,
record->ecc_notice_size); record->ecc_notice_size);
/* Copy decompressed contents into an minimum-sized allocation. */ /* Copy decompressed contents into an minimum-sized allocation. */
unzipped = kmemdup(workspace, unzipped_len + record->ecc_notice_size, unzipped = kvmemdup(workspace, unzipped_len + record->ecc_notice_size,
GFP_KERNEL); GFP_KERNEL);
kfree(workspace); kvfree(workspace);
if (!unzipped) if (!unzipped)
return; return;
/* Swap out compressed contents with decompressed contents. */ /* Swap out compressed contents with decompressed contents. */
kfree(record->buf); kvfree(record->buf);
record->buf = unzipped; record->buf = unzipped;
record->size = unzipped_len; record->size = unzipped_len;
record->compressed = false; record->compressed = false;
...@@ -747,10 +631,17 @@ void pstore_get_backend_records(struct pstore_info *psi, ...@@ -747,10 +631,17 @@ void pstore_get_backend_records(struct pstore_info *psi,
{ {
int failed = 0; int failed = 0;
unsigned int stop_loop = 65536; unsigned int stop_loop = 65536;
struct z_stream_s zstream = {};
if (!psi || !root) if (!psi || !root)
return; 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); mutex_lock(&psi->read_mutex);
if (psi->open && psi->open(psi)) if (psi->open && psi->open(psi))
goto out; goto out;
...@@ -779,11 +670,11 @@ void pstore_get_backend_records(struct pstore_info *psi, ...@@ -779,11 +670,11 @@ void pstore_get_backend_records(struct pstore_info *psi,
break; break;
} }
decompress_record(record); decompress_record(record, &zstream);
rc = pstore_mkfile(root, record); rc = pstore_mkfile(root, record);
if (rc) { if (rc) {
/* pstore_mkfile() did not take record, so free it. */ /* pstore_mkfile() did not take record, so free it. */
kfree(record->buf); kvfree(record->buf);
kfree(record->priv); kfree(record->priv);
kfree(record); kfree(record);
if (rc != -EEXIST || !quiet) if (rc != -EEXIST || !quiet)
...@@ -795,6 +686,12 @@ void pstore_get_backend_records(struct pstore_info *psi, ...@@ -795,6 +686,12 @@ void pstore_get_backend_records(struct pstore_info *psi,
out: out:
mutex_unlock(&psi->read_mutex); 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) if (failed)
pr_warn("failed to create %d record(s) from '%s'\n", pr_warn("failed to create %d record(s) from '%s'\n",
failed, psi->name); failed, psi->name);
...@@ -818,34 +715,10 @@ static void pstore_timefunc(struct timer_list *unused) ...@@ -818,34 +715,10 @@ static void pstore_timefunc(struct timer_list *unused)
pstore_timer_kick(); pstore_timer_kick();
} }
static 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;
return;
}
}
}
static int __init pstore_init(void) static int __init pstore_init(void)
{ {
int ret; int ret;
pstore_choose_compression();
/*
* 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(); ret = pstore_init_fs();
if (ret) if (ret)
free_buf_for_compression(); free_buf_for_compression();
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/mm.h>
#include "internal.h" #include "internal.h"
#include "ram_internal.h" #include "ram_internal.h"
...@@ -268,7 +269,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record) ...@@ -268,7 +269,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
/* ECC correction notice */ /* ECC correction notice */
record->ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0); record->ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
record->buf = kmalloc(size + record->ecc_notice_size + 1, GFP_KERNEL); record->buf = kvzalloc(size + record->ecc_notice_size + 1, GFP_KERNEL);
if (record->buf == NULL) { if (record->buf == NULL) {
size = -ENOMEM; size = -ENOMEM;
goto out; goto out;
...@@ -282,7 +283,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record) ...@@ -282,7 +283,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
out: out:
if (free_prz) { if (free_prz) {
kfree(prz->old_log); kvfree(prz->old_log);
kfree(prz); kfree(prz);
} }
...@@ -833,7 +834,7 @@ static int ramoops_probe(struct platform_device *pdev) ...@@ -833,7 +834,7 @@ static int ramoops_probe(struct platform_device *pdev)
*/ */
if (cxt->pstore.flags & PSTORE_FLAGS_DMESG) { if (cxt->pstore.flags & PSTORE_FLAGS_DMESG) {
cxt->pstore.bufsize = cxt->dprzs[0]->buffer_size; cxt->pstore.bufsize = cxt->dprzs[0]->buffer_size;
cxt->pstore.buf = kzalloc(cxt->pstore.bufsize, GFP_KERNEL); cxt->pstore.buf = kvzalloc(cxt->pstore.bufsize, GFP_KERNEL);
if (!cxt->pstore.buf) { if (!cxt->pstore.buf) {
pr_err("cannot allocate pstore crash dump buffer\n"); pr_err("cannot allocate pstore crash dump buffer\n");
err = -ENOMEM; err = -ENOMEM;
...@@ -866,7 +867,7 @@ static int ramoops_probe(struct platform_device *pdev) ...@@ -866,7 +867,7 @@ static int ramoops_probe(struct platform_device *pdev)
return 0; return 0;
fail_buf: fail_buf:
kfree(cxt->pstore.buf); kvfree(cxt->pstore.buf);
fail_clear: fail_clear:
cxt->pstore.bufsize = 0; cxt->pstore.bufsize = 0;
fail_init: fail_init:
...@@ -881,7 +882,7 @@ static void ramoops_remove(struct platform_device *pdev) ...@@ -881,7 +882,7 @@ static void ramoops_remove(struct platform_device *pdev)
pstore_unregister(&cxt->pstore); pstore_unregister(&cxt->pstore);
kfree(cxt->pstore.buf); kvfree(cxt->pstore.buf);
cxt->pstore.bufsize = 0; cxt->pstore.bufsize = 0;
ramoops_free_przs(cxt); ramoops_free_przs(cxt);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/mm.h>
#include <asm/page.h> #include <asm/page.h>
#include "ram_internal.h" #include "ram_internal.h"
...@@ -24,12 +25,10 @@ ...@@ -24,12 +25,10 @@
/** /**
* struct persistent_ram_buffer - persistent circular RAM buffer * struct persistent_ram_buffer - persistent circular RAM buffer
* *
* @sig: * @sig: Signature to indicate header (PERSISTENT_RAM_SIG xor PRZ-type value)
* signature to indicate header (PERSISTENT_RAM_SIG xor PRZ-type value) * @start: First valid byte in the buffer.
* @start: * @size: Number of valid bytes in the buffer.
* offset into @data where the beginning of the stored bytes begin * @data: The contents of the buffer.
* @size:
* number of valid bytes stored in @data
*/ */
struct persistent_ram_buffer { struct persistent_ram_buffer {
uint32_t sig; uint32_t sig;
...@@ -301,7 +300,7 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz) ...@@ -301,7 +300,7 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz)
if (!prz->old_log) { if (!prz->old_log) {
persistent_ram_ecc_old(prz); persistent_ram_ecc_old(prz);
prz->old_log = kmalloc(size, GFP_KERNEL); prz->old_log = kvzalloc(size, GFP_KERNEL);
} }
if (!prz->old_log) { if (!prz->old_log) {
pr_err("failed to allocate buffer\n"); pr_err("failed to allocate buffer\n");
...@@ -385,7 +384,7 @@ void *persistent_ram_old(struct persistent_ram_zone *prz) ...@@ -385,7 +384,7 @@ void *persistent_ram_old(struct persistent_ram_zone *prz)
void persistent_ram_free_old(struct persistent_ram_zone *prz) void persistent_ram_free_old(struct persistent_ram_zone *prz)
{ {
kfree(prz->old_log); kvfree(prz->old_log);
prz->old_log = NULL; prz->old_log = NULL;
prz->old_log_size = 0; prz->old_log_size = 0;
} }
...@@ -519,7 +518,7 @@ static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig, ...@@ -519,7 +518,7 @@ static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
sig ^= PERSISTENT_RAM_SIG; sig ^= PERSISTENT_RAM_SIG;
if (prz->buffer->sig == sig) { if (prz->buffer->sig == sig) {
if (buffer_size(prz) == 0) { if (buffer_size(prz) == 0 && buffer_start(prz) == 0) {
pr_debug("found existing empty buffer\n"); pr_debug("found existing empty buffer\n");
return 0; return 0;
} }
......
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