Loading Documentation/ABI/testing/pstore 0 → 100644 +35 −0 Original line number Diff line number Diff line Where: /dev/pstore/... Date: January 2011 Kernel Version: 2.6.38 Contact: tony.luck@intel.com Description: Generic interface to platform dependent persistent storage. Platforms that provide a mechanism to preserve some data across system reboots can register with this driver to provide a generic interface to show records captured in the dying moments. In the case of a panic the last part of the console log is captured, but other interesting data can also be saved. # mount -t pstore - /dev/pstore $ ls -l /dev/pstore total 0 -r--r--r-- 1 root root 7896 Nov 30 15:38 dmesg-erst-1 Different users of this interface will result in different filename prefixes. Currently two are defined: "dmesg" - saved console log "mce" - architecture dependent data from fatal h/w error Once the information in a file has been read, removing the file will signal to the underlying persistent storage device that it can reclaim the space for later re-use. $ rm /dev/pstore/dmesg-erst-1 The expectation is that all files in /dev/pstore will be saved elsewhere and erased from persistent store soon after boot to free up space ready for the next catastrophe. Documentation/ABI/testing/sysfs-fs-pstore 0 → 100644 +7 −0 Original line number Diff line number Diff line What: /sys/fs/pstore/kmsg_bytes Date: January 2011 Kernel Version: 2.6.38 Contact: "Tony Luck" <tony.luck@intel.com> Description: Controls amount of console log that will be saved to persistent store on oops/panic. drivers/acpi/apei/Kconfig +1 −0 Original line number Diff line number Diff line config ACPI_APEI bool "ACPI Platform Error Interface (APEI)" select PSTORE depends on X86 help APEI allows to report errors (for example from the chipset) Loading drivers/acpi/apei/erst.c +136 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <linux/cper.h> #include <linux/nmi.h> #include <linux/hardirq.h> #include <linux/pstore.h> #include <acpi/apei.h> #include "apei-internal.h" Loading Loading @@ -781,6 +782,128 @@ static int erst_check_table(struct acpi_table_erst *erst_tab) return 0; } static size_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time); static u64 erst_writer(enum pstore_type_id type, size_t size); static struct pstore_info erst_info = { .owner = THIS_MODULE, .name = "erst", .read = erst_reader, .write = erst_writer, .erase = erst_clear }; #define CPER_CREATOR_PSTORE \ UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \ 0x64, 0x90, 0xb8, 0x9d) #define CPER_SECTION_TYPE_DMESG \ UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \ 0x94, 0x19, 0xeb, 0x12) #define CPER_SECTION_TYPE_MCE \ UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \ 0x04, 0x4a, 0x38, 0xfc) struct cper_pstore_record { struct cper_record_header hdr; struct cper_section_descriptor sec_hdr; char data[]; } __packed; static size_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time) { int rc; ssize_t len; unsigned long flags; u64 record_id; struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); if (erst_disable) return -ENODEV; raw_spin_lock_irqsave(&erst_lock, flags); skip: rc = __erst_get_next_record_id(&record_id); if (rc) { raw_spin_unlock_irqrestore(&erst_lock, flags); return rc; } /* no more record */ if (record_id == APEI_ERST_INVALID_RECORD_ID) { raw_spin_unlock_irqrestore(&erst_lock, flags); return 0; } len = __erst_read(record_id, &rcd->hdr, sizeof(*rcd) + erst_erange.size); if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) goto skip; raw_spin_unlock_irqrestore(&erst_lock, flags); *id = record_id; if (uuid_le_cmp(rcd->sec_hdr.section_type, CPER_SECTION_TYPE_DMESG) == 0) *type = PSTORE_TYPE_DMESG; else if (uuid_le_cmp(rcd->sec_hdr.section_type, CPER_SECTION_TYPE_MCE) == 0) *type = PSTORE_TYPE_MCE; else *type = PSTORE_TYPE_UNKNOWN; if (rcd->hdr.validation_bits & CPER_VALID_TIMESTAMP) time->tv_sec = rcd->hdr.timestamp; else time->tv_sec = 0; time->tv_nsec = 0; return len - sizeof(*rcd); } static u64 erst_writer(enum pstore_type_id type, size_t size) { struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); memset(rcd, 0, sizeof(*rcd)); memcpy(rcd->hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE); rcd->hdr.revision = CPER_RECORD_REV; rcd->hdr.signature_end = CPER_SIG_END; rcd->hdr.section_count = 1; rcd->hdr.error_severity = CPER_SEV_FATAL; /* timestamp valid. platform_id, partition_id are invalid */ rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP; rcd->hdr.timestamp = get_seconds(); rcd->hdr.record_length = sizeof(*rcd) + size; rcd->hdr.creator_id = CPER_CREATOR_PSTORE; rcd->hdr.notification_type = CPER_NOTIFY_MCE; rcd->hdr.record_id = cper_next_record_id(); rcd->hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR; rcd->sec_hdr.section_offset = sizeof(*rcd); rcd->sec_hdr.section_length = size; rcd->sec_hdr.revision = CPER_SEC_REV; /* fru_id and fru_text is invalid */ rcd->sec_hdr.validation_bits = 0; rcd->sec_hdr.flags = CPER_SEC_PRIMARY; switch (type) { case PSTORE_TYPE_DMESG: rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG; break; case PSTORE_TYPE_MCE: rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE; break; default: return -EINVAL; } rcd->sec_hdr.section_severity = CPER_SEV_FATAL; erst_write(&rcd->hdr); return rcd->hdr.record_id; } static int __init erst_init(void) { int rc = 0; Loading @@ -788,6 +911,7 @@ static int __init erst_init(void) struct apei_exec_context ctx; struct apei_resources erst_resources; struct resource *r; char *buf; if (acpi_disabled) goto err; Loading Loading @@ -854,6 +978,18 @@ static int __init erst_init(void) if (!erst_erange.vaddr) goto err_release_erange; buf = kmalloc(erst_erange.size, GFP_KERNEL); mutex_init(&erst_info.buf_mutex); if (buf) { erst_info.buf = buf + sizeof(struct cper_pstore_record); erst_info.bufsize = erst_erange.size - sizeof(struct cper_pstore_record); if (pstore_register(&erst_info)) { pr_info(ERST_PFX "Could not register with persistent store\n"); kfree(buf); } } pr_info(ERST_PFX "Error Record Serialization Table (ERST) support is initialized.\n"); Loading fs/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -187,6 +187,7 @@ source "fs/omfs/Kconfig" source "fs/hpfs/Kconfig" source "fs/qnx4/Kconfig" source "fs/romfs/Kconfig" source "fs/pstore/Kconfig" source "fs/sysv/Kconfig" source "fs/ufs/Kconfig" source "fs/exofs/Kconfig" Loading Loading
Documentation/ABI/testing/pstore 0 → 100644 +35 −0 Original line number Diff line number Diff line Where: /dev/pstore/... Date: January 2011 Kernel Version: 2.6.38 Contact: tony.luck@intel.com Description: Generic interface to platform dependent persistent storage. Platforms that provide a mechanism to preserve some data across system reboots can register with this driver to provide a generic interface to show records captured in the dying moments. In the case of a panic the last part of the console log is captured, but other interesting data can also be saved. # mount -t pstore - /dev/pstore $ ls -l /dev/pstore total 0 -r--r--r-- 1 root root 7896 Nov 30 15:38 dmesg-erst-1 Different users of this interface will result in different filename prefixes. Currently two are defined: "dmesg" - saved console log "mce" - architecture dependent data from fatal h/w error Once the information in a file has been read, removing the file will signal to the underlying persistent storage device that it can reclaim the space for later re-use. $ rm /dev/pstore/dmesg-erst-1 The expectation is that all files in /dev/pstore will be saved elsewhere and erased from persistent store soon after boot to free up space ready for the next catastrophe.
Documentation/ABI/testing/sysfs-fs-pstore 0 → 100644 +7 −0 Original line number Diff line number Diff line What: /sys/fs/pstore/kmsg_bytes Date: January 2011 Kernel Version: 2.6.38 Contact: "Tony Luck" <tony.luck@intel.com> Description: Controls amount of console log that will be saved to persistent store on oops/panic.
drivers/acpi/apei/Kconfig +1 −0 Original line number Diff line number Diff line config ACPI_APEI bool "ACPI Platform Error Interface (APEI)" select PSTORE depends on X86 help APEI allows to report errors (for example from the chipset) Loading
drivers/acpi/apei/erst.c +136 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <linux/cper.h> #include <linux/nmi.h> #include <linux/hardirq.h> #include <linux/pstore.h> #include <acpi/apei.h> #include "apei-internal.h" Loading Loading @@ -781,6 +782,128 @@ static int erst_check_table(struct acpi_table_erst *erst_tab) return 0; } static size_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time); static u64 erst_writer(enum pstore_type_id type, size_t size); static struct pstore_info erst_info = { .owner = THIS_MODULE, .name = "erst", .read = erst_reader, .write = erst_writer, .erase = erst_clear }; #define CPER_CREATOR_PSTORE \ UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \ 0x64, 0x90, 0xb8, 0x9d) #define CPER_SECTION_TYPE_DMESG \ UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \ 0x94, 0x19, 0xeb, 0x12) #define CPER_SECTION_TYPE_MCE \ UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \ 0x04, 0x4a, 0x38, 0xfc) struct cper_pstore_record { struct cper_record_header hdr; struct cper_section_descriptor sec_hdr; char data[]; } __packed; static size_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time) { int rc; ssize_t len; unsigned long flags; u64 record_id; struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); if (erst_disable) return -ENODEV; raw_spin_lock_irqsave(&erst_lock, flags); skip: rc = __erst_get_next_record_id(&record_id); if (rc) { raw_spin_unlock_irqrestore(&erst_lock, flags); return rc; } /* no more record */ if (record_id == APEI_ERST_INVALID_RECORD_ID) { raw_spin_unlock_irqrestore(&erst_lock, flags); return 0; } len = __erst_read(record_id, &rcd->hdr, sizeof(*rcd) + erst_erange.size); if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) goto skip; raw_spin_unlock_irqrestore(&erst_lock, flags); *id = record_id; if (uuid_le_cmp(rcd->sec_hdr.section_type, CPER_SECTION_TYPE_DMESG) == 0) *type = PSTORE_TYPE_DMESG; else if (uuid_le_cmp(rcd->sec_hdr.section_type, CPER_SECTION_TYPE_MCE) == 0) *type = PSTORE_TYPE_MCE; else *type = PSTORE_TYPE_UNKNOWN; if (rcd->hdr.validation_bits & CPER_VALID_TIMESTAMP) time->tv_sec = rcd->hdr.timestamp; else time->tv_sec = 0; time->tv_nsec = 0; return len - sizeof(*rcd); } static u64 erst_writer(enum pstore_type_id type, size_t size) { struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); memset(rcd, 0, sizeof(*rcd)); memcpy(rcd->hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE); rcd->hdr.revision = CPER_RECORD_REV; rcd->hdr.signature_end = CPER_SIG_END; rcd->hdr.section_count = 1; rcd->hdr.error_severity = CPER_SEV_FATAL; /* timestamp valid. platform_id, partition_id are invalid */ rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP; rcd->hdr.timestamp = get_seconds(); rcd->hdr.record_length = sizeof(*rcd) + size; rcd->hdr.creator_id = CPER_CREATOR_PSTORE; rcd->hdr.notification_type = CPER_NOTIFY_MCE; rcd->hdr.record_id = cper_next_record_id(); rcd->hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR; rcd->sec_hdr.section_offset = sizeof(*rcd); rcd->sec_hdr.section_length = size; rcd->sec_hdr.revision = CPER_SEC_REV; /* fru_id and fru_text is invalid */ rcd->sec_hdr.validation_bits = 0; rcd->sec_hdr.flags = CPER_SEC_PRIMARY; switch (type) { case PSTORE_TYPE_DMESG: rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG; break; case PSTORE_TYPE_MCE: rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE; break; default: return -EINVAL; } rcd->sec_hdr.section_severity = CPER_SEV_FATAL; erst_write(&rcd->hdr); return rcd->hdr.record_id; } static int __init erst_init(void) { int rc = 0; Loading @@ -788,6 +911,7 @@ static int __init erst_init(void) struct apei_exec_context ctx; struct apei_resources erst_resources; struct resource *r; char *buf; if (acpi_disabled) goto err; Loading Loading @@ -854,6 +978,18 @@ static int __init erst_init(void) if (!erst_erange.vaddr) goto err_release_erange; buf = kmalloc(erst_erange.size, GFP_KERNEL); mutex_init(&erst_info.buf_mutex); if (buf) { erst_info.buf = buf + sizeof(struct cper_pstore_record); erst_info.bufsize = erst_erange.size - sizeof(struct cper_pstore_record); if (pstore_register(&erst_info)) { pr_info(ERST_PFX "Could not register with persistent store\n"); kfree(buf); } } pr_info(ERST_PFX "Error Record Serialization Table (ERST) support is initialized.\n"); Loading
fs/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -187,6 +187,7 @@ source "fs/omfs/Kconfig" source "fs/hpfs/Kconfig" source "fs/qnx4/Kconfig" source "fs/romfs/Kconfig" source "fs/pstore/Kconfig" source "fs/sysv/Kconfig" source "fs/ufs/Kconfig" source "fs/exofs/Kconfig" Loading