diff options
-rw-r--r-- | arch/powerpc/platforms/pseries/nvram.c | 112 | ||||
-rw-r--r-- | drivers/acpi/apei/erst.c | 25 | ||||
-rw-r--r-- | drivers/firmware/efi/efi-pstore.c | 27 | ||||
-rw-r--r-- | fs/pstore/Kconfig | 2 | ||||
-rw-r--r-- | fs/pstore/inode.c | 10 | ||||
-rw-r--r-- | fs/pstore/internal.h | 5 | ||||
-rw-r--r-- | fs/pstore/platform.c | 212 | ||||
-rw-r--r-- | fs/pstore/ram.c | 47 | ||||
-rw-r--r-- | include/linux/pstore.h | 6 |
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 */ | ||
543 | int 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; | ||
568 | error: | ||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | static int nvram_pstore_open(struct pstore_info *psi) | 542 | static 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) | |||
595 | static int nvram_pstore_write(enum pstore_type_id type, | 565 | static 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 | */ |
651 | static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, | 602 | static 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) | |||
802 | static void __init nvram_init_oops_partition(int rtas_partition_exists) | 734 | static 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); | |||
933 | static int erst_close_pstore(struct pstore_info *psi); | 935 | static int erst_close_pstore(struct pstore_info *psi); |
934 | static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, | 936 | static 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); |
937 | static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, | 939 | static 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); |
940 | static int erst_clearer(enum pstore_type_id type, u64 id, int count, | 942 | static 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 | ||
990 | static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, | 995 | static 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 | ||
1057 | static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, | 1067 | static 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 | ||
88 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | 101 | static 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 | ||
104 | static int efi_pstore_write(enum pstore_type_id type, | 119 | static 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 @@ | |||
1 | config PSTORE | 1 | config 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 | */ |
277 | int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, | 277 | int 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; | |||
50 | extern void pstore_set_kmsg_bytes(int); | 50 | extern void pstore_set_kmsg_bytes(int); |
51 | extern void pstore_get_records(int); | 51 | extern void pstore_get_records(int); |
52 | extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, | 52 | extern 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); | ||
55 | extern int pstore_is_mounted(void); | 56 | extern 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 | ||
66 | static char *backend; | 67 | static char *backend; |
67 | 68 | ||
69 | /* Compression parameters */ | ||
70 | #define COMPR_LEVEL 6 | ||
71 | #define WINDOW_BITS 12 | ||
72 | #define MEM_LEVEL 4 | ||
73 | static struct z_stream_s stream; | ||
74 | |||
75 | static char *big_oops_buf; | ||
76 | static 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 */ |
69 | static unsigned long kmsg_bytes = 10240; | 79 | static unsigned long kmsg_bytes = 10240; |
70 | 80 | ||
@@ -117,6 +127,121 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason) | |||
117 | } | 127 | } |
118 | EXPORT_SYMBOL_GPL(pstore_cannot_block_path); | 128 | EXPORT_SYMBOL_GPL(pstore_cannot_block_path); |
119 | 129 | ||
130 | /* Derived from logfs_compress() */ | ||
131 | static 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; | ||
161 | error: | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | /* Derived from logfs_uncompress */ | ||
166 | static 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; | ||
191 | error: | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | static 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 | */ | ||
226 | static 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) {} | |||
221 | static int pstore_write_compat(enum pstore_type_id type, | 380 | static 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 | ||
134 | static 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 | |||
134 | static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, | 155 | static 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 | ||
174 | static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) | 193 | static 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, |