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:
Linus Torvalds 2023-08-28 12:36:04 -07:00
commit 5b07aaca18
5 changed files with 137 additions and 346 deletions

View File

@ -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"

View File

@ -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);
}

View File

@ -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();

View File

@ -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);

View File

@ -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;
}