mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 21:02:19 +00:00
pstore updates for v6.6-rc1
- 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). -----BEGIN PGP SIGNATURE----- iQJKBAABCgA0FiEEpcP2jyKd1g9yPm4TiXL039xtwCYFAmTs5TUWHGtlZXNjb29r QGNocm9taXVtLm9yZwAKCRCJcvTf3G3AJkn8D/9mdBm32Wfx/if84YejxHJpzHmV nKPRgib89vNZdL5ORP02ZTonJBZn4NC7KtJfBHSfdoW1U+5GCC/cHOpECUHQui9Q CN22VFm37JdmBZq2+YmPug5y7z94wbFkD79otCR9VlMt5uwbNIGxUaI10fK2M97n 3avg/RZzz6kI9Y6BChZfBDLKXXi6ytnIRQOa9ZqZyDylN1nTLi8vqrxf0P8Am0jE 1s2GumYj54NuuNTdqvlz0XhTyCM5pk5omTqlq1VW9Trr0fLa2CLvEBWxWo8G7odC Yav5p8e0jX0GjDFM3NHPgRcXTcY0vkWGnJLdZGNyEkxPq96GH09j5rhFOIo9+KPz Y3fhYWzZyNWjy7YujWupDyL6lozWObhOcjBRnFmW7gJHjoO2G0GT2ufW2fb9cD4q fTGPiX2Fum1Zl6b0CXF+j4wDaazsBxGGAGzTqj7yp2Je0rPJPotd69q8LT2bbVcP ZahXJsFNn/YmVKv9MhNZjOuxGZoR4Cgco114V+sU5aYZMcZ68fQNzTzMydkbbdch SMapAV9a99H1D8ldT9dhm+HlKZFzIrOtBDrDoIbF4qQB8OWhjEK6Ot3oBbXvLl7w 72i1niDVRj+v/hUSc/7XYfZkUG7NYJQqXbaJp20LWvEs5OALdWRC3T6vXnvh53Qd 9ErztYLmF6k3W/h/xA== =bu02 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
5b07aaca18
@ -1,7 +1,6 @@
|
||||
# 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
|
||||
@ -22,99 +21,18 @@ config PSTORE_DEFAULT_KMSG_BYTES
|
||||
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"
|
||||
|
@ -54,7 +54,7 @@ static void free_pstore_private(struct pstore_private *private)
|
||||
if (!private)
|
||||
return;
|
||||
if (private->record) {
|
||||
kfree(private->record->buf);
|
||||
kvfree(private->record->buf);
|
||||
kfree(private->record->priv);
|
||||
kfree(private->record);
|
||||
}
|
||||
|
@ -14,24 +14,17 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kmsg_dump.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.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/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"
|
||||
|
||||
@ -80,12 +73,21 @@ static char *backend;
|
||||
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");
|
||||
|
||||
@ -94,16 +96,9 @@ unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES;
|
||||
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;
|
||||
|
||||
struct pstore_zbackend {
|
||||
int (*zbufsize)(size_t size);
|
||||
const char *name;
|
||||
};
|
||||
static void *compress_workspace;
|
||||
|
||||
static char *big_oops_buf;
|
||||
static size_t big_oops_buf_sz;
|
||||
|
||||
void pstore_set_kmsg_bytes(int bytes)
|
||||
{
|
||||
@ -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,
|
||||
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;
|
||||
int size;
|
||||
char *buf;
|
||||
|
||||
/* Skip if not built-in or compression backend not selected yet. */
|
||||
if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !zbackend)
|
||||
return;
|
||||
|
||||
/* 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);
|
||||
/* Skip if not built-in or compression disabled. */
|
||||
if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !compress ||
|
||||
!strcmp(compress, "none")) {
|
||||
compress = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
size = zbackend->zbufsize(psinfo->bufsize);
|
||||
if (size <= 0) {
|
||||
pr_err("Invalid compression size for %s: %d\n",
|
||||
zbackend->name, size);
|
||||
return;
|
||||
if (strcmp(compress, "deflate")) {
|
||||
pr_err("Unsupported compression '%s', falling back to deflate\n",
|
||||
compress);
|
||||
compress = "deflate";
|
||||
}
|
||||
|
||||
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) {
|
||||
pr_err("Failed %d byte compression buffer allocation for: %s\n",
|
||||
size, zbackend->name);
|
||||
pr_err("Failed %zu byte compression buffer allocation for: %s\n",
|
||||
psinfo->bufsize, compress);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = crypto_alloc_comp(zbackend->name, 0, 0);
|
||||
if (IS_ERR_OR_NULL(ctx)) {
|
||||
kfree(buf);
|
||||
pr_err("crypto_alloc_comp('%s') failed: %ld\n", zbackend->name,
|
||||
PTR_ERR(ctx));
|
||||
compress_workspace =
|
||||
vmalloc(zlib_deflate_workspacesize(MAX_WBITS, DEF_MEM_LEVEL));
|
||||
if (!compress_workspace) {
|
||||
pr_err("Failed to allocate zlib deflate workspace\n");
|
||||
kvfree(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* A non-NULL big_oops_buf indicates compression is available. */
|
||||
tfm = ctx;
|
||||
big_oops_buf_sz = size;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
kvfree(big_oops_buf);
|
||||
big_oops_buf = NULL;
|
||||
big_oops_buf_sz = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when compression fails, since the printk buffer
|
||||
* 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,
|
||||
@ -426,13 +304,8 @@ static void pstore_dump(struct kmsg_dumper *dumper,
|
||||
record.part = part;
|
||||
record.buf = psinfo->buf;
|
||||
|
||||
if (big_oops_buf) {
|
||||
dst = big_oops_buf;
|
||||
dst_size = big_oops_buf_sz;
|
||||
} else {
|
||||
dst = psinfo->buf;
|
||||
dst_size = psinfo->bufsize;
|
||||
}
|
||||
dst = big_oops_buf ?: psinfo->buf;
|
||||
dst_size = psinfo->bufsize;
|
||||
|
||||
/* Write dump header. */
|
||||
header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why,
|
||||
@ -453,8 +326,8 @@ static void pstore_dump(struct kmsg_dumper *dumper,
|
||||
record.compressed = true;
|
||||
record.size = zipped_len;
|
||||
} else {
|
||||
record.size = copy_kmsg_to_buffer(header_size,
|
||||
dump_size);
|
||||
record.size = header_size + dump_size;
|
||||
memcpy(psinfo->buf, dst, record.size);
|
||||
}
|
||||
} else {
|
||||
record.size = header_size + dump_size;
|
||||
@ -549,7 +422,7 @@ static int pstore_write_user_compat(struct pstore_record *record,
|
||||
if (record->buf)
|
||||
return -EINVAL;
|
||||
|
||||
record->buf = memdup_user(buf, record->size);
|
||||
record->buf = vmemdup_user(buf, record->size);
|
||||
if (IS_ERR(record->buf)) {
|
||||
ret = PTR_ERR(record->buf);
|
||||
goto out;
|
||||
@ -557,7 +430,7 @@ static int pstore_write_user_compat(struct pstore_record *record,
|
||||
|
||||
ret = record->psi->write(record);
|
||||
|
||||
kfree(record->buf);
|
||||
kvfree(record->buf);
|
||||
out:
|
||||
record->buf = NULL;
|
||||
|
||||
@ -681,7 +554,8 @@ void pstore_unregister(struct pstore_info *psi)
|
||||
}
|
||||
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;
|
||||
@ -697,40 +571,50 @@ static void decompress_record(struct pstore_record *record)
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
unzipped_len = big_oops_buf_sz;
|
||||
workspace = kmalloc(unzipped_len + record->ecc_notice_size,
|
||||
GFP_KERNEL);
|
||||
workspace = kvzalloc(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);
|
||||
kfree(workspace);
|
||||
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);
|
||||
kvfree(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);
|
||||
|
||||
/* Copy decompressed contents into an minimum-sized allocation. */
|
||||
unzipped = kmemdup(workspace, unzipped_len + record->ecc_notice_size,
|
||||
GFP_KERNEL);
|
||||
kfree(workspace);
|
||||
unzipped = kvmemdup(workspace, unzipped_len + record->ecc_notice_size,
|
||||
GFP_KERNEL);
|
||||
kvfree(workspace);
|
||||
if (!unzipped)
|
||||
return;
|
||||
|
||||
/* Swap out compressed contents with decompressed contents. */
|
||||
kfree(record->buf);
|
||||
kvfree(record->buf);
|
||||
record->buf = unzipped;
|
||||
record->size = unzipped_len;
|
||||
record->compressed = false;
|
||||
@ -747,10 +631,17 @@ void pstore_get_backend_records(struct pstore_info *psi,
|
||||
{
|
||||
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;
|
||||
@ -779,11 +670,11 @@ void pstore_get_backend_records(struct pstore_info *psi,
|
||||
break;
|
||||
}
|
||||
|
||||
decompress_record(record);
|
||||
decompress_record(record, &zstream);
|
||||
rc = pstore_mkfile(root, record);
|
||||
if (rc) {
|
||||
/* pstore_mkfile() did not take record, so free it. */
|
||||
kfree(record->buf);
|
||||
kvfree(record->buf);
|
||||
kfree(record->priv);
|
||||
kfree(record);
|
||||
if (rc != -EEXIST || !quiet)
|
||||
@ -795,6 +686,12 @@ void pstore_get_backend_records(struct pstore_info *psi,
|
||||
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);
|
||||
@ -818,34 +715,10 @@ static void pstore_timefunc(struct timer_list *unused)
|
||||
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)
|
||||
{
|
||||
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();
|
||||
if (ret)
|
||||
free_buf_for_compression();
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "ram_internal.h"
|
||||
@ -268,7 +269,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
|
||||
/* ECC correction notice */
|
||||
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) {
|
||||
size = -ENOMEM;
|
||||
goto out;
|
||||
@ -282,7 +283,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
|
||||
|
||||
out:
|
||||
if (free_prz) {
|
||||
kfree(prz->old_log);
|
||||
kvfree(prz->old_log);
|
||||
kfree(prz);
|
||||
}
|
||||
|
||||
@ -833,7 +834,7 @@ static int ramoops_probe(struct platform_device *pdev)
|
||||
*/
|
||||
if (cxt->pstore.flags & PSTORE_FLAGS_DMESG) {
|
||||
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) {
|
||||
pr_err("cannot allocate pstore crash dump buffer\n");
|
||||
err = -ENOMEM;
|
||||
@ -866,7 +867,7 @@ static int ramoops_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
fail_buf:
|
||||
kfree(cxt->pstore.buf);
|
||||
kvfree(cxt->pstore.buf);
|
||||
fail_clear:
|
||||
cxt->pstore.bufsize = 0;
|
||||
fail_init:
|
||||
@ -881,7 +882,7 @@ static void ramoops_remove(struct platform_device *pdev)
|
||||
|
||||
pstore_unregister(&cxt->pstore);
|
||||
|
||||
kfree(cxt->pstore.buf);
|
||||
kvfree(cxt->pstore.buf);
|
||||
cxt->pstore.bufsize = 0;
|
||||
|
||||
ramoops_free_przs(cxt);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include "ram_internal.h"
|
||||
@ -24,12 +25,10 @@
|
||||
/**
|
||||
* struct persistent_ram_buffer - persistent circular RAM buffer
|
||||
*
|
||||
* @sig:
|
||||
* signature to indicate header (PERSISTENT_RAM_SIG xor PRZ-type value)
|
||||
* @start:
|
||||
* offset into @data where the beginning of the stored bytes begin
|
||||
* @size:
|
||||
* number of valid bytes stored in @data
|
||||
* @sig: Signature to indicate header (PERSISTENT_RAM_SIG xor PRZ-type value)
|
||||
* @start: First valid byte in the buffer.
|
||||
* @size: Number of valid bytes in the buffer.
|
||||
* @data: The contents of the buffer.
|
||||
*/
|
||||
struct persistent_ram_buffer {
|
||||
uint32_t sig;
|
||||
@ -301,7 +300,7 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz)
|
||||
|
||||
if (!prz->old_log) {
|
||||
persistent_ram_ecc_old(prz);
|
||||
prz->old_log = kmalloc(size, GFP_KERNEL);
|
||||
prz->old_log = kvzalloc(size, GFP_KERNEL);
|
||||
}
|
||||
if (!prz->old_log) {
|
||||
pr_err("failed to allocate buffer\n");
|
||||
@ -385,7 +384,7 @@ void *persistent_ram_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_size = 0;
|
||||
}
|
||||
@ -519,7 +518,7 @@ static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
|
||||
sig ^= PERSISTENT_RAM_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");
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user