From: Len Brown <lenb@kernel.org>
To: linux-acpi@vger.kernel.org
Cc: Huang Ying <ying.huang@intel.com>, Len Brown <len.brown@intel.com>
Subject: [PATCH 49/60] Hardware error record persistent support
Date: Mon, 25 Oct 2010 02:20:57 -0400 [thread overview]
Message-ID: <af7e02c78484aa273ce7bb1d2caa3a2ae0665a18.1287987547.git.len.brown@intel.com> (raw)
In-Reply-To: <1287987668-17584-1-git-send-email-lenb@kernel.org>
In-Reply-To: <a210080195c95ebca2a517ee3057d71607aa65e0.1287987547.git.len.brown@intel.com>
From: Huang Ying <ying.huang@intel.com>
Normally, corrected hardware error records will go through the kernel
processing and be logged to disk or network finally. But for
uncorrected errors, system may go panic directly for better error
containment, disk or network is not usable in this half-working
system. To avoid losing these valuable hardware error records, the
error records are saved into some kind of simple persistent storage
such as flash before panic, so that they can be read out after system
reboot successfully.
Different kind of simple persistent storage implementation mechanisms
are provided on different platforms, so an abstract interface for
persistent storage is defined. Different implementations of the
interface can be registered.
This patch is designed by Andi Kleen and Huang Ying.
Signed-off-by: Huang Ying <ying.huang@intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/char/herror/Makefile | 2 +-
drivers/char/herror/herr-core.c | 39 +++++++-
drivers/char/herror/herr-internal.h | 12 +++
drivers/char/herror/herr-persist.c | 174 +++++++++++++++++++++++++++++++++++
include/linux/Kbuild | 1 +
include/linux/herror.h | 48 ++++++++++-
6 files changed, 271 insertions(+), 5 deletions(-)
create mode 100644 drivers/char/herror/herr-internal.h
create mode 100644 drivers/char/herror/herr-persist.c
diff --git a/drivers/char/herror/Makefile b/drivers/char/herror/Makefile
index e47b7bf..5452df0 100644
--- a/drivers/char/herror/Makefile
+++ b/drivers/char/herror/Makefile
@@ -1 +1 @@
-obj-y += herr-core.o
+obj-y += herr-core.o herr-persist.o
diff --git a/drivers/char/herror/herr-core.c b/drivers/char/herror/herr-core.c
index aeff738..42b9cb9 100644
--- a/drivers/char/herror/herr-core.c
+++ b/drivers/char/herror/herr-core.c
@@ -43,9 +43,9 @@
#include <linux/llalloc.h>
#include <linux/herror.h>
-#define HERR_NOTIFY_BIT 0
+#include "herr-internal.h"
-static unsigned long herr_flags;
+unsigned long herr_flags;
/*
* Record list management and error reporting
@@ -524,6 +524,7 @@ static ssize_t herr_mix_read(struct file *filp, char __user *ubuf,
{
int rc;
static DEFINE_MUTEX(read_mutex);
+ u64 record_id;
if (*off != 0)
return -EINVAL;
@@ -531,7 +532,14 @@ static ssize_t herr_mix_read(struct file *filp, char __user *ubuf,
rc = mutex_lock_interruptible(&read_mutex);
if (rc)
return rc;
+ rc = herr_persist_peek_user(&record_id, ubuf, usize);
+ if (rc > 0) {
+ herr_persist_clear(record_id);
+ goto out;
+ }
+
rc = herr_rcd_lists_read(ubuf, usize, &read_mutex);
+out:
mutex_unlock(&read_mutex);
return rc;
@@ -540,15 +548,40 @@ static ssize_t herr_mix_read(struct file *filp, char __user *ubuf,
static unsigned int herr_mix_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &herr_mix_wait, wait);
- if (!herr_rcd_lists_is_empty())
+ if (!herr_rcd_lists_is_empty() || !herr_persist_read_done())
return POLLIN | POLLRDNORM;
return 0;
}
+static long herr_mix_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+ void __user *p = (void __user *)arg;
+ int rc;
+ u64 record_id;
+ struct herr_persist_buffer buf;
+
+ switch (cmd) {
+ case HERR_PERSIST_PEEK:
+ rc = copy_from_user(&buf, p, sizeof(buf));
+ if (rc)
+ return -EFAULT;
+ return herr_persist_peek_user(&record_id, buf.buf,
+ buf.buf_size);
+ case HERR_PERSIST_CLEAR:
+ rc = copy_from_user(&record_id, p, sizeof(record_id));
+ if (rc)
+ return -EFAULT;
+ return herr_persist_clear(record_id);
+ default:
+ return -ENOTTY;
+ }
+}
+
static const struct file_operations herr_mix_dev_fops = {
.owner = THIS_MODULE,
.read = herr_mix_read,
.poll = herr_mix_poll,
+ .unlocked_ioctl = herr_mix_ioctl,
};
static int __init herr_mix_dev_init(void)
diff --git a/drivers/char/herror/herr-internal.h b/drivers/char/herror/herr-internal.h
new file mode 100644
index 0000000..43e75ca
--- /dev/null
+++ b/drivers/char/herror/herr-internal.h
@@ -0,0 +1,12 @@
+#ifndef HERR_INTERNAL_H
+#define HERR_INTERNAL_H
+
+#define HERR_NOTIFY_BIT 0
+
+extern unsigned long herr_flags;
+
+int herr_persist_read_done(void);
+ssize_t herr_persist_peek_user(u64 *record_id, char __user *ercd,
+ size_t bufsiz);
+int herr_persist_clear(u64 record_id);
+#endif /* HERR_INTERNAL_H */
diff --git a/drivers/char/herror/herr-persist.c b/drivers/char/herror/herr-persist.c
new file mode 100644
index 0000000..106298f
--- /dev/null
+++ b/drivers/char/herror/herr-persist.c
@@ -0,0 +1,174 @@
+/*
+ * Hardware error record persistent support
+ *
+ * Normally, corrected hardware error records will go through the
+ * kernel processing and be logged to disk or network finally. But
+ * for uncorrected errors, system may go panic directly for better
+ * error containment, disk or network is not usable in this
+ * half-working system. To avoid losing these valuable hardware error
+ * records, the error records are saved into some kind of simple
+ * persistent storage such as flash before panic, so that they can be
+ * read out after system reboot successfully.
+ *
+ * Copyright 2010 Intel Corp.
+ * Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rculist.h>
+#include <linux/mutex.h>
+
+#include <linux/herror.h>
+
+#include "herr-internal.h"
+
+/*
+ * Simple persistent storage provider list, herr_persists_mutex is
+ * used for writer side mutual exclusion, RCU is used to implement
+ * lock-less reader side.
+ */
+static LIST_HEAD(herr_persists);
+static DEFINE_MUTEX(herr_persists_mutex);
+
+int herr_persist_register(struct herr_persist *persist)
+{
+ if (!persist->peek_user)
+ return -EINVAL;
+ persist->read_done = 0;
+ if (mutex_lock_interruptible(&herr_persists_mutex))
+ return -EINTR;
+ list_add_rcu(&persist->list, &herr_persists);
+ mutex_unlock(&herr_persists_mutex);
+ /*
+ * There may be hardware error records of previous boot in
+ * persistent storage, notify the user space error daemon to
+ * check.
+ */
+ set_bit(HERR_NOTIFY_BIT, &herr_flags);
+ herr_notify();
+ return 0;
+}
+EXPORT_SYMBOL_GPL(herr_persist_register);
+
+void herr_persist_unregister(struct herr_persist *persist)
+{
+ mutex_lock(&herr_persists_mutex);
+ list_del_rcu(&persist->list);
+ mutex_unlock(&herr_persists_mutex);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(herr_persist_unregister);
+
+/* Can be used in atomic context including NMI */
+int herr_persist_in(const struct herr_record *ercd)
+{
+ struct herr_persist *persist;
+ int rc = -ENODEV;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(persist, &herr_persists, list) {
+ if (!persist->in)
+ continue;
+ rc = persist->in(ercd);
+ if (!rc)
+ break;
+ }
+ rcu_read_unlock();
+ return rc;
+}
+EXPORT_SYMBOL_GPL(herr_persist_in);
+
+int herr_persist_read_done(void)
+{
+ struct herr_persist *persist;
+ int rc = 1;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(persist, &herr_persists, list) {
+ if (!persist->read_done) {
+ rc = 0;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ return rc;
+}
+
+/* Read next error record from persist storage, don't remove it */
+ssize_t herr_persist_peek_user(u64 *record_id, char __user *ercd,
+ size_t bufsiz)
+{
+ struct herr_persist *persist;
+ ssize_t rc = 0;
+
+ if (mutex_lock_interruptible(&herr_persists_mutex))
+ return -EINTR;
+ list_for_each_entry(persist, &herr_persists, list) {
+ if (persist->read_done)
+ continue;
+ rc = persist->peek_user(record_id, ercd, bufsiz);
+ if (rc > 0)
+ break;
+ else if (rc != -EINTR && rc != -EAGAIN && rc != -EINVAL)
+ persist->read_done = 1;
+ }
+ mutex_unlock(&herr_persists_mutex);
+ return rc;
+}
+
+/* Clear specified error record from persist storage */
+int herr_persist_clear(u64 record_id)
+{
+ struct herr_persist *persist;
+ int rc = -ENOENT;
+
+ if (mutex_lock_interruptible(&herr_persists_mutex))
+ return -EINTR;
+ list_for_each_entry(persist, &herr_persists, list) {
+ if (!persist->clear)
+ continue;
+ rc = persist->clear(record_id);
+ if (!rc)
+ break;
+ /*
+ * Failed to clear, mark as read_done, because we can
+ * not skip this one
+ */
+ else if (rc != -EINTR && rc != -EAGAIN && rc != -ENOENT)
+ persist->read_done = 1;
+ }
+ mutex_unlock(&herr_persists_mutex);
+ return rc;
+}
+
+static int herr_persist_record(struct herr_record *ercd, void *data)
+{
+ int *severity = data;
+
+ if (ercd->severity == *severity)
+ return herr_persist_in(ercd);
+ return 0;
+}
+
+void herr_persist_all_records(void)
+{
+ int severity;
+
+ for (severity = HERR_SEV_FATAL; severity >= HERR_SEV_NONE; severity--)
+ herr_for_each_record(herr_persist_record, &severity);
+}
+EXPORT_SYMBOL_GPL(herr_persist_all_records);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 3b31865..abfd16f 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -141,6 +141,7 @@ header-y += hdlc.h
header-y += hdlcdrv.h
header-y += hdreg.h
header-y += herror_record.h
+header-y += herror.h
header-y += hid.h
header-y += hiddev.h
header-y += hidraw.h
diff --git a/include/linux/herror.h b/include/linux/herror.h
index aba1102..4635df6 100644
--- a/include/linux/herror.h
+++ b/include/linux/herror.h
@@ -1,10 +1,22 @@
#ifndef LINUX_HERROR_H
#define LINUX_HERROR_H
+#include <linux/ioctl.h>
+#include <linux/herror_record.h>
+
+struct herr_persist_buffer {
+ void __user *buf;
+ unsigned int buf_size;
+};
+
+#define HERR_PERSIST_PEEK _IOW('H', 1, struct herr_persist_buffer)
+#define HERR_PERSIST_CLEAR _IOW('H', 2, u64)
+
+#ifdef __KERNEL__
+
#include <linux/types.h>
#include <linux/list.h>
#include <linux/device.h>
-#include <linux/herror_record.h>
/*
* Hardware error reporting
@@ -66,4 +78,38 @@ static inline void herr_dev_put(struct herr_dev *dev)
int herr_dev_register(struct herr_dev *dev);
void herr_dev_unregister(struct herr_dev *dev);
+
+
+/*
+ * Simple Persistent Storage
+ */
+
+struct herr_persist;
+/* Put an error record into simple persistent storage */
+int herr_persist_in(const struct herr_record *ercd);
+/* Save all error records not yet consumed in persistent storage */
+void herr_persist_all_records(void);
+
+/*
+ * Simple Persistent Storage Provider Management
+ */
+struct herr_persist {
+ struct list_head list;
+ char *name;
+ unsigned int read_done:1;
+ /* Put an error record into storage, must be NMI-safe */
+ int (*in)(const struct herr_record *ercd);
+ /*
+ * Read out an error record from storage to user space, don't
+ * remove it, the HERR_RCD_PERSIST must be set in record flags
+ */
+ ssize_t (*peek_user)(u64 *record_id, char __user *ubuf, size_t usize);
+ /* Clear an error record */
+ int (*clear)(u64 record_id);
+};
+
+/* Register (un-register) simple persistent storage provider */
+int herr_persist_register(struct herr_persist *persist);
+void herr_persist_unregister(struct herr_persist *persist);
+#endif
#endif
--
1.7.3.2.90.gd4c43
next prev parent reply other threads:[~2010-10-25 8:11 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-25 6:20 ACPI patches for 2.6.37-merge Len Brown
2010-10-25 6:20 ` [PATCH 01/60] ACPI / ACPICA: Defer enabling of runtime GPEs (v3) Len Brown
2010-10-25 6:20 ` [PATCH 02/60] ACPICA: Fix acpi_os_read_pci_configuration prototype Len Brown
2010-10-25 6:20 ` [PATCH 03/60] ACPICA: Revert "Revert "Enable multi-byte EC transfers Len Brown
2010-10-25 6:20 ` [PATCH 04/60] ACPICA/ACPI: Add new host interfaces for _OSI support Len Brown
2010-10-25 6:20 ` [PATCH 05/60] ACPICA: Update version to 20100806 Len Brown
2010-10-25 6:20 ` [PATCH 06/60] ACPICA: Obsolete the acpi_os_derive_pci_id OSL interface Len Brown
2010-10-25 6:20 ` [PATCH 07/60] ACPICA: Add ACPI_INLINE configuration parameter Len Brown
2010-10-25 6:20 ` [PATCH 08/60] ACPICA: Make acpi_thread_id no longer configurable, always u64 Len Brown
2010-10-25 6:20 ` [PATCH 09/60] ACPICA: Update math module; no functional change Len Brown
2010-10-25 6:20 ` [PATCH 10/60] ACPICA: Make acpi_gbl_system_awake_and_running publically available Len Brown
2010-10-25 6:20 ` [PATCH 11/60] ACPICA: iASL/Disassembler: Write ACPI errors to stderr instead of output file Len Brown
2010-10-25 6:20 ` [PATCH 12/60] ACPICA: Add repair for _HID and _CID strings Len Brown
2010-10-25 6:20 ` [PATCH 13/60] ACPICA: Increase configurability of error messages Len Brown
2010-10-25 6:20 ` [PATCH 14/60] ACPICA: Update version to 20100915 Len Brown
2010-10-25 6:20 ` [PATCH 15/60] PNP: log PNP resources, as we do for PCI Len Brown
2010-10-25 6:20 ` [PATCH 16/60] PNPACPI: cope with invalid device IDs Len Brown
2010-10-25 6:20 ` [PATCH 17/60] ACPI: Remove unused #define ACPI_PROCESSOR_FILE_POWER Len Brown
2010-10-25 6:20 ` [PATCH 18/60] ACPI: Do not export hid/modalias sysfs file for ACPI objects without a HID Len Brown
2010-10-25 6:20 ` [PATCH 19/60] ACPI/PNP: A HID value of an object never changes -> make it const Len Brown
2010-10-25 6:20 ` [PATCH 20/60] acpi-cpufreq: fix a memleak when unloading driver Len Brown
2010-10-25 6:20 ` [PATCH 21/60] ACPI / PM: Fix problems with acpi_pm_device_sleep_state() Len Brown
2010-10-25 6:20 ` [PATCH 22/60] ACPI: add FW_BUG to OSI(Linux) message Len Brown
2010-10-25 6:20 ` [PATCH 23/60] ACPI ac/battery/sbs: sysfs I/F always built in, procfs I/F disabled by default Len Brown
2010-10-25 6:20 ` [PATCH 24/60] ACPI fan: remove deprecated procfs I/F Len Brown
2010-10-25 6:20 ` [PATCH 25/60] ACPI thermal: " Len Brown
2010-10-25 6:20 ` [PATCH 26/60] ACPI video: " Len Brown
2010-10-25 6:20 ` [PATCH 27/60] ACPI processor: make /proc/acpi/processor/*/throttle depends on CONFIG_ACPI_PROCFS Len Brown
2010-10-25 6:20 ` [PATCH 28/60] ACPI: remove unused declaration of proc_fs.h Len Brown
2010-10-25 6:20 ` [PATCH 29/60] ACPICA: Comment update; no functional change Len Brown
2010-10-25 6:20 ` [PATCH 30/60] ACPICA: Change type of _TZ from ThermalZone to Device Len Brown
2010-10-25 6:20 ` [PATCH 31/60] ACPICA: Eliminate duplicate code in acpi_ut_execute_* functions Len Brown
2010-10-25 6:20 ` [PATCH 32/60] ACPICA: Add Vista SP2 to supported _OSI strings Len Brown
2010-10-25 6:20 ` [PATCH 33/60] ACPICA: Clear PCIEXP_WAKE_STS when clearing ACPI events Len Brown
2010-10-25 6:20 ` [PATCH 34/60] ACPICA: Update version to 20101013 Len Brown
2010-10-25 6:20 ` [PATCH 35/60] ACPI: Only processor needs CPU_IDLE Len Brown
2010-10-25 6:20 ` [PATCH 36/60] ACPI: delete dedicated MAINTAINERS entries for ACPI EC and BATTERY drivers Len Brown
2010-10-25 6:20 ` [PATCH 37/60] ACPI: remove dead code Len Brown
2010-10-25 6:20 ` [PATCH 38/60] ACPI: static sleep_states[] and acpi_gts_bfs_check Len Brown
2010-10-25 6:20 ` [PATCH 39/60] ACPI: thermal: remove unused limit code Len Brown
2010-10-25 6:20 ` [PATCH 40/60] ACPI dock: move some functions to .init.text Len Brown
2010-10-25 6:20 ` [PATCH 41/60] ACPI: Make Embedded Controller command timeout delay configurable Len Brown
2010-10-25 6:20 ` [PATCH 42/60] ACPI battery: support percentage battery remaining capacity Len Brown
2010-10-25 6:20 ` [PATCH 43/60] Subject: [PATCH] ACPICA: Fix Scope() op in module level code Len Brown
2010-10-25 6:20 ` [PATCH 44/60] ACPI, APEI, Add ERST record ID cache Len Brown
2010-10-25 8:56 ` Ingo Molnar
2010-10-25 6:20 ` [PATCH 45/60] Add lock-less version of bitmap_set/clear Len Brown
2010-10-25 6:20 ` [PATCH 46/60] lock-less NULL terminated single list implementation Len Brown
2010-10-25 6:20 ` [PATCH 47/60] lock-less general memory allocator Len Brown
2010-10-25 6:20 ` [PATCH 48/60] Hardware error device core Len Brown
2010-10-25 6:20 ` Len Brown [this message]
2010-10-25 6:20 ` [PATCH 50/60] ACPI, APEI, Use ERST for hardware error persisting before panic Len Brown
2010-10-25 6:20 ` [PATCH 51/60] ACPI, APEI, Report GHES error record with hardware error device core Len Brown
2010-10-25 6:21 ` [PATCH 52/60] ACPI, APEI, Generic Hardware Error Source POLL/IRQ/NMI notification type support Len Brown
2010-10-25 6:21 ` [PATCH 53/60] ACPI / PM: Fix reference counting of power resources Len Brown
2010-10-25 6:21 ` [PATCH 54/60] ACPI / Battery: Return -ENODEV for unknown values in get_property() Len Brown
2010-10-25 6:21 ` [PATCH 55/60] ACPI: Fix ioremap size for MMIO reads and writes Len Brown
2010-10-25 6:21 ` [PATCH 56/60] ACPI: Maintain a list of ACPI memory mapped I/O remappings Len Brown
2010-10-25 6:21 ` [PATCH 57/60] ACPI: Add interfaces for ioremapping/iounmapping ACPI registers Len Brown
2010-10-25 6:21 ` [PATCH 58/60] ACPI: Pre-map 'system event' related register blocks Len Brown
2010-10-25 6:21 ` [PATCH 59/60] ACPI: Convert simple locking to RCU based locking Len Brown
2010-10-25 6:21 ` [PATCH 60/60] ACPI: Page based coalescing of I/O remappings optimization Len Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=af7e02c78484aa273ce7bb1d2caa3a2ae0665a18.1287987547.git.len.brown@intel.com \
--to=lenb@kernel.org \
--cc=len.brown@intel.com \
--cc=linux-acpi@vger.kernel.org \
--cc=ying.huang@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).