Skip to content

Commit

Permalink
Merge tag 'please-pull-pstore' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/aegl/linux

Pull pstore changes from Tony Luck:
 "A big part of this is the addition of compression to the generic
  pstore layer so that all backends can use the pitiful amounts of
  storage they control more effectively.  Three other small
  fixes/cleanups too.

* tag 'please-pull-pstore' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux:
  pstore/ram: (really) fix undefined usage of rounddown_pow_of_two
  pstore/ram: Read and write to the 'compressed' flag of pstore
  efi-pstore: Read and write to the 'compressed' flag of pstore
  erst: Read and write to the 'compressed' flag of pstore
  powerpc/pseries: Read and write to the 'compressed' flag of pstore
  pstore: Add file extension to pstore file if compressed
  pstore: Add decompression support to pstore
  pstore: Introduce new argument 'compressed' in the read callback
  pstore: Add compression support to pstore
  pstore/Kconfig: Select ZLIB_DEFLATE and ZLIB_INFLATE when PSTORE is selected
  pstore: Add new argument 'compressed' in pstore write callback
  powerpc/pseries: Remove (de)compression in nvram with pstore enabled
  pstore: d_alloc_name() doesn't return an ERR_PTR
  acpi/apei/erst: Add missing iounmap() on error in erst_exec_move_data()
  • Loading branch information
Linus Torvalds committed Sep 4, 2013
2 parents 32dad03 + 3bd11cf commit f83b0a4
Show file tree
Hide file tree
Showing 9 changed files with 306 additions and 140 deletions.
112 changes: 21 additions & 91 deletions arch/powerpc/platforms/pseries/nvram.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,36 +539,6 @@ static int zip_oops(size_t text_len)
}

#ifdef CONFIG_PSTORE
/* Derived from logfs_uncompress */
int nvram_decompress(void *in, void *out, size_t inlen, size_t outlen)
{
int err, ret;

ret = -EIO;
err = zlib_inflateInit(&stream);
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 int nvram_pstore_open(struct pstore_info *psi)
{
/* Reset the iterator to start reading partitions again */
Expand All @@ -584,7 +554,7 @@ static int nvram_pstore_open(struct pstore_info *psi)
* @part: pstore writes data to registered buffer in parts,
* part number will indicate the same.
* @count: Indicates oops count
* @hsize: Size of header added by pstore
* @compressed: Flag to indicate the log is compressed
* @size: number of bytes written to the registered buffer
* @psi: registered pstore_info structure
*
Expand All @@ -595,7 +565,7 @@ static int nvram_pstore_open(struct pstore_info *psi)
static int nvram_pstore_write(enum pstore_type_id type,
enum kmsg_dump_reason reason,
u64 *id, unsigned int part, int count,
size_t hsize, size_t size,
bool compressed, size_t size,
struct pstore_info *psi)
{
int rc;
Expand All @@ -611,30 +581,11 @@ static int nvram_pstore_write(enum pstore_type_id type,
oops_hdr->report_length = (u16) size;
oops_hdr->timestamp = get_seconds();

if (big_oops_buf) {
rc = zip_oops(size);
/*
* If compression fails copy recent log messages from
* big_oops_buf to oops_data.
*/
if (rc != 0) {
size_t diff = size - oops_data_sz + hsize;

if (size > oops_data_sz) {
memcpy(oops_data, big_oops_buf, hsize);
memcpy(oops_data + hsize, big_oops_buf + diff,
oops_data_sz - hsize);

oops_hdr->report_length = (u16) oops_data_sz;
} else
memcpy(oops_data, big_oops_buf, size);
} else
err_type = ERR_TYPE_KERNEL_PANIC_GZ;
}
if (compressed)
err_type = ERR_TYPE_KERNEL_PANIC_GZ;

rc = nvram_write_os_partition(&oops_log_partition, oops_buf,
(int) (sizeof(*oops_hdr) + oops_hdr->report_length), err_type,
count);
(int) (sizeof(*oops_hdr) + size), err_type, count);

if (rc != 0)
return rc;
Expand All @@ -650,12 +601,12 @@ static int nvram_pstore_write(enum pstore_type_id type,
*/
static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
int *count, struct timespec *time, char **buf,
struct pstore_info *psi)
bool *compressed, struct pstore_info *psi)
{
struct oops_log_info *oops_hdr;
unsigned int err_type, id_no, size = 0;
struct nvram_os_partition *part = NULL;
char *buff = NULL, *big_buff = NULL;
char *buff = NULL;
int sig = 0;
loff_t p;

Expand Down Expand Up @@ -719,8 +670,7 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
*id = id_no;

if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
int length, unzipped_len;
size_t hdr_size;
size_t length, hdr_size;

oops_hdr = (struct oops_log_info *)buff;
if (oops_hdr->version < OOPS_HDR_VERSION) {
Expand All @@ -741,23 +691,10 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
memcpy(*buf, buff + hdr_size, length);
kfree(buff);

if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
if (!big_buff)
return -ENOMEM;

unzipped_len = nvram_decompress(*buf, big_buff,
length, big_oops_buf_sz);

if (unzipped_len < 0) {
pr_err("nvram: decompression failed, returned "
"rc %d\n", unzipped_len);
kfree(big_buff);
} else {
*buf = big_buff;
length = unzipped_len;
}
}
if (err_type == ERR_TYPE_KERNEL_PANIC_GZ)
*compressed = true;
else
*compressed = false;
return length;
}

Expand All @@ -777,13 +714,8 @@ static int nvram_pstore_init(void)
{
int rc = 0;

if (big_oops_buf) {
nvram_pstore_info.buf = big_oops_buf;
nvram_pstore_info.bufsize = big_oops_buf_sz;
} else {
nvram_pstore_info.buf = oops_data;
nvram_pstore_info.bufsize = oops_data_sz;
}
nvram_pstore_info.buf = oops_data;
nvram_pstore_info.bufsize = oops_data_sz;

rc = pstore_register(&nvram_pstore_info);
if (rc != 0)
Expand All @@ -802,7 +734,6 @@ static int nvram_pstore_init(void)
static void __init nvram_init_oops_partition(int rtas_partition_exists)
{
int rc;
size_t size;

rc = pseries_nvram_init_os_partition(&oops_log_partition);
if (rc != 0) {
Expand All @@ -823,6 +754,11 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
oops_data = oops_buf + sizeof(struct oops_log_info);
oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);

rc = nvram_pstore_init();

if (!rc)
return;

/*
* Figure compression (preceded by elimination of each line's <n>
* severity prefix) will reduce the oops/panic report to at most
Expand All @@ -831,9 +767,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
big_oops_buf_sz = (oops_data_sz * 100) / 45;
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);
stream.workspace = kmalloc(zlib_deflate_workspacesize(
WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
if (!stream.workspace) {
pr_err("nvram: No memory for compression workspace; "
"skipping compression of %s partition data\n",
Expand All @@ -847,11 +782,6 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
stream.workspace = NULL;
}

rc = nvram_pstore_init();

if (!rc)
return;

rc = kmsg_dump_register(&nvram_kmsg_dumper);
if (rc != 0) {
pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);
Expand Down
25 changes: 19 additions & 6 deletions drivers/acpi/apei/erst.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,10 @@ static int erst_exec_move_data(struct apei_exec_context *ctx,
if (!src)
return -ENOMEM;
dst = ioremap(ctx->dst_base + offset, ctx->var2);
if (!dst)
if (!dst) {
iounmap(src);
return -ENOMEM;
}

memmove(dst, src, ctx->var2);

Expand Down Expand Up @@ -933,9 +935,9 @@ static int erst_open_pstore(struct pstore_info *psi);
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,
struct pstore_info *psi);
bool *compressed, 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, size_t hsize,
u64 *id, unsigned int part, int count, bool compressed,
size_t size, struct pstore_info *psi);
static int erst_clearer(enum pstore_type_id type, u64 id, int count,
struct timespec time, struct pstore_info *psi);
Expand All @@ -956,6 +958,9 @@ static struct pstore_info erst_info = {
#define CPER_SECTION_TYPE_DMESG \
UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \
0x94, 0x19, 0xeb, 0x12)
#define CPER_SECTION_TYPE_DMESG_Z \
UUID_LE(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d, \
0x34, 0xdd, 0xfa, 0xc6)
#define CPER_SECTION_TYPE_MCE \
UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \
0x04, 0x4a, 0x38, 0xfc)
Expand Down Expand Up @@ -989,7 +994,7 @@ 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,
struct pstore_info *psi)
bool *compressed, struct pstore_info *psi)
{
int rc;
ssize_t len = 0;
Expand Down Expand Up @@ -1034,7 +1039,12 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
}
memcpy(*buf, rcd->data, len - sizeof(*rcd));
*id = record_id;
*compressed = false;
if (uuid_le_cmp(rcd->sec_hdr.section_type,
CPER_SECTION_TYPE_DMESG_Z) == 0) {
*type = PSTORE_TYPE_DMESG;
*compressed = true;
} else if (uuid_le_cmp(rcd->sec_hdr.section_type,
CPER_SECTION_TYPE_DMESG) == 0)
*type = PSTORE_TYPE_DMESG;
else if (uuid_le_cmp(rcd->sec_hdr.section_type,
Expand All @@ -1055,7 +1065,7 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
}

static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
u64 *id, unsigned int part, int count, size_t hsize,
u64 *id, unsigned int part, int count, bool compressed,
size_t size, struct pstore_info *psi)
{
struct cper_pstore_record *rcd = (struct cper_pstore_record *)
Expand Down Expand Up @@ -1085,7 +1095,10 @@ static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
rcd->sec_hdr.flags = CPER_SEC_PRIMARY;
switch (type) {
case PSTORE_TYPE_DMESG:
rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG;
if (compressed)
rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG_Z;
else
rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG;
break;
case PSTORE_TYPE_MCE:
rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
Expand Down
27 changes: 21 additions & 6 deletions drivers/firmware/efi/efi-pstore.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ struct pstore_read_data {
enum pstore_type_id *type;
int *count;
struct timespec *timespec;
bool *compressed;
char **buf;
};

static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
{
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
struct pstore_read_data *cb_data = data;
char name[DUMP_NAME_LEN];
char name[DUMP_NAME_LEN], data_type;
int i;
int cnt;
unsigned int part;
Expand All @@ -54,12 +55,23 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
for (i = 0; i < DUMP_NAME_LEN; i++)
name[i] = entry->var.VariableName[i];

if (sscanf(name, "dump-type%u-%u-%d-%lu",
if (sscanf(name, "dump-type%u-%u-%d-%lu-%c",
cb_data->type, &part, &cnt, &time, &data_type) == 5) {
*cb_data->id = part;
*cb_data->count = cnt;
cb_data->timespec->tv_sec = time;
cb_data->timespec->tv_nsec = 0;
if (data_type == 'C')
*cb_data->compressed = true;
else
*cb_data->compressed = false;
} else if (sscanf(name, "dump-type%u-%u-%d-%lu",
cb_data->type, &part, &cnt, &time) == 4) {
*cb_data->id = part;
*cb_data->count = cnt;
cb_data->timespec->tv_sec = time;
cb_data->timespec->tv_nsec = 0;
*cb_data->compressed = false;
} else if (sscanf(name, "dump-type%u-%u-%lu",
cb_data->type, &part, &time) == 3) {
/*
Expand All @@ -71,6 +83,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
*cb_data->count = 0;
cb_data->timespec->tv_sec = time;
cb_data->timespec->tv_nsec = 0;
*cb_data->compressed = false;
} else
return 0;

Expand All @@ -87,14 +100,16 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)

static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
int *count, struct timespec *timespec,
char **buf, struct pstore_info *psi)
char **buf, bool *compressed,
struct pstore_info *psi)
{
struct pstore_read_data data;

data.id = id;
data.type = type;
data.count = count;
data.timespec = timespec;
data.compressed = compressed;
data.buf = buf;

return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data,
Expand All @@ -103,16 +118,16 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,

static int efi_pstore_write(enum pstore_type_id type,
enum kmsg_dump_reason reason, u64 *id,
unsigned int part, int count, size_t hsize, size_t size,
unsigned int part, int count, bool compressed, size_t size,
struct pstore_info *psi)
{
char name[DUMP_NAME_LEN];
efi_char16_t efi_name[DUMP_NAME_LEN];
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
int i, ret = 0;

sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count,
get_seconds());
sprintf(name, "dump-type%u-%u-%d-%lu-%c", type, part, count,
get_seconds(), compressed ? 'C' : 'D');

for (i = 0; i < DUMP_NAME_LEN; i++)
efi_name[i] = name[i];
Expand Down
2 changes: 2 additions & 0 deletions fs/pstore/Kconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
config PSTORE
bool "Persistent store support"
default n
select ZLIB_DEFLATE
select ZLIB_INFLATE
help
This option enables generic access to platform level
persistent storage via "pstore" filesystem that can
Expand Down
Loading

0 comments on commit f83b0a4

Please sign in to comment.