aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAruna Balakrishnaiah <aruna@linux.vnet.ibm.com>2013-06-05 14:51:32 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-06-20 03:04:49 -0400
commitd7563c94f728d8c9228cfddbb044c843b2e243e8 (patch)
treea1aa32537e0a3946f36cc9b5e3f2e05ac2a1c3b2
parent126746101e89991f179209ef58ab5937bc5ea4a3 (diff)
powerpc/pseries: Read/Write oops nvram partition via pstore
IBM's p series machines provide persistent storage for LPARs through NVRAM. NVRAM's lnx,oops-log partition is used to log oops messages. Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose oops partition in NVRAM as a separate file in /dev/pstore. For instance, Oops messages will be stored in a file named [dmesg-nvram-2]. In case pstore registration fails it will fall back to kmsg_dump mechanism. This patch will read/write the oops messages from/to this partition via pstore. Signed-off-by: Jim Keniston <jkenisto@us.ibm.com> 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.c172
1 files changed, 157 insertions, 15 deletions
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 088f023d8f25..9edec8ee02ef 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -18,6 +18,7 @@
18#include <linux/spinlock.h> 18#include <linux/spinlock.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/kmsg_dump.h> 20#include <linux/kmsg_dump.h>
21#include <linux/pstore.h>
21#include <linux/ctype.h> 22#include <linux/ctype.h>
22#include <linux/zlib.h> 23#include <linux/zlib.h>
23#include <asm/uaccess.h> 24#include <asm/uaccess.h>
@@ -127,6 +128,14 @@ static size_t oops_data_sz;
127#define MEM_LEVEL 4 128#define MEM_LEVEL 4
128static struct z_stream_s stream; 129static struct z_stream_s stream;
129 130
131#ifdef CONFIG_PSTORE
132static enum pstore_type_id nvram_type_ids[] = {
133 PSTORE_TYPE_DMESG,
134 -1
135};
136static int read_type;
137#endif
138
130static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) 139static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
131{ 140{
132 unsigned int i; 141 unsigned int i;
@@ -430,6 +439,149 @@ static int __init pseries_nvram_init_os_partition(struct nvram_os_partition
430 return 0; 439 return 0;
431} 440}
432 441
442/*
443 * Are we using the ibm,rtas-log for oops/panic reports? And if so,
444 * would logging this oops/panic overwrite an RTAS event that rtas_errd
445 * hasn't had a chance to read and process? Return 1 if so, else 0.
446 *
447 * We assume that if rtas_errd hasn't read the RTAS event in
448 * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to.
449 */
450static int clobbering_unread_rtas_event(void)
451{
452 return (oops_log_partition.index == rtas_log_partition.index
453 && last_unread_rtas_event
454 && get_seconds() - last_unread_rtas_event <=
455 NVRAM_RTAS_READ_TIMEOUT);
456}
457
458#ifdef CONFIG_PSTORE
459static int nvram_pstore_open(struct pstore_info *psi)
460{
461 /* Reset the iterator to start reading partitions again */
462 read_type = -1;
463 return 0;
464}
465
466/**
467 * nvram_pstore_write - pstore write callback for nvram
468 * @type: Type of message logged
469 * @reason: reason behind dump (oops/panic)
470 * @id: identifier to indicate the write performed
471 * @part: pstore writes data to registered buffer in parts,
472 * part number will indicate the same.
473 * @count: Indicates oops count
474 * @size: number of bytes written to the registered buffer
475 * @psi: registered pstore_info structure
476 *
477 * Called by pstore_dump() when an oops or panic report is logged in the
478 * printk buffer.
479 * Returns 0 on successful write.
480 */
481static int nvram_pstore_write(enum pstore_type_id type,
482 enum kmsg_dump_reason reason,
483 u64 *id, unsigned int part, int count,
484 size_t size, struct pstore_info *psi)
485{
486 int rc;
487 struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf;
488
489 /* part 1 has the recent messages from printk buffer */
490 if (part > 1 || type != PSTORE_TYPE_DMESG ||
491 clobbering_unread_rtas_event())
492 return -1;
493
494 oops_hdr->version = OOPS_HDR_VERSION;
495 oops_hdr->report_length = (u16) size;
496 oops_hdr->timestamp = get_seconds();
497 rc = nvram_write_os_partition(&oops_log_partition, oops_buf,
498 (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC,
499 count);
500
501 if (rc != 0)
502 return rc;
503
504 *id = part;
505 return 0;
506}
507
508/*
509 * Reads the oops/panic report.
510 * Returns the length of the data we read from each partition.
511 * Returns 0 if we've been called before.
512 */
513static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
514 int *count, struct timespec *time, char **buf,
515 struct pstore_info *psi)
516{
517 struct oops_log_info *oops_hdr;
518 unsigned int err_type, id_no;
519 struct nvram_os_partition *part = NULL;
520 char *buff = NULL;
521
522 read_type++;
523
524 switch (nvram_type_ids[read_type]) {
525 case PSTORE_TYPE_DMESG:
526 part = &oops_log_partition;
527 *type = PSTORE_TYPE_DMESG;
528 break;
529 default:
530 return 0;
531 }
532
533 buff = kmalloc(part->size, GFP_KERNEL);
534
535 if (!buff)
536 return -ENOMEM;
537
538 if (nvram_read_partition(part, buff, part->size, &err_type, &id_no)) {
539 kfree(buff);
540 return 0;
541 }
542
543 *count = 0;
544 *id = id_no;
545 oops_hdr = (struct oops_log_info *)buff;
546 *buf = buff + sizeof(*oops_hdr);
547 time->tv_sec = oops_hdr->timestamp;
548 time->tv_nsec = 0;
549 return oops_hdr->report_length;
550}
551
552static struct pstore_info nvram_pstore_info = {
553 .owner = THIS_MODULE,
554 .name = "nvram",
555 .open = nvram_pstore_open,
556 .read = nvram_pstore_read,
557 .write = nvram_pstore_write,
558};
559
560static int nvram_pstore_init(void)
561{
562 int rc = 0;
563
564 nvram_pstore_info.buf = oops_data;
565 nvram_pstore_info.bufsize = oops_data_sz;
566
567 rc = pstore_register(&nvram_pstore_info);
568 if (rc != 0)
569 pr_err("nvram: pstore_register() failed, defaults to "
570 "kmsg_dump; returned %d\n", rc);
571 else
572 /*TODO: Support compression when pstore is configured */
573 pr_info("nvram: Compression of oops text supported only when "
574 "pstore is not configured");
575
576 return rc;
577}
578#else
579static int nvram_pstore_init(void)
580{
581 return -1;
582}
583#endif
584
433static void __init nvram_init_oops_partition(int rtas_partition_exists) 585static void __init nvram_init_oops_partition(int rtas_partition_exists)
434{ 586{
435 int rc; 587 int rc;
@@ -453,6 +605,11 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
453 oops_data = oops_buf + sizeof(struct oops_log_info); 605 oops_data = oops_buf + sizeof(struct oops_log_info);
454 oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info); 606 oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
455 607
608 rc = nvram_pstore_init();
609
610 if (!rc)
611 return;
612
456 /* 613 /*
457 * Figure compression (preceded by elimination of each line's <n> 614 * Figure compression (preceded by elimination of each line's <n>
458 * severity prefix) will reduce the oops/panic report to at most 615 * severity prefix) will reduce the oops/panic report to at most
@@ -525,21 +682,6 @@ int __init pSeries_nvram_init(void)
525 return 0; 682 return 0;
526} 683}
527 684
528/*
529 * Are we using the ibm,rtas-log for oops/panic reports? And if so,
530 * would logging this oops/panic overwrite an RTAS event that rtas_errd
531 * hasn't had a chance to read and process? Return 1 if so, else 0.
532 *
533 * We assume that if rtas_errd hasn't read the RTAS event in
534 * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to.
535 */
536static int clobbering_unread_rtas_event(void)
537{
538 return (oops_log_partition.index == rtas_log_partition.index
539 && last_unread_rtas_event
540 && get_seconds() - last_unread_rtas_event <=
541 NVRAM_RTAS_READ_TIMEOUT);
542}
543 685
544/* Derived from logfs_compress() */ 686/* Derived from logfs_compress() */
545static int nvram_compress(const void *in, void *out, size_t inlen, 687static int nvram_compress(const void *in, void *out, size_t inlen,