aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,