aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAruna Balakrishnaiah <aruna@linux.vnet.ibm.com>2013-06-27 04:33:13 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-07-01 04:10:49 -0400
commit40847e56609c21692ebe593abbf72c1e7f4af206 (patch)
treed172321146ecebc805379e06cab6de09008919e9
parentfbfe86fc0c53911cf243479f7d26c37dcb1243f1 (diff)
powerpc/pseries: Support compression of oops text via pstore
The patch set supports compression of oops messages while writing to NVRAM, this helps in capturing more of oops data to lnx,oops-log. The pstore file for oops messages will be in decompressed format making it readable. In case compression fails, the patch takes care of copying the header added by pstore and last oops_data_sz bytes of big_oops_buf to NVRAM so that we have recent oops messages in lnx,oops-log. In case decompression fails, it will result in absence of oops file but still have files (in /dev/pstore) for other partitions. Signed-off-by: Aruna Balakrishnaiah <aruna@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c131
1 files changed, 117 insertions, 14 deletions
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 588bab5da8cb..9f8671a44551 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -539,6 +539,65 @@ 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 unzip_oops(char *oops_buf, char *big_buf)
573{
574 struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
575 u64 timestamp = oops_hdr->timestamp;
576 char *big_oops_data = NULL;
577 char *oops_data_buf = NULL;
578 size_t big_oops_data_sz;
579 int unzipped_len;
580
581 big_oops_data = big_buf + sizeof(struct oops_log_info);
582 big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info);
583 oops_data_buf = oops_buf + sizeof(struct oops_log_info);
584
585 unzipped_len = nvram_decompress(oops_data_buf, big_oops_data,
586 oops_hdr->report_length,
587 big_oops_data_sz);
588
589 if (unzipped_len < 0) {
590 pr_err("nvram: decompression failed; returned %d\n",
591 unzipped_len);
592 return -1;
593 }
594 oops_hdr = (struct oops_log_info *)big_buf;
595 oops_hdr->version = OOPS_HDR_VERSION;
596 oops_hdr->report_length = (u16) unzipped_len;
597 oops_hdr->timestamp = timestamp;
598 return 0;
599}
600
542static int nvram_pstore_open(struct pstore_info *psi) 601static int nvram_pstore_open(struct pstore_info *psi)
543{ 602{
544 /* Reset the iterator to start reading partitions again */ 603 /* Reset the iterator to start reading partitions again */
@@ -569,6 +628,7 @@ static int nvram_pstore_write(enum pstore_type_id type,
569 struct pstore_info *psi) 628 struct pstore_info *psi)
570{ 629{
571 int rc; 630 int rc;
631 unsigned int err_type = ERR_TYPE_KERNEL_PANIC;
572 struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; 632 struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf;
573 633
574 /* part 1 has the recent messages from printk buffer */ 634 /* part 1 has the recent messages from printk buffer */
@@ -579,8 +639,30 @@ static int nvram_pstore_write(enum pstore_type_id type,
579 oops_hdr->version = OOPS_HDR_VERSION; 639 oops_hdr->version = OOPS_HDR_VERSION;
580 oops_hdr->report_length = (u16) size; 640 oops_hdr->report_length = (u16) size;
581 oops_hdr->timestamp = get_seconds(); 641 oops_hdr->timestamp = get_seconds();
642
643 if (big_oops_buf) {
644 rc = zip_oops(size);
645 /*
646 * If compression fails copy recent log messages from
647 * big_oops_buf to oops_data.
648 */
649 if (rc != 0) {
650 size_t diff = size - oops_data_sz + hsize;
651
652 if (size > oops_data_sz) {
653 memcpy(oops_data, big_oops_buf, hsize);
654 memcpy(oops_data + hsize, big_oops_buf + diff,
655 oops_data_sz - hsize);
656
657 oops_hdr->report_length = (u16) oops_data_sz;
658 } else
659 memcpy(oops_data, big_oops_buf, size);
660 } else
661 err_type = ERR_TYPE_KERNEL_PANIC_GZ;
662 }
663
582 rc = nvram_write_os_partition(&oops_log_partition, oops_buf, 664 rc = nvram_write_os_partition(&oops_log_partition, oops_buf,
583 (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC, 665 (int) (sizeof(*oops_hdr) + oops_hdr->report_length), err_type,
584 count); 666 count);
585 667
586 if (rc != 0) 668 if (rc != 0)
@@ -602,10 +684,11 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
602 struct oops_log_info *oops_hdr; 684 struct oops_log_info *oops_hdr;
603 unsigned int err_type, id_no, size = 0; 685 unsigned int err_type, id_no, size = 0;
604 struct nvram_os_partition *part = NULL; 686 struct nvram_os_partition *part = NULL;
605 char *buff = NULL; 687 char *buff = NULL, *big_buff = NULL;
606 int sig = 0; 688 int rc, sig = 0;
607 loff_t p; 689 loff_t p;
608 690
691read_partition:
609 read_type++; 692 read_type++;
610 693
611 switch (nvram_type_ids[read_type]) { 694 switch (nvram_type_ids[read_type]) {
@@ -668,6 +751,25 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
668 if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { 751 if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
669 oops_hdr = (struct oops_log_info *)buff; 752 oops_hdr = (struct oops_log_info *)buff;
670 *buf = buff + sizeof(*oops_hdr); 753 *buf = buff + sizeof(*oops_hdr);
754
755 if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
756 big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
757 if (!big_buff)
758 return -ENOMEM;
759
760 rc = unzip_oops(buff, big_buff);
761
762 if (rc != 0) {
763 kfree(buff);
764 kfree(big_buff);
765 goto read_partition;
766 }
767
768 oops_hdr = (struct oops_log_info *)big_buff;
769 *buf = big_buff + sizeof(*oops_hdr);
770 kfree(buff);
771 }
772
671 time->tv_sec = oops_hdr->timestamp; 773 time->tv_sec = oops_hdr->timestamp;
672 time->tv_nsec = 0; 774 time->tv_nsec = 0;
673 return oops_hdr->report_length; 775 return oops_hdr->report_length;
@@ -689,17 +791,18 @@ static int nvram_pstore_init(void)
689{ 791{
690 int rc = 0; 792 int rc = 0;
691 793
692 nvram_pstore_info.buf = oops_data; 794 if (big_oops_buf) {
693 nvram_pstore_info.bufsize = oops_data_sz; 795 nvram_pstore_info.buf = big_oops_buf;
796 nvram_pstore_info.bufsize = big_oops_buf_sz;
797 } else {
798 nvram_pstore_info.buf = oops_data;
799 nvram_pstore_info.bufsize = oops_data_sz;
800 }
694 801
695 rc = pstore_register(&nvram_pstore_info); 802 rc = pstore_register(&nvram_pstore_info);
696 if (rc != 0) 803 if (rc != 0)
697 pr_err("nvram: pstore_register() failed, defaults to " 804 pr_err("nvram: pstore_register() failed, defaults to "
698 "kmsg_dump; returned %d\n", rc); 805 "kmsg_dump; returned %d\n", rc);
699 else
700 /*TODO: Support compression when pstore is configured */
701 pr_info("nvram: Compression of oops text supported only when "
702 "pstore is not configured");
703 806
704 return rc; 807 return rc;
705} 808}
@@ -733,11 +836,6 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
733 oops_data = oops_buf + sizeof(struct oops_log_info); 836 oops_data = oops_buf + sizeof(struct oops_log_info);
734 oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info); 837 oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
735 838
736 rc = nvram_pstore_init();
737
738 if (!rc)
739 return;
740
741 /* 839 /*
742 * Figure compression (preceded by elimination of each line's <n> 840 * Figure compression (preceded by elimination of each line's <n>
743 * severity prefix) will reduce the oops/panic report to at most 841 * severity prefix) will reduce the oops/panic report to at most
@@ -761,6 +859,11 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
761 stream.workspace = NULL; 859 stream.workspace = NULL;
762 } 860 }
763 861
862 rc = nvram_pstore_init();
863
864 if (!rc)
865 return;
866
764 rc = kmsg_dump_register(&nvram_kmsg_dumper); 867 rc = kmsg_dump_register(&nvram_kmsg_dumper);
765 if (rc != 0) { 868 if (rc != 0) {
766 pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc); 869 pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);