static int erst_close_pstore(struct pstore_info *psi);
static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
struct timespec *time, char **buf,
- bool *compressed, struct pstore_info *psi);
+ bool *compressed, ssize_t *ecc_notice_size,
+ struct pstore_info *psi);
static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
u64 *id, unsigned int part, int count, bool compressed,
size_t size, struct pstore_info *psi);
static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
struct timespec *time, char **buf,
- bool *compressed, struct pstore_info *psi)
+ bool *compressed, ssize_t *ecc_notice_size,
+ struct pstore_info *psi)
{
int rc;
ssize_t len = 0;
memcpy(*buf, rcd->data, len - sizeof(*rcd));
*id = record_id;
*compressed = false;
+ *ecc_notice_size = 0;
if (uuid_le_cmp(rcd->sec_hdr.section_type,
CPER_SECTION_TYPE_DMESG_Z) == 0) {
*type = PSTORE_TYPE_DMESG;
int *count;
struct timespec *timespec;
bool *compressed;
+ ssize_t *ecc_notice_size;
char **buf;
};
*cb_data->compressed = true;
else
*cb_data->compressed = false;
+ *cb_data->ecc_notice_size = 0;
} else if (sscanf(name, "dump-type%u-%u-%d-%lu",
cb_data->type, &part, &cnt, &time) == 4) {
*cb_data->id = generic_id(time, part, cnt);
cb_data->timespec->tv_sec = time;
cb_data->timespec->tv_nsec = 0;
*cb_data->compressed = false;
+ *cb_data->ecc_notice_size = 0;
} else if (sscanf(name, "dump-type%u-%u-%lu",
cb_data->type, &part, &time) == 3) {
/*
cb_data->timespec->tv_sec = time;
cb_data->timespec->tv_nsec = 0;
*cb_data->compressed = false;
+ *cb_data->ecc_notice_size = 0;
} else
return 0;
static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
int *count, struct timespec *timespec,
char **buf, bool *compressed,
+ ssize_t *ecc_notice_size,
struct pstore_info *psi)
{
struct pstore_read_data data;
data.count = count;
data.timespec = timespec;
data.compressed = compressed;
+ data.ecc_notice_size = ecc_notice_size;
data.buf = buf;
*data.buf = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL);
#include <linux/console.h>
#include <linux/module.h>
#include <linux/pstore.h>
+#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
#include <linux/zlib.h>
+#endif
+#ifdef CONFIG_PSTORE_LZO_COMPRESS
+#include <linux/lzo.h>
+#endif
+#ifdef CONFIG_PSTORE_LZ4_COMPRESS
+#include <linux/lz4.h>
+#endif
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/slab.h>
static char *backend;
/* Compression parameters */
+#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
#define COMPR_LEVEL 6
#define WINDOW_BITS 12
#define MEM_LEVEL 4
static struct z_stream_s stream;
+#else
+static unsigned char *workspace;
+#endif
+
+struct pstore_zbackend {
+ int (*compress)(const void *in, void *out, size_t inlen, size_t outlen);
+ int (*decompress)(void *in, void *out, size_t inlen, size_t outlen);
+ void (*allocate)(void);
+ void (*free)(void);
+
+ const char *name;
+};
static char *big_oops_buf;
static size_t big_oops_buf_sz;
}
EXPORT_SYMBOL_GPL(pstore_cannot_block_path);
+#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
/* Derived from logfs_compress() */
-static int pstore_compress(const void *in, void *out, size_t inlen,
- size_t outlen)
+static int compress_zlib(const void *in, void *out, size_t inlen, size_t outlen)
{
int err, ret;
}
/* Derived from logfs_uncompress */
-static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen)
+static int decompress_zlib(void *in, void *out, size_t inlen, size_t outlen)
{
int err, ret;
return ret;
}
-static void allocate_buf_for_compression(void)
+static void allocate_zlib(void)
{
size_t size;
size_t cmpr;
}
-static void free_buf_for_compression(void)
+static void free_zlib(void)
{
kfree(stream.workspace);
stream.workspace = NULL;
kfree(big_oops_buf);
big_oops_buf = NULL;
+ big_oops_buf_sz = 0;
+}
+
+static struct pstore_zbackend backend_zlib = {
+ .compress = compress_zlib,
+ .decompress = decompress_zlib,
+ .allocate = allocate_zlib,
+ .free = free_zlib,
+ .name = "zlib",
+};
+#endif
+
+#ifdef CONFIG_PSTORE_LZO_COMPRESS
+static int compress_lzo(const void *in, void *out, size_t inlen, size_t outlen)
+{
+ int ret;
+
+ ret = lzo1x_1_compress(in, inlen, out, &outlen, workspace);
+ if (ret != LZO_E_OK) {
+ pr_err("lzo_compress error, ret = %d!\n", ret);
+ return -EIO;
+ }
+
+ return outlen;
+}
+
+static int decompress_lzo(void *in, void *out, size_t inlen, size_t outlen)
+{
+ int ret;
+
+ ret = lzo1x_decompress_safe(in, inlen, out, &outlen);
+ if (ret != LZO_E_OK) {
+ pr_err("lzo_decompress error, ret = %d!\n", ret);
+ return -EIO;
+ }
+
+ return outlen;
+}
+
+static void allocate_lzo(void)
+{
+ big_oops_buf_sz = lzo1x_worst_compress(psinfo->bufsize);
+ big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
+ if (big_oops_buf) {
+ workspace = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+ if (!workspace) {
+ pr_err("No memory for compression workspace; skipping compression\n");
+ kfree(big_oops_buf);
+ big_oops_buf = NULL;
+ }
+ } else {
+ pr_err("No memory for uncompressed data; skipping compression\n");
+ workspace = NULL;
+ }
+}
+
+static void free_lzo(void)
+{
+ kfree(workspace);
+ kfree(big_oops_buf);
+ big_oops_buf = NULL;
+ big_oops_buf_sz = 0;
+}
+
+static struct pstore_zbackend backend_lzo = {
+ .compress = compress_lzo,
+ .decompress = decompress_lzo,
+ .allocate = allocate_lzo,
+ .free = free_lzo,
+ .name = "lzo",
+};
+#endif
+
+#ifdef CONFIG_PSTORE_LZ4_COMPRESS
+static int compress_lz4(const void *in, void *out, size_t inlen, size_t outlen)
+{
+ int ret;
+
+ ret = lz4_compress(in, inlen, out, &outlen, workspace);
+ if (ret) {
+ pr_err("lz4_compress error, ret = %d!\n", ret);
+ return -EIO;
+ }
+
+ return outlen;
+}
+
+static int decompress_lz4(void *in, void *out, size_t inlen, size_t outlen)
+{
+ int ret;
+
+ ret = lz4_decompress_unknownoutputsize(in, inlen, out, &outlen);
+ if (ret) {
+ pr_err("lz4_decompress error, ret = %d!\n", ret);
+ return -EIO;
+ }
+
+ return outlen;
+}
+
+static void allocate_lz4(void)
+{
+ big_oops_buf_sz = lz4_compressbound(psinfo->bufsize);
+ big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
+ if (big_oops_buf) {
+ workspace = kmalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
+ if (!workspace) {
+ pr_err("No memory for compression workspace; skipping compression\n");
+ kfree(big_oops_buf);
+ big_oops_buf = NULL;
+ }
+ } else {
+ pr_err("No memory for uncompressed data; skipping compression\n");
+ workspace = NULL;
+ }
+}
+
+static void free_lz4(void)
+{
+ kfree(workspace);
+ kfree(big_oops_buf);
+ big_oops_buf = NULL;
+ big_oops_buf_sz = 0;
+}
+
+static struct pstore_zbackend backend_lz4 = {
+ .compress = compress_lz4,
+ .decompress = decompress_lz4,
+ .allocate = allocate_lz4,
+ .free = free_lz4,
+ .name = "lz4",
+};
+#endif
+
+static 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,
+ size_t inlen, size_t outlen)
+{
+ 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)
+{
+ if (zbackend)
+ return zbackend->decompress(in, out, inlen, outlen);
+ else
+ return -EIO;
+}
+
+static void allocate_buf_for_compression(void)
+{
+ if (zbackend) {
+ pr_info("using %s compression\n", zbackend->name);
+ zbackend->allocate();
+ } else {
+ pr_err("allocate compression buffer error!\n");
+ }
+}
+
+static void free_buf_for_compression(void)
+{
+ if (zbackend)
+ zbackend->free();
+ else
+ pr_err("free compression buffer error!\n");
}
/*
int failed = 0, rc;
bool compressed;
int unzipped_len = -1;
+ ssize_t ecc_notice_size = 0;
if (!psi)
return;
goto out;
while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed,
- psi)) > 0) {
+ &ecc_notice_size, psi)) > 0) {
if (compressed && (type == PSTORE_TYPE_DMESG)) {
if (big_oops_buf)
unzipped_len = pstore_decompress(buf,
big_oops_buf_sz);
if (unzipped_len > 0) {
+ if (ecc_notice_size)
+ memcpy(big_oops_buf + unzipped_len,
+ buf + size, ecc_notice_size);
kfree(buf);
buf = big_oops_buf;
size = unzipped_len;
}
}
rc = pstore_mkfile(type, psi->name, id, count, buf,
- compressed, (size_t)size, time, psi);
+ compressed, size + ecc_notice_size,
+ time, psi);
if (unzipped_len < 0) {
/* Free buffer other than big oops */
kfree(buf);
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
int *count, struct timespec *time,
char **buf, bool *compressed,
+ ssize_t *ecc_notice_size,
struct pstore_info *psi)
{
ssize_t size;
- ssize_t ecc_notice_size;
struct ramoops_context *cxt = psi->data;
struct persistent_ram_zone *prz = NULL;
int header_length = 0;
size = persistent_ram_old_size(prz) - header_length;
/* ECC correction notice */
- ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
+ *ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
- *buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL);
+ *buf = kmalloc(size + *ecc_notice_size + 1, GFP_KERNEL);
if (*buf == NULL)
return -ENOMEM;
memcpy(*buf, (char *)persistent_ram_old(prz) + header_length, size);
- persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);
+ persistent_ram_ecc_string(prz, *buf + size, *ecc_notice_size + 1);
- return size + ecc_notice_size;
+ return size;
}
static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz,