aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-04 00:14:06 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-04 00:14:06 -0400
commitf83b0a4e4c33aa31dac0b8b48f1f3a470edc933a (patch)
treefade92500aa68531de6cd4761cc4693ea901540b
parent32dad03d164206ea886885d0740284ba215b0970 (diff)
parent3bd11cf56e4d9c9a79c0c1a4ebe381c674ec9709 (diff)
Merge tag 'please-pull-pstore' of git://git.kernel.org/pub/scm/linux/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()
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c112
-rw-r--r--drivers/acpi/apei/erst.c25
-rw-r--r--drivers/firmware/efi/efi-pstore.c27
-rw-r--r--fs/pstore/Kconfig2
-rw-r--r--fs/pstore/inode.c10
-rw-r--r--fs/pstore/internal.h5
-rw-r--r--fs/pstore/platform.c212
-rw-r--r--fs/pstore/ram.c47
-rw-r--r--include/linux/pstore.h6
9 files changed, 306 insertions, 140 deletions
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 6a5f2b1f32ca..d276cd3edd8f 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -539,36 +539,6 @@ static int zip_oops(size_t text_len)
539} 539}
540 540
541#ifdef CONFIG_PSTORE 541#ifdef CONFIG_PSTORE
542/* Derived from logfs_uncompress */
543int nvram_decompress(void *in, void *out, size_t inlen, size_t outlen)
544{
545 int err, ret;
546
547 ret = -EIO;
548 err = zlib_inflateInit(&stream);
549 if (err != Z_OK)
550 goto error;
551
552 stream.next_in = in;
553 stream.avail_in = inlen;
554 stream.total_in = 0;
555 stream.next_out = out;
556 stream.avail_out = outlen;
557 stream.total_out = 0;
558
559 err = zlib_inflate(&stream, Z_FINISH);
560 if (err != Z_STREAM_END)
561 goto error;
562
563 err = zlib_inflateEnd(&stream);
564 if (err != Z_OK)
565 goto error;
566
567 ret = stream.total_out;
568error:
569 return ret;
570}
571
572static int nvram_pstore_open(struct pstore_info *psi) 542static int nvram_pstore_open(struct pstore_info *psi)
573{ 543{
574 /* Reset the iterator to start reading partitions again */ 544 /* Reset the iterator to start reading partitions again */
@@ -584,7 +554,7 @@ static int nvram_pstore_open(struct pstore_info *psi)
584 * @part: pstore writes data to registered buffer in parts, 554 * @part: pstore writes data to registered buffer in parts,
585 * part number will indicate the same. 555 * part number will indicate the same.
586 * @count: Indicates oops count 556 * @count: Indicates oops count
587 * @hsize: Size of header added by pstore 557 * @compressed: Flag to indicate the log is compressed
588 * @size: number of bytes written to the registered buffer 558 * @size: number of bytes written to the registered buffer
589 * @psi: registered pstore_info structure 559 * @psi: registered pstore_info structure
590 * 560 *
@@ -595,7 +565,7 @@ static int nvram_pstore_open(struct pstore_info *psi)
595static int nvram_pstore_write(enum pstore_type_id type, 565static int nvram_pstore_write(enum pstore_type_id type,
596 enum kmsg_dump_reason reason, 566 enum kmsg_dump_reason reason,
597 u64 *id, unsigned int part, int count, 567 u64 *id, unsigned int part, int count,
598 size_t hsize, size_t size, 568 bool compressed, size_t size,
599 struct pstore_info *psi) 569 struct pstore_info *psi)
600{ 570{
601 int rc; 571 int rc;
@@ -611,30 +581,11 @@ static int nvram_pstore_write(enum pstore_type_id type,
611 oops_hdr->report_length = (u16) size; 581 oops_hdr->report_length = (u16) size;
612 oops_hdr->timestamp = get_seconds(); 582 oops_hdr->timestamp = get_seconds();
613 583
614 if (big_oops_buf) { 584 if (compressed)
615 rc = zip_oops(size); 585 err_type = ERR_TYPE_KERNEL_PANIC_GZ;
616 /*
617 * If compression fails copy recent log messages from
618 * big_oops_buf to oops_data.
619 */
620 if (rc != 0) {
621 size_t diff = size - oops_data_sz + hsize;
622
623 if (size > oops_data_sz) {
624 memcpy(oops_data, big_oops_buf, hsize);
625 memcpy(oops_data + hsize, big_oops_buf + diff,
626 oops_data_sz - hsize);
627
628 oops_hdr->report_length = (u16) oops_data_sz;
629 } else
630 memcpy(oops_data, big_oops_buf, size);
631 } else
632 err_type = ERR_TYPE_KERNEL_PANIC_GZ;
633 }
634 586
635 rc = nvram_write_os_partition(&oops_log_partition, oops_buf, 587 rc = nvram_write_os_partition(&oops_log_partition, oops_buf,
636 (int) (sizeof(*oops_hdr) + oops_hdr->report_length), err_type, 588 (int) (sizeof(*oops_hdr) + size), err_type, count);
637 count);
638 589
639 if (rc != 0) 590 if (rc != 0)
640 return rc; 591 return rc;
@@ -650,12 +601,12 @@ static int nvram_pstore_write(enum pstore_type_id type,
650 */ 601 */
651static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, 602static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
652 int *count, struct timespec *time, char **buf, 603 int *count, struct timespec *time, char **buf,
653 struct pstore_info *psi) 604 bool *compressed, struct pstore_info *psi)
654{ 605{
655 struct oops_log_info *oops_hdr; 606 struct oops_log_info *oops_hdr;
656 unsigned int err_type, id_no, size = 0; 607 unsigned int err_type, id_no, size = 0;
657 struct nvram_os_partition *part = NULL; 608 struct nvram_os_partition *part = NULL;
658 char *buff = NULL, *big_buff = NULL; 609 char *buff = NULL;
659 int sig = 0; 610 int sig = 0;
660 loff_t p; 611 loff_t p;
661 612
@@ -719,8 +670,7 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
719 *id = id_no; 670 *id = id_no;
720 671
721 if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { 672 if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
722 int length, unzipped_len; 673 size_t length, hdr_size;
723 size_t hdr_size;
724 674
725 oops_hdr = (struct oops_log_info *)buff; 675 oops_hdr = (struct oops_log_info *)buff;
726 if (oops_hdr->version < OOPS_HDR_VERSION) { 676 if (oops_hdr->version < OOPS_HDR_VERSION) {
@@ -741,23 +691,10 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
741 memcpy(*buf, buff + hdr_size, length); 691 memcpy(*buf, buff + hdr_size, length);
742 kfree(buff); 692 kfree(buff);
743 693
744 if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) { 694 if (err_type == ERR_TYPE_KERNEL_PANIC_GZ)
745 big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL); 695 *compressed = true;
746 if (!big_buff) 696 else
747 return -ENOMEM; 697 *compressed = false;
748
749 unzipped_len = nvram_decompress(*buf, big_buff,
750 length, big_oops_buf_sz);
751
752 if (unzipped_len < 0) {
753 pr_err("nvram: decompression failed, returned "
754 "rc %d\n", unzipped_len);
755 kfree(big_buff);
756 } else {
757 *buf = big_buff;
758 length = unzipped_len;
759 }
760 }
761 return length; 698 return length;
762 } 699 }
763 700
@@ -777,13 +714,8 @@ static int nvram_pstore_init(void)
777{ 714{
778 int rc = 0; 715 int rc = 0;
779 716
780 if (big_oops_buf) { 717 nvram_pstore_info.buf = oops_data;
781 nvram_pstore_info.buf = big_oops_buf; 718 nvram_pstore_info.bufsize = oops_data_sz;
782 nvram_pstore_info.bufsize = big_oops_buf_sz;
783 } else {
784 nvram_pstore_info.buf = oops_data;
785 nvram_pstore_info.bufsize = oops_data_sz;
786 }
787 719
788 rc = pstore_register(&nvram_pstore_info); 720 rc = pstore_register(&nvram_pstore_info);
789 if (rc != 0) 721 if (rc != 0)
@@ -802,7 +734,6 @@ static int nvram_pstore_init(void)
802static void __init nvram_init_oops_partition(int rtas_partition_exists) 734static void __init nvram_init_oops_partition(int rtas_partition_exists)
803{ 735{
804 int rc; 736 int rc;
805 size_t size;
806 737
807 rc = pseries_nvram_init_os_partition(&oops_log_partition); 738 rc = pseries_nvram_init_os_partition(&oops_log_partition);
808 if (rc != 0) { 739 if (rc != 0) {
@@ -823,6 +754,11 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
823 oops_data = oops_buf + sizeof(struct oops_log_info); 754 oops_data = oops_buf + sizeof(struct oops_log_info);
824 oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info); 755 oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
825 756
757 rc = nvram_pstore_init();
758
759 if (!rc)
760 return;
761
826 /* 762 /*
827 * Figure compression (preceded by elimination of each line's <n> 763 * Figure compression (preceded by elimination of each line's <n>
828 * severity prefix) will reduce the oops/panic report to at most 764 * severity prefix) will reduce the oops/panic report to at most
@@ -831,9 +767,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
831 big_oops_buf_sz = (oops_data_sz * 100) / 45; 767 big_oops_buf_sz = (oops_data_sz * 100) / 45;
832 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); 768 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
833 if (big_oops_buf) { 769 if (big_oops_buf) {
834 size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL), 770 stream.workspace = kmalloc(zlib_deflate_workspacesize(
835 zlib_inflate_workspacesize()); 771 WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
836 stream.workspace = kmalloc(size, GFP_KERNEL);
837 if (!stream.workspace) { 772 if (!stream.workspace) {
838 pr_err("nvram: No memory for compression workspace; " 773 pr_err("nvram: No memory for compression workspace; "
839 "skipping compression of %s partition data\n", 774 "skipping compression of %s partition data\n",
@@ -847,11 +782,6 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
847 stream.workspace = NULL; 782 stream.workspace = NULL;
848 } 783 }
849 784
850 rc = nvram_pstore_init();
851
852 if (!rc)
853 return;
854
855 rc = kmsg_dump_register(&nvram_kmsg_dumper); 785 rc = kmsg_dump_register(&nvram_kmsg_dumper);
856 if (rc != 0) { 786 if (rc != 0) {
857 pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc); 787 pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 88d0b0f9f92b..822b1ed3b00f 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -284,8 +284,10 @@ static int erst_exec_move_data(struct apei_exec_context *ctx,
284 if (!src) 284 if (!src)
285 return -ENOMEM; 285 return -ENOMEM;
286 dst = ioremap(ctx->dst_base + offset, ctx->var2); 286 dst = ioremap(ctx->dst_base + offset, ctx->var2);
287 if (!dst) 287 if (!dst) {
288 iounmap(src);
288 return -ENOMEM; 289 return -ENOMEM;
290 }
289 291
290 memmove(dst, src, ctx->var2); 292 memmove(dst, src, ctx->var2);
291 293
@@ -933,9 +935,9 @@ static int erst_open_pstore(struct pstore_info *psi);
933static int erst_close_pstore(struct pstore_info *psi); 935static int erst_close_pstore(struct pstore_info *psi);
934static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, 936static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
935 struct timespec *time, char **buf, 937 struct timespec *time, char **buf,
936 struct pstore_info *psi); 938 bool *compressed, struct pstore_info *psi);
937static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, 939static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
938 u64 *id, unsigned int part, int count, size_t hsize, 940 u64 *id, unsigned int part, int count, bool compressed,
939 size_t size, struct pstore_info *psi); 941 size_t size, struct pstore_info *psi);
940static int erst_clearer(enum pstore_type_id type, u64 id, int count, 942static int erst_clearer(enum pstore_type_id type, u64 id, int count,
941 struct timespec time, struct pstore_info *psi); 943 struct timespec time, struct pstore_info *psi);
@@ -956,6 +958,9 @@ static struct pstore_info erst_info = {
956#define CPER_SECTION_TYPE_DMESG \ 958#define CPER_SECTION_TYPE_DMESG \
957 UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \ 959 UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \
958 0x94, 0x19, 0xeb, 0x12) 960 0x94, 0x19, 0xeb, 0x12)
961#define CPER_SECTION_TYPE_DMESG_Z \
962 UUID_LE(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d, \
963 0x34, 0xdd, 0xfa, 0xc6)
959#define CPER_SECTION_TYPE_MCE \ 964#define CPER_SECTION_TYPE_MCE \
960 UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \ 965 UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \
961 0x04, 0x4a, 0x38, 0xfc) 966 0x04, 0x4a, 0x38, 0xfc)
@@ -989,7 +994,7 @@ static int erst_close_pstore(struct pstore_info *psi)
989 994
990static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, 995static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
991 struct timespec *time, char **buf, 996 struct timespec *time, char **buf,
992 struct pstore_info *psi) 997 bool *compressed, struct pstore_info *psi)
993{ 998{
994 int rc; 999 int rc;
995 ssize_t len = 0; 1000 ssize_t len = 0;
@@ -1034,7 +1039,12 @@ skip:
1034 } 1039 }
1035 memcpy(*buf, rcd->data, len - sizeof(*rcd)); 1040 memcpy(*buf, rcd->data, len - sizeof(*rcd));
1036 *id = record_id; 1041 *id = record_id;
1042 *compressed = false;
1037 if (uuid_le_cmp(rcd->sec_hdr.section_type, 1043 if (uuid_le_cmp(rcd->sec_hdr.section_type,
1044 CPER_SECTION_TYPE_DMESG_Z) == 0) {
1045 *type = PSTORE_TYPE_DMESG;
1046 *compressed = true;
1047 } else if (uuid_le_cmp(rcd->sec_hdr.section_type,
1038 CPER_SECTION_TYPE_DMESG) == 0) 1048 CPER_SECTION_TYPE_DMESG) == 0)
1039 *type = PSTORE_TYPE_DMESG; 1049 *type = PSTORE_TYPE_DMESG;
1040 else if (uuid_le_cmp(rcd->sec_hdr.section_type, 1050 else if (uuid_le_cmp(rcd->sec_hdr.section_type,
@@ -1055,7 +1065,7 @@ out:
1055} 1065}
1056 1066
1057static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, 1067static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
1058 u64 *id, unsigned int part, int count, size_t hsize, 1068 u64 *id, unsigned int part, int count, bool compressed,
1059 size_t size, struct pstore_info *psi) 1069 size_t size, struct pstore_info *psi)
1060{ 1070{
1061 struct cper_pstore_record *rcd = (struct cper_pstore_record *) 1071 struct cper_pstore_record *rcd = (struct cper_pstore_record *)
@@ -1085,7 +1095,10 @@ static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
1085 rcd->sec_hdr.flags = CPER_SEC_PRIMARY; 1095 rcd->sec_hdr.flags = CPER_SEC_PRIMARY;
1086 switch (type) { 1096 switch (type) {
1087 case PSTORE_TYPE_DMESG: 1097 case PSTORE_TYPE_DMESG:
1088 rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG; 1098 if (compressed)
1099 rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG_Z;
1100 else
1101 rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG;
1089 break; 1102 break;
1090 case PSTORE_TYPE_MCE: 1103 case PSTORE_TYPE_MCE:
1091 rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE; 1104 rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
index 73de5a9c2247..5002d50e3781 100644
--- a/drivers/firmware/efi/efi-pstore.c
+++ b/drivers/firmware/efi/efi-pstore.c
@@ -35,6 +35,7 @@ struct pstore_read_data {
35 enum pstore_type_id *type; 35 enum pstore_type_id *type;
36 int *count; 36 int *count;
37 struct timespec *timespec; 37 struct timespec *timespec;
38 bool *compressed;
38 char **buf; 39 char **buf;
39}; 40};
40 41
@@ -42,7 +43,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
42{ 43{
43 efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 44 efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
44 struct pstore_read_data *cb_data = data; 45 struct pstore_read_data *cb_data = data;
45 char name[DUMP_NAME_LEN]; 46 char name[DUMP_NAME_LEN], data_type;
46 int i; 47 int i;
47 int cnt; 48 int cnt;
48 unsigned int part; 49 unsigned int part;
@@ -54,12 +55,23 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
54 for (i = 0; i < DUMP_NAME_LEN; i++) 55 for (i = 0; i < DUMP_NAME_LEN; i++)
55 name[i] = entry->var.VariableName[i]; 56 name[i] = entry->var.VariableName[i];
56 57
57 if (sscanf(name, "dump-type%u-%u-%d-%lu", 58 if (sscanf(name, "dump-type%u-%u-%d-%lu-%c",
59 cb_data->type, &part, &cnt, &time, &data_type) == 5) {
60 *cb_data->id = part;
61 *cb_data->count = cnt;
62 cb_data->timespec->tv_sec = time;
63 cb_data->timespec->tv_nsec = 0;
64 if (data_type == 'C')
65 *cb_data->compressed = true;
66 else
67 *cb_data->compressed = false;
68 } else if (sscanf(name, "dump-type%u-%u-%d-%lu",
58 cb_data->type, &part, &cnt, &time) == 4) { 69 cb_data->type, &part, &cnt, &time) == 4) {
59 *cb_data->id = part; 70 *cb_data->id = part;
60 *cb_data->count = cnt; 71 *cb_data->count = cnt;
61 cb_data->timespec->tv_sec = time; 72 cb_data->timespec->tv_sec = time;
62 cb_data->timespec->tv_nsec = 0; 73 cb_data->timespec->tv_nsec = 0;
74 *cb_data->compressed = false;
63 } else if (sscanf(name, "dump-type%u-%u-%lu", 75 } else if (sscanf(name, "dump-type%u-%u-%lu",
64 cb_data->type, &part, &time) == 3) { 76 cb_data->type, &part, &time) == 3) {
65 /* 77 /*
@@ -71,6 +83,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
71 *cb_data->count = 0; 83 *cb_data->count = 0;
72 cb_data->timespec->tv_sec = time; 84 cb_data->timespec->tv_sec = time;
73 cb_data->timespec->tv_nsec = 0; 85 cb_data->timespec->tv_nsec = 0;
86 *cb_data->compressed = false;
74 } else 87 } else
75 return 0; 88 return 0;
76 89
@@ -87,7 +100,8 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
87 100
88static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, 101static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
89 int *count, struct timespec *timespec, 102 int *count, struct timespec *timespec,
90 char **buf, struct pstore_info *psi) 103 char **buf, bool *compressed,
104 struct pstore_info *psi)
91{ 105{
92 struct pstore_read_data data; 106 struct pstore_read_data data;
93 107
@@ -95,6 +109,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
95 data.type = type; 109 data.type = type;
96 data.count = count; 110 data.count = count;
97 data.timespec = timespec; 111 data.timespec = timespec;
112 data.compressed = compressed;
98 data.buf = buf; 113 data.buf = buf;
99 114
100 return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data, 115 return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data,
@@ -103,7 +118,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
103 118
104static int efi_pstore_write(enum pstore_type_id type, 119static int efi_pstore_write(enum pstore_type_id type,
105 enum kmsg_dump_reason reason, u64 *id, 120 enum kmsg_dump_reason reason, u64 *id,
106 unsigned int part, int count, size_t hsize, size_t size, 121 unsigned int part, int count, bool compressed, size_t size,
107 struct pstore_info *psi) 122 struct pstore_info *psi)
108{ 123{
109 char name[DUMP_NAME_LEN]; 124 char name[DUMP_NAME_LEN];
@@ -111,8 +126,8 @@ static int efi_pstore_write(enum pstore_type_id type,
111 efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 126 efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
112 int i, ret = 0; 127 int i, ret = 0;
113 128
114 sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, 129 sprintf(name, "dump-type%u-%u-%d-%lu-%c", type, part, count,
115 get_seconds()); 130 get_seconds(), compressed ? 'C' : 'D');
116 131
117 for (i = 0; i < DUMP_NAME_LEN; i++) 132 for (i = 0; i < DUMP_NAME_LEN; i++)
118 efi_name[i] = name[i]; 133 efi_name[i] = name[i];
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index ca71db69da07..983d9510becc 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -1,6 +1,8 @@
1config PSTORE 1config PSTORE
2 bool "Persistent store support" 2 bool "Persistent store support"
3 default n 3 default n
4 select ZLIB_DEFLATE
5 select ZLIB_INFLATE
4 help 6 help
5 This option enables generic access to platform level 7 This option enables generic access to platform level
6 persistent storage via "pstore" filesystem that can 8 persistent storage via "pstore" filesystem that can
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 71bf5f4ae84c..12823845d324 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -275,8 +275,8 @@ int pstore_is_mounted(void)
275 * Set the mtime & ctime to the date that this record was originally stored. 275 * Set the mtime & ctime to the date that this record was originally stored.
276 */ 276 */
277int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, 277int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
278 char *data, size_t size, struct timespec time, 278 char *data, bool compressed, size_t size,
279 struct pstore_info *psi) 279 struct timespec time, struct pstore_info *psi)
280{ 280{
281 struct dentry *root = pstore_sb->s_root; 281 struct dentry *root = pstore_sb->s_root;
282 struct dentry *dentry; 282 struct dentry *dentry;
@@ -315,7 +315,8 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
315 315
316 switch (type) { 316 switch (type) {
317 case PSTORE_TYPE_DMESG: 317 case PSTORE_TYPE_DMESG:
318 sprintf(name, "dmesg-%s-%lld", psname, id); 318 sprintf(name, "dmesg-%s-%lld%s", psname, id,
319 compressed ? ".enc.z" : "");
319 break; 320 break;
320 case PSTORE_TYPE_CONSOLE: 321 case PSTORE_TYPE_CONSOLE:
321 sprintf(name, "console-%s", psname); 322 sprintf(name, "console-%s", psname);
@@ -345,9 +346,8 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
345 346
346 mutex_lock(&root->d_inode->i_mutex); 347 mutex_lock(&root->d_inode->i_mutex);
347 348
348 rc = -ENOSPC;
349 dentry = d_alloc_name(root, name); 349 dentry = d_alloc_name(root, name);
350 if (IS_ERR(dentry)) 350 if (!dentry)
351 goto fail_lockedalloc; 351 goto fail_lockedalloc;
352 352
353 memcpy(private->data, data, size); 353 memcpy(private->data, data, size);
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 937d820f273c..3b3d305277c4 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -50,8 +50,9 @@ extern struct pstore_info *psinfo;
50extern void pstore_set_kmsg_bytes(int); 50extern void pstore_set_kmsg_bytes(int);
51extern void pstore_get_records(int); 51extern void pstore_get_records(int);
52extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, 52extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
53 int count, char *data, size_t size, 53 int count, char *data, bool compressed,
54 struct timespec time, struct pstore_info *psi); 54 size_t size, struct timespec time,
55 struct pstore_info *psi);
55extern int pstore_is_mounted(void); 56extern int pstore_is_mounted(void);
56 57
57#endif 58#endif
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 422962ae9fc2..4ffb7ab5e397 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -26,6 +26,7 @@
26#include <linux/console.h> 26#include <linux/console.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/pstore.h> 28#include <linux/pstore.h>
29#include <linux/zlib.h>
29#include <linux/string.h> 30#include <linux/string.h>
30#include <linux/timer.h> 31#include <linux/timer.h>
31#include <linux/slab.h> 32#include <linux/slab.h>
@@ -65,6 +66,15 @@ struct pstore_info *psinfo;
65 66
66static char *backend; 67static char *backend;
67 68
69/* Compression parameters */
70#define COMPR_LEVEL 6
71#define WINDOW_BITS 12
72#define MEM_LEVEL 4
73static struct z_stream_s stream;
74
75static char *big_oops_buf;
76static size_t big_oops_buf_sz;
77
68/* How much of the console log to snapshot */ 78/* How much of the console log to snapshot */
69static unsigned long kmsg_bytes = 10240; 79static unsigned long kmsg_bytes = 10240;
70 80
@@ -117,6 +127,121 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
117} 127}
118EXPORT_SYMBOL_GPL(pstore_cannot_block_path); 128EXPORT_SYMBOL_GPL(pstore_cannot_block_path);
119 129
130/* Derived from logfs_compress() */
131static int pstore_compress(const void *in, void *out, size_t inlen,
132 size_t outlen)
133{
134 int err, ret;
135
136 ret = -EIO;
137 err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
138 MEM_LEVEL, Z_DEFAULT_STRATEGY);
139 if (err != Z_OK)
140 goto error;
141
142 stream.next_in = in;
143 stream.avail_in = inlen;
144 stream.total_in = 0;
145 stream.next_out = out;
146 stream.avail_out = outlen;
147 stream.total_out = 0;
148
149 err = zlib_deflate(&stream, Z_FINISH);
150 if (err != Z_STREAM_END)
151 goto error;
152
153 err = zlib_deflateEnd(&stream);
154 if (err != Z_OK)
155 goto error;
156
157 if (stream.total_out >= stream.total_in)
158 goto error;
159
160 ret = stream.total_out;
161error:
162 return ret;
163}
164
165/* Derived from logfs_uncompress */
166static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen)
167{
168 int err, ret;
169
170 ret = -EIO;
171 err = zlib_inflateInit(&stream);
172 if (err != Z_OK)
173 goto error;
174
175 stream.next_in = in;
176 stream.avail_in = inlen;
177 stream.total_in = 0;
178 stream.next_out = out;
179 stream.avail_out = outlen;
180 stream.total_out = 0;
181
182 err = zlib_inflate(&stream, Z_FINISH);
183 if (err != Z_STREAM_END)
184 goto error;
185
186 err = zlib_inflateEnd(&stream);
187 if (err != Z_OK)
188 goto error;
189
190 ret = stream.total_out;
191error:
192 return ret;
193}
194
195static void allocate_buf_for_compression(void)
196{
197 size_t size;
198
199 big_oops_buf_sz = (psinfo->bufsize * 100) / 45;
200 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
201 if (big_oops_buf) {
202 size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
203 zlib_inflate_workspacesize());
204 stream.workspace = kmalloc(size, GFP_KERNEL);
205 if (!stream.workspace) {
206 pr_err("pstore: No memory for compression workspace; "
207 "skipping compression\n");
208 kfree(big_oops_buf);
209 big_oops_buf = NULL;
210 }
211 } else {
212 pr_err("No memory for uncompressed data; "
213 "skipping compression\n");
214 stream.workspace = NULL;
215 }
216
217}
218
219/*
220 * Called when compression fails, since the printk buffer
221 * would be fetched for compression calling it again when
222 * compression fails would have moved the iterator of
223 * printk buffer which results in fetching old contents.
224 * Copy the recent messages from big_oops_buf to psinfo->buf
225 */
226static size_t copy_kmsg_to_buffer(int hsize, size_t len)
227{
228 size_t total_len;
229 size_t diff;
230
231 total_len = hsize + len;
232
233 if (total_len > psinfo->bufsize) {
234 diff = total_len - psinfo->bufsize + hsize;
235 memcpy(psinfo->buf, big_oops_buf, hsize);
236 memcpy(psinfo->buf + hsize, big_oops_buf + diff,
237 psinfo->bufsize - hsize);
238 total_len = psinfo->bufsize;
239 } else
240 memcpy(psinfo->buf, big_oops_buf, total_len);
241
242 return total_len;
243}
244
120/* 245/*
121 * callback from kmsg_dump. (s2,l2) has the most recently 246 * callback from kmsg_dump. (s2,l2) has the most recently
122 * written bytes, older bytes are in (s1,l1). Save as much 247 * written bytes, older bytes are in (s1,l1). Save as much
@@ -148,22 +273,56 @@ static void pstore_dump(struct kmsg_dumper *dumper,
148 char *dst; 273 char *dst;
149 unsigned long size; 274 unsigned long size;
150 int hsize; 275 int hsize;
276 int zipped_len = -1;
151 size_t len; 277 size_t len;
278 bool compressed;
279 size_t total_len;
152 280
153 dst = psinfo->buf; 281 if (big_oops_buf) {
154 hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part); 282 dst = big_oops_buf;
155 size = psinfo->bufsize - hsize; 283 hsize = sprintf(dst, "%s#%d Part%d\n", why,
156 dst += hsize; 284 oopscount, part);
285 size = big_oops_buf_sz - hsize;
157 286
158 if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len)) 287 if (!kmsg_dump_get_buffer(dumper, true, dst + hsize,
159 break; 288 size, &len))
289 break;
290
291 zipped_len = pstore_compress(dst, psinfo->buf,
292 hsize + len, psinfo->bufsize);
293
294 if (zipped_len > 0) {
295 compressed = true;
296 total_len = zipped_len;
297 } else {
298 pr_err("pstore: compression failed for Part %d"
299 " returned %d\n", part, zipped_len);
300 pr_err("pstore: Capture uncompressed"
301 " oops/panic report of Part %d\n", part);
302 compressed = false;
303 total_len = copy_kmsg_to_buffer(hsize, len);
304 }
305 } else {
306 dst = psinfo->buf;
307 hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount,
308 part);
309 size = psinfo->bufsize - hsize;
310 dst += hsize;
311
312 if (!kmsg_dump_get_buffer(dumper, true, dst,
313 size, &len))
314 break;
315
316 compressed = false;
317 total_len = hsize + len;
318 }
160 319
161 ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part, 320 ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,
162 oopscount, hsize, hsize + len, psinfo); 321 oopscount, compressed, total_len, psinfo);
163 if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted()) 322 if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
164 pstore_new_entry = 1; 323 pstore_new_entry = 1;
165 324
166 total += hsize + len; 325 total += total_len;
167 part++; 326 part++;
168 } 327 }
169 if (pstore_cannot_block_path(reason)) { 328 if (pstore_cannot_block_path(reason)) {
@@ -221,10 +380,10 @@ static void pstore_register_console(void) {}
221static int pstore_write_compat(enum pstore_type_id type, 380static int pstore_write_compat(enum pstore_type_id type,
222 enum kmsg_dump_reason reason, 381 enum kmsg_dump_reason reason,
223 u64 *id, unsigned int part, int count, 382 u64 *id, unsigned int part, int count,
224 size_t hsize, size_t size, 383 bool compressed, size_t size,
225 struct pstore_info *psi) 384 struct pstore_info *psi)
226{ 385{
227 return psi->write_buf(type, reason, id, part, psinfo->buf, hsize, 386 return psi->write_buf(type, reason, id, part, psinfo->buf, compressed,
228 size, psi); 387 size, psi);
229} 388}
230 389
@@ -261,6 +420,8 @@ int pstore_register(struct pstore_info *psi)
261 return -EINVAL; 420 return -EINVAL;
262 } 421 }
263 422
423 allocate_buf_for_compression();
424
264 if (pstore_is_mounted()) 425 if (pstore_is_mounted())
265 pstore_get_records(0); 426 pstore_get_records(0);
266 427
@@ -297,6 +458,8 @@ void pstore_get_records(int quiet)
297 enum pstore_type_id type; 458 enum pstore_type_id type;
298 struct timespec time; 459 struct timespec time;
299 int failed = 0, rc; 460 int failed = 0, rc;
461 bool compressed;
462 int unzipped_len = -1;
300 463
301 if (!psi) 464 if (!psi)
302 return; 465 return;
@@ -305,11 +468,32 @@ void pstore_get_records(int quiet)
305 if (psi->open && psi->open(psi)) 468 if (psi->open && psi->open(psi))
306 goto out; 469 goto out;
307 470
308 while ((size = psi->read(&id, &type, &count, &time, &buf, psi)) > 0) { 471 while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed,
472 psi)) > 0) {
473 if (compressed && (type == PSTORE_TYPE_DMESG)) {
474 if (big_oops_buf)
475 unzipped_len = pstore_decompress(buf,
476 big_oops_buf, size,
477 big_oops_buf_sz);
478
479 if (unzipped_len > 0) {
480 buf = big_oops_buf;
481 size = unzipped_len;
482 compressed = false;
483 } else {
484 pr_err("pstore: decompression failed;"
485 "returned %d\n", unzipped_len);
486 compressed = true;
487 }
488 }
309 rc = pstore_mkfile(type, psi->name, id, count, buf, 489 rc = pstore_mkfile(type, psi->name, id, count, buf,
310 (size_t)size, time, psi); 490 compressed, (size_t)size, time, psi);
311 kfree(buf); 491 if (unzipped_len < 0) {
312 buf = NULL; 492 /* Free buffer other than big oops */
493 kfree(buf);
494 buf = NULL;
495 } else
496 unzipped_len = -1;
313 if (rc && (rc != -EEXIST || !quiet)) 497 if (rc && (rc != -EEXIST || !quiet))
314 failed++; 498 failed++;
315 } 499 }
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index a6119f9469e2..fa8cef2cca3a 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -131,9 +131,31 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
131 return prz; 131 return prz;
132} 132}
133 133
134static void ramoops_read_kmsg_hdr(char *buffer, struct timespec *time,
135 bool *compressed)
136{
137 char data_type;
138
139 if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n",
140 &time->tv_sec, &time->tv_nsec, &data_type) == 3) {
141 if (data_type == 'C')
142 *compressed = true;
143 else
144 *compressed = false;
145 } else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
146 &time->tv_sec, &time->tv_nsec) == 2) {
147 *compressed = false;
148 } else {
149 time->tv_sec = 0;
150 time->tv_nsec = 0;
151 *compressed = false;
152 }
153}
154
134static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, 155static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
135 int *count, struct timespec *time, 156 int *count, struct timespec *time,
136 char **buf, struct pstore_info *psi) 157 char **buf, bool *compressed,
158 struct pstore_info *psi)
137{ 159{
138 ssize_t size; 160 ssize_t size;
139 ssize_t ecc_notice_size; 161 ssize_t ecc_notice_size;
@@ -152,10 +174,6 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
152 if (!prz) 174 if (!prz)
153 return 0; 175 return 0;
154 176
155 /* TODO(kees): Bogus time for the moment. */
156 time->tv_sec = 0;
157 time->tv_nsec = 0;
158
159 size = persistent_ram_old_size(prz); 177 size = persistent_ram_old_size(prz);
160 178
161 /* ECC correction notice */ 179 /* ECC correction notice */
@@ -166,12 +184,14 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
166 return -ENOMEM; 184 return -ENOMEM;
167 185
168 memcpy(*buf, persistent_ram_old(prz), size); 186 memcpy(*buf, persistent_ram_old(prz), size);
187 ramoops_read_kmsg_hdr(*buf, time, compressed);
169 persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1); 188 persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);
170 189
171 return size + ecc_notice_size; 190 return size + ecc_notice_size;
172} 191}
173 192
174static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) 193static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz,
194 bool compressed)
175{ 195{
176 char *hdr; 196 char *hdr;
177 struct timespec timestamp; 197 struct timespec timestamp;
@@ -182,8 +202,9 @@ static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
182 timestamp.tv_sec = 0; 202 timestamp.tv_sec = 0;
183 timestamp.tv_nsec = 0; 203 timestamp.tv_nsec = 0;
184 } 204 }
185 hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n", 205 hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n",
186 (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000)); 206 (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000),
207 compressed ? 'C' : 'D');
187 WARN_ON_ONCE(!hdr); 208 WARN_ON_ONCE(!hdr);
188 len = hdr ? strlen(hdr) : 0; 209 len = hdr ? strlen(hdr) : 0;
189 persistent_ram_write(prz, hdr, len); 210 persistent_ram_write(prz, hdr, len);
@@ -196,7 +217,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
196 enum kmsg_dump_reason reason, 217 enum kmsg_dump_reason reason,
197 u64 *id, unsigned int part, 218 u64 *id, unsigned int part,
198 const char *buf, 219 const char *buf,
199 size_t hsize, size_t size, 220 bool compressed, size_t size,
200 struct pstore_info *psi) 221 struct pstore_info *psi)
201{ 222{
202 struct ramoops_context *cxt = psi->data; 223 struct ramoops_context *cxt = psi->data;
@@ -242,7 +263,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
242 263
243 prz = cxt->przs[cxt->dump_write_cnt]; 264 prz = cxt->przs[cxt->dump_write_cnt];
244 265
245 hlen = ramoops_write_kmsg_hdr(prz); 266 hlen = ramoops_write_kmsg_hdr(prz, compressed);
246 if (size + hlen > prz->buffer_size) 267 if (size + hlen > prz->buffer_size)
247 size = prz->buffer_size - hlen; 268 size = prz->buffer_size - hlen;
248 persistent_ram_write(prz, buf, size); 269 persistent_ram_write(prz, buf, size);
@@ -400,11 +421,11 @@ static int ramoops_probe(struct platform_device *pdev)
400 goto fail_out; 421 goto fail_out;
401 } 422 }
402 423
403 if (!is_power_of_2(pdata->record_size)) 424 if (pdata->record_size && !is_power_of_2(pdata->record_size))
404 pdata->record_size = rounddown_pow_of_two(pdata->record_size); 425 pdata->record_size = rounddown_pow_of_two(pdata->record_size);
405 if (!is_power_of_2(pdata->console_size)) 426 if (pdata->console_size && !is_power_of_2(pdata->console_size))
406 pdata->console_size = rounddown_pow_of_two(pdata->console_size); 427 pdata->console_size = rounddown_pow_of_two(pdata->console_size);
407 if (!is_power_of_2(pdata->ftrace_size)) 428 if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size))
408 pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); 429 pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
409 430
410 cxt->dump_read_cnt = 0; 431 cxt->dump_read_cnt = 0;
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index 4aa80ba830a2..abd437d0a8a7 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -55,14 +55,14 @@ struct pstore_info {
55 int (*close)(struct pstore_info *psi); 55 int (*close)(struct pstore_info *psi);
56 ssize_t (*read)(u64 *id, enum pstore_type_id *type, 56 ssize_t (*read)(u64 *id, enum pstore_type_id *type,
57 int *count, struct timespec *time, char **buf, 57 int *count, struct timespec *time, char **buf,
58 struct pstore_info *psi); 58 bool *compressed, struct pstore_info *psi);
59 int (*write)(enum pstore_type_id type, 59 int (*write)(enum pstore_type_id type,
60 enum kmsg_dump_reason reason, u64 *id, 60 enum kmsg_dump_reason reason, u64 *id,
61 unsigned int part, int count, size_t hsize, 61 unsigned int part, int count, bool compressed,
62 size_t size, struct pstore_info *psi); 62 size_t size, struct pstore_info *psi);
63 int (*write_buf)(enum pstore_type_id type, 63 int (*write_buf)(enum pstore_type_id type,
64 enum kmsg_dump_reason reason, u64 *id, 64 enum kmsg_dump_reason reason, u64 *id,
65 unsigned int part, const char *buf, size_t hsize, 65 unsigned int part, const char *buf, bool compressed,
66 size_t size, struct pstore_info *psi); 66 size_t size, struct pstore_info *psi);
67 int (*erase)(enum pstore_type_id type, u64 id, 67 int (*erase)(enum pstore_type_id type, u64 id,
68 int count, struct timespec time, 68 int count, struct timespec time,