2012-05-16 12:42:42

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH v2 0/6] Merge ramoops and persistent_ram, generic pstore RAM backend

Hi all,

Here is v2 of the previous patch set. The series do not include
patches that were already merged.

I believe I addressed all the previous comments, plus now the
series include another small cleanup patch.

Here's some background for the series:

There are currently two competing debug facilities to store kernel
messages in a persistent storage: a generic pstore and Google's
persistent_ram. Not so long ago (https://lkml.org/lkml/2012/3/8/252),
it was decided that we should fix this situation.

Recently ramoops has switched to pstore, which basically means that
it became a RAM backend for the pstore framework.

persistent_ram+ram_console and ramoops+pstore have almost the same
features, except:

1. Ramoops doesn't support ECC. Having ECC is useful when a hardware
reset was used to bring the machine back to life (i.e. a watchdog
triggered). In such cases, RAM may be somewhat corrupt, but
usually it is restorable.

2. Pstore doesn't support logging kernel messages in run-time, it only
dumps dmesg when kernel oopses/panics. This makes pstore useless for
debugging hangs caused by HW issues or improper use of HW (e.g.
weird device inserted -> driver tried to write a reserved bits ->
SoC hanged. In that case we don't get any messages in the pstore.

These patches solve the first issue, plus move things to their
proper places. Patches that will fix the second issue will be sent
shortly.

---
Documentation/ramoops.txt | 8 +-
drivers/char/Kconfig | 9 -
drivers/char/Makefile | 1 -
drivers/char/ramoops.c | 362 --------------------
drivers/staging/android/Kconfig | 10 +-
drivers/staging/android/Makefile | 1 -
drivers/staging/android/persistent_ram.c | 530 -----------------------------
drivers/staging/android/persistent_ram.h | 84 -----
drivers/staging/android/ram_console.c | 2 +-
fs/pstore/Kconfig | 17 +
fs/pstore/Makefile | 3 +
fs/pstore/ram.c | 383 +++++++++++++++++++++
fs/pstore/ram_core.c | 532 ++++++++++++++++++++++++++++++
include/linux/pstore_ram.h | 98 ++++++
include/linux/ramoops.h | 17 -
15 files changed, 1042 insertions(+), 1015 deletions(-)

--
Anton Vorontsov
Email: [email protected]


2012-05-16 12:44:28

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 1/6] persistent_ram: Remove never used struct persistent_ram_zone members

Remove 'old_log_footer_size' and 'early' members of struct
persistent_ram_zone, as these were never used at all.

Signed-off-by: Anton Vorontsov <[email protected]>
---
drivers/staging/android/persistent_ram.h | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/staging/android/persistent_ram.h b/drivers/staging/android/persistent_ram.h
index d3b2b45..d23850c 100644
--- a/drivers/staging/android/persistent_ram.h
+++ b/drivers/staging/android/persistent_ram.h
@@ -59,8 +59,6 @@ struct persistent_ram_zone {

char *old_log;
size_t old_log_size;
- size_t old_log_footer_size;
- bool early;
};

int persistent_ram_early_init(struct persistent_ram *ram);
--
1.7.9.2

2012-05-16 12:44:42

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 2/6] ramoops: Move to fs/pstore/ram.c

Since ramoops was converted to pstore, it has nothing to do with character
devices nowadays. Instead, today it is just a RAM backend for pstore.

The patch just moves things around. There are a few changes were needed
because of the move:

1. Kconfig and Makefiles fixups, of course.

2. In pstore/ram.c we have to play a bit with MODULE_PARAM_PREFIX, this
is needed to keep user experience the same as with ramoops driver
(i.e. so that ramoops.foo kernel command line arguments would still
work).

Signed-off-by: Anton Vorontsov <[email protected]>
Acked-by: Marco Stornelli <[email protected]>
---
Documentation/ramoops.txt | 2 +-
drivers/char/Kconfig | 9 --
drivers/char/Makefile | 1 -
drivers/char/ramoops.c | 362 --------------------------------------------
fs/pstore/Kconfig | 14 ++
fs/pstore/Makefile | 3 +
fs/pstore/ram.c | 362 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/pstore_ram.h | 17 +++
include/linux/ramoops.h | 17 ---
9 files changed, 397 insertions(+), 390 deletions(-)
delete mode 100644 drivers/char/ramoops.c
create mode 100644 fs/pstore/ram.c
create mode 100644 include/linux/pstore_ram.h
delete mode 100644 include/linux/ramoops.h

diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
index a0b9d8e..470d2c4 100644
--- a/Documentation/ramoops.txt
+++ b/Documentation/ramoops.txt
@@ -38,7 +38,7 @@ Setting the ramoops parameters can be done in 2 different manners:
2. Use a platform device and set the platform data. The parameters can then
be set through that platform data. An example of doing that is:

-#include <linux/ramoops.h>
+#include <linux/pstore_ram.h>
[...]

static struct ramoops_platform_data ramoops_data = {
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index fab778d4..ea6f632 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -585,15 +585,6 @@ config DEVPORT

source "drivers/s390/char/Kconfig"

-config RAMOOPS
- tristate "Log panic/oops to a RAM buffer"
- depends on HAS_IOMEM
- depends on PSTORE
- default n
- help
- This enables panic and oops messages to be logged to a circular
- buffer in RAM where it can be read back at some later point.
-
config MSM_SMD_PKT
bool "Enable device interface for some SMD packet ports"
default n
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 0dc5d7c..d0b27a3 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -58,7 +58,6 @@ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/

obj-$(CONFIG_PS3_FLASH) += ps3flash.o
-obj-$(CONFIG_RAMOOPS) += ramoops.o

obj-$(CONFIG_JS_RTC) += js-rtc.o
js-rtc-y = rtc.o
diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
deleted file mode 100644
index b8b8542..0000000
--- a/drivers/char/ramoops.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * RAM Oops/Panic logger
- *
- * Copyright (C) 2010 Marco Stornelli <[email protected]>
- * Copyright (C) 2011 Kees Cook <[email protected]>
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/pstore.h>
-#include <linux/time.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/ramoops.h>
-
-#define RAMOOPS_KERNMSG_HDR "===="
-#define MIN_MEM_SIZE 4096UL
-
-static ulong record_size = MIN_MEM_SIZE;
-module_param(record_size, ulong, 0400);
-MODULE_PARM_DESC(record_size,
- "size of each dump done on oops/panic");
-
-static ulong mem_address;
-module_param(mem_address, ulong, 0400);
-MODULE_PARM_DESC(mem_address,
- "start of reserved RAM used to store oops/panic logs");
-
-static ulong mem_size;
-module_param(mem_size, ulong, 0400);
-MODULE_PARM_DESC(mem_size,
- "size of reserved RAM used to store oops/panic logs");
-
-static int dump_oops = 1;
-module_param(dump_oops, int, 0600);
-MODULE_PARM_DESC(dump_oops,
- "set to 1 to dump oopses, 0 to only dump panics (default 1)");
-
-struct ramoops_context {
- void *virt_addr;
- phys_addr_t phys_addr;
- unsigned long size;
- size_t record_size;
- int dump_oops;
- unsigned int count;
- unsigned int max_count;
- unsigned int read_count;
- struct pstore_info pstore;
-};
-
-static struct platform_device *dummy;
-static struct ramoops_platform_data *dummy_data;
-
-static int ramoops_pstore_open(struct pstore_info *psi)
-{
- struct ramoops_context *cxt = psi->data;
-
- cxt->read_count = 0;
- return 0;
-}
-
-static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
- struct timespec *time,
- char **buf,
- struct pstore_info *psi)
-{
- ssize_t size;
- char *rambuf;
- struct ramoops_context *cxt = psi->data;
-
- if (cxt->read_count >= cxt->max_count)
- return -EINVAL;
- *id = cxt->read_count++;
- /* Only supports dmesg output so far. */
- *type = PSTORE_TYPE_DMESG;
- /* TODO(kees): Bogus time for the moment. */
- time->tv_sec = 0;
- time->tv_nsec = 0;
-
- rambuf = cxt->virt_addr + (*id * cxt->record_size);
- size = strnlen(rambuf, cxt->record_size);
- *buf = kmalloc(size, GFP_KERNEL);
- if (*buf == NULL)
- return -ENOMEM;
- memcpy(*buf, rambuf, size);
-
- return size;
-}
-
-static int ramoops_pstore_write(enum pstore_type_id type,
- enum kmsg_dump_reason reason,
- u64 *id,
- unsigned int part,
- size_t size, struct pstore_info *psi)
-{
- char *buf;
- size_t res;
- struct timeval timestamp;
- struct ramoops_context *cxt = psi->data;
- size_t available = cxt->record_size;
-
- /* Currently ramoops is designed to only store dmesg dumps. */
- if (type != PSTORE_TYPE_DMESG)
- return -EINVAL;
-
- /* Out of the various dmesg dump types, ramoops is currently designed
- * to only store crash logs, rather than storing general kernel logs.
- */
- if (reason != KMSG_DUMP_OOPS &&
- reason != KMSG_DUMP_PANIC)
- return -EINVAL;
-
- /* Skip Oopes when configured to do so. */
- if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
- return -EINVAL;
-
- /* Explicitly only take the first part of any new crash.
- * If our buffer is larger than kmsg_bytes, this can never happen,
- * and if our buffer is smaller than kmsg_bytes, we don't want the
- * report split across multiple records.
- */
- if (part != 1)
- return -ENOSPC;
-
- buf = cxt->virt_addr + (cxt->count * cxt->record_size);
-
- res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
- buf += res;
- available -= res;
-
- do_gettimeofday(&timestamp);
- res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
- buf += res;
- available -= res;
-
- if (size > available)
- size = available;
-
- memcpy(buf, cxt->pstore.buf, size);
- memset(buf + size, '\0', available - size);
-
- cxt->count = (cxt->count + 1) % cxt->max_count;
-
- return 0;
-}
-
-static int ramoops_pstore_erase(enum pstore_type_id type, u64 id,
- struct pstore_info *psi)
-{
- char *buf;
- struct ramoops_context *cxt = psi->data;
-
- if (id >= cxt->max_count)
- return -EINVAL;
-
- buf = cxt->virt_addr + (id * cxt->record_size);
- memset(buf, '\0', cxt->record_size);
-
- return 0;
-}
-
-static struct ramoops_context oops_cxt = {
- .pstore = {
- .owner = THIS_MODULE,
- .name = "ramoops",
- .open = ramoops_pstore_open,
- .read = ramoops_pstore_read,
- .write = ramoops_pstore_write,
- .erase = ramoops_pstore_erase,
- },
-};
-
-static int __init ramoops_probe(struct platform_device *pdev)
-{
- struct ramoops_platform_data *pdata = pdev->dev.platform_data;
- struct ramoops_context *cxt = &oops_cxt;
- int err = -EINVAL;
-
- /* Only a single ramoops area allowed at a time, so fail extra
- * probes.
- */
- if (cxt->max_count)
- goto fail_out;
-
- if (!pdata->mem_size || !pdata->record_size) {
- pr_err("The memory size and the record size must be "
- "non-zero\n");
- goto fail_out;
- }
-
- pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
- pdata->record_size = rounddown_pow_of_two(pdata->record_size);
-
- /* Check for the minimum memory size */
- if (pdata->mem_size < MIN_MEM_SIZE &&
- pdata->record_size < MIN_MEM_SIZE) {
- pr_err("memory size too small, minimum is %lu\n",
- MIN_MEM_SIZE);
- goto fail_out;
- }
-
- if (pdata->mem_size < pdata->record_size) {
- pr_err("The memory size must be larger than the "
- "records size\n");
- goto fail_out;
- }
-
- cxt->max_count = pdata->mem_size / pdata->record_size;
- cxt->count = 0;
- cxt->size = pdata->mem_size;
- cxt->phys_addr = pdata->mem_address;
- cxt->record_size = pdata->record_size;
- cxt->dump_oops = pdata->dump_oops;
-
- cxt->pstore.data = cxt;
- cxt->pstore.bufsize = cxt->record_size;
- cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
- spin_lock_init(&cxt->pstore.buf_lock);
- if (!cxt->pstore.buf) {
- pr_err("cannot allocate pstore buffer\n");
- goto fail_clear;
- }
-
- if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
- pr_err("request mem region (0x%lx@0x%llx) failed\n",
- cxt->size, (unsigned long long)cxt->phys_addr);
- err = -EINVAL;
- goto fail_buf;
- }
-
- cxt->virt_addr = ioremap(cxt->phys_addr, cxt->size);
- if (!cxt->virt_addr) {
- pr_err("ioremap failed\n");
- goto fail_mem_region;
- }
-
- err = pstore_register(&cxt->pstore);
- if (err) {
- pr_err("registering with pstore failed\n");
- goto fail_iounmap;
- }
-
- /*
- * Update the module parameter variables as well so they are visible
- * through /sys/module/ramoops/parameters/
- */
- mem_size = pdata->mem_size;
- mem_address = pdata->mem_address;
- record_size = pdata->record_size;
- dump_oops = pdata->dump_oops;
-
- pr_info("attached 0x%lx@0x%llx (%ux0x%zx)\n",
- cxt->size, (unsigned long long)cxt->phys_addr,
- cxt->max_count, cxt->record_size);
-
- return 0;
-
-fail_iounmap:
- iounmap(cxt->virt_addr);
-fail_mem_region:
- release_mem_region(cxt->phys_addr, cxt->size);
-fail_buf:
- kfree(cxt->pstore.buf);
-fail_clear:
- cxt->pstore.bufsize = 0;
- cxt->max_count = 0;
-fail_out:
- return err;
-}
-
-static int __exit ramoops_remove(struct platform_device *pdev)
-{
-#if 0
- /* TODO(kees): We cannot unload ramoops since pstore doesn't support
- * unregistering yet.
- */
- struct ramoops_context *cxt = &oops_cxt;
-
- iounmap(cxt->virt_addr);
- release_mem_region(cxt->phys_addr, cxt->size);
- cxt->max_count = 0;
-
- /* TODO(kees): When pstore supports unregistering, call it here. */
- kfree(cxt->pstore.buf);
- cxt->pstore.bufsize = 0;
-
- return 0;
-#endif
- return -EBUSY;
-}
-
-static struct platform_driver ramoops_driver = {
- .remove = __exit_p(ramoops_remove),
- .driver = {
- .name = "ramoops",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init ramoops_init(void)
-{
- int ret;
- ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
- if (ret == -ENODEV) {
- /*
- * If we didn't find a platform device, we use module parameters
- * building platform data on the fly.
- */
- pr_info("platform device not found, using module parameters\n");
- dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
- GFP_KERNEL);
- if (!dummy_data)
- return -ENOMEM;
- dummy_data->mem_size = mem_size;
- dummy_data->mem_address = mem_address;
- dummy_data->record_size = record_size;
- dummy_data->dump_oops = dump_oops;
- dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
- NULL, 0, dummy_data,
- sizeof(struct ramoops_platform_data));
-
- if (IS_ERR(dummy))
- ret = PTR_ERR(dummy);
- else
- ret = 0;
- }
-
- return ret;
-}
-
-static void __exit ramoops_exit(void)
-{
- platform_driver_unregister(&ramoops_driver);
- kfree(dummy_data);
-}
-
-module_init(ramoops_init);
-module_exit(ramoops_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marco Stornelli <[email protected]>");
-MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 8007ae7..b75ee51 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -11,3 +11,17 @@ config PSTORE
(e.g. ACPI_APEI on X86) which will select this for you.
If you don't have a platform persistent store driver,
say N.
+
+config PSTORE_RAM
+ tristate "Log panic/oops to a RAM buffer"
+ depends on HAS_IOMEM
+ depends on PSTORE
+ default n
+ help
+ This enables panic and oops messages to be logged to a circular
+ buffer in RAM where it can be read back at some later point.
+
+ Note that for historical reasons, the module will be named
+ "ramoops.ko".
+
+ For more information, see Documentation/ramoops.txt.
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index 760f4bc..2ab3d0d 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -5,3 +5,6 @@
obj-y += pstore.o

pstore-objs += inode.o platform.o
+
+ramoops-objs += ram.o
+obj-$(CONFIG_PSTORE_RAM) += ramoops.o
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
new file mode 100644
index 0000000..e443c9c
--- /dev/null
+++ b/fs/pstore/ram.c
@@ -0,0 +1,362 @@
+/*
+ * RAM Oops/Panic logger
+ *
+ * Copyright (C) 2010 Marco Stornelli <[email protected]>
+ * Copyright (C) 2011 Kees Cook <[email protected]>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/pstore.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pstore_ram.h>
+
+#define RAMOOPS_KERNMSG_HDR "===="
+#define MIN_MEM_SIZE 4096UL
+
+static ulong record_size = MIN_MEM_SIZE;
+module_param(record_size, ulong, 0400);
+MODULE_PARM_DESC(record_size,
+ "size of each dump done on oops/panic");
+
+static ulong mem_address;
+module_param(mem_address, ulong, 0400);
+MODULE_PARM_DESC(mem_address,
+ "start of reserved RAM used to store oops/panic logs");
+
+static ulong mem_size;
+module_param(mem_size, ulong, 0400);
+MODULE_PARM_DESC(mem_size,
+ "size of reserved RAM used to store oops/panic logs");
+
+static int dump_oops = 1;
+module_param(dump_oops, int, 0600);
+MODULE_PARM_DESC(dump_oops,
+ "set to 1 to dump oopses, 0 to only dump panics (default 1)");
+
+struct ramoops_context {
+ void *virt_addr;
+ phys_addr_t phys_addr;
+ unsigned long size;
+ size_t record_size;
+ int dump_oops;
+ unsigned int count;
+ unsigned int max_count;
+ unsigned int read_count;
+ struct pstore_info pstore;
+};
+
+static struct platform_device *dummy;
+static struct ramoops_platform_data *dummy_data;
+
+static int ramoops_pstore_open(struct pstore_info *psi)
+{
+ struct ramoops_context *cxt = psi->data;
+
+ cxt->read_count = 0;
+ return 0;
+}
+
+static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
+ struct timespec *time,
+ char **buf,
+ struct pstore_info *psi)
+{
+ ssize_t size;
+ char *rambuf;
+ struct ramoops_context *cxt = psi->data;
+
+ if (cxt->read_count >= cxt->max_count)
+ return -EINVAL;
+ *id = cxt->read_count++;
+ /* Only supports dmesg output so far. */
+ *type = PSTORE_TYPE_DMESG;
+ /* TODO(kees): Bogus time for the moment. */
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+
+ rambuf = cxt->virt_addr + (*id * cxt->record_size);
+ size = strnlen(rambuf, cxt->record_size);
+ *buf = kmalloc(size, GFP_KERNEL);
+ if (*buf == NULL)
+ return -ENOMEM;
+ memcpy(*buf, rambuf, size);
+
+ return size;
+}
+
+static int ramoops_pstore_write(enum pstore_type_id type,
+ enum kmsg_dump_reason reason,
+ u64 *id,
+ unsigned int part,
+ size_t size, struct pstore_info *psi)
+{
+ char *buf;
+ size_t res;
+ struct timeval timestamp;
+ struct ramoops_context *cxt = psi->data;
+ size_t available = cxt->record_size;
+
+ /* Currently ramoops is designed to only store dmesg dumps. */
+ if (type != PSTORE_TYPE_DMESG)
+ return -EINVAL;
+
+ /* Out of the various dmesg dump types, ramoops is currently designed
+ * to only store crash logs, rather than storing general kernel logs.
+ */
+ if (reason != KMSG_DUMP_OOPS &&
+ reason != KMSG_DUMP_PANIC)
+ return -EINVAL;
+
+ /* Skip Oopes when configured to do so. */
+ if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
+ return -EINVAL;
+
+ /* Explicitly only take the first part of any new crash.
+ * If our buffer is larger than kmsg_bytes, this can never happen,
+ * and if our buffer is smaller than kmsg_bytes, we don't want the
+ * report split across multiple records.
+ */
+ if (part != 1)
+ return -ENOSPC;
+
+ buf = cxt->virt_addr + (cxt->count * cxt->record_size);
+
+ res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
+ buf += res;
+ available -= res;
+
+ do_gettimeofday(&timestamp);
+ res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
+ buf += res;
+ available -= res;
+
+ if (size > available)
+ size = available;
+
+ memcpy(buf, cxt->pstore.buf, size);
+ memset(buf + size, '\0', available - size);
+
+ cxt->count = (cxt->count + 1) % cxt->max_count;
+
+ return 0;
+}
+
+static int ramoops_pstore_erase(enum pstore_type_id type, u64 id,
+ struct pstore_info *psi)
+{
+ char *buf;
+ struct ramoops_context *cxt = psi->data;
+
+ if (id >= cxt->max_count)
+ return -EINVAL;
+
+ buf = cxt->virt_addr + (id * cxt->record_size);
+ memset(buf, '\0', cxt->record_size);
+
+ return 0;
+}
+
+static struct ramoops_context oops_cxt = {
+ .pstore = {
+ .owner = THIS_MODULE,
+ .name = "ramoops",
+ .open = ramoops_pstore_open,
+ .read = ramoops_pstore_read,
+ .write = ramoops_pstore_write,
+ .erase = ramoops_pstore_erase,
+ },
+};
+
+static int __init ramoops_probe(struct platform_device *pdev)
+{
+ struct ramoops_platform_data *pdata = pdev->dev.platform_data;
+ struct ramoops_context *cxt = &oops_cxt;
+ int err = -EINVAL;
+
+ /* Only a single ramoops area allowed at a time, so fail extra
+ * probes.
+ */
+ if (cxt->max_count)
+ goto fail_out;
+
+ if (!pdata->mem_size || !pdata->record_size) {
+ pr_err("The memory size and the record size must be "
+ "non-zero\n");
+ goto fail_out;
+ }
+
+ pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
+ pdata->record_size = rounddown_pow_of_two(pdata->record_size);
+
+ /* Check for the minimum memory size */
+ if (pdata->mem_size < MIN_MEM_SIZE &&
+ pdata->record_size < MIN_MEM_SIZE) {
+ pr_err("memory size too small, minimum is %lu\n",
+ MIN_MEM_SIZE);
+ goto fail_out;
+ }
+
+ if (pdata->mem_size < pdata->record_size) {
+ pr_err("The memory size must be larger than the "
+ "records size\n");
+ goto fail_out;
+ }
+
+ cxt->max_count = pdata->mem_size / pdata->record_size;
+ cxt->count = 0;
+ cxt->size = pdata->mem_size;
+ cxt->phys_addr = pdata->mem_address;
+ cxt->record_size = pdata->record_size;
+ cxt->dump_oops = pdata->dump_oops;
+
+ cxt->pstore.data = cxt;
+ cxt->pstore.bufsize = cxt->record_size;
+ cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
+ spin_lock_init(&cxt->pstore.buf_lock);
+ if (!cxt->pstore.buf) {
+ pr_err("cannot allocate pstore buffer\n");
+ goto fail_clear;
+ }
+
+ if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
+ pr_err("request mem region (0x%lx@0x%llx) failed\n",
+ cxt->size, (unsigned long long)cxt->phys_addr);
+ err = -EINVAL;
+ goto fail_buf;
+ }
+
+ cxt->virt_addr = ioremap(cxt->phys_addr, cxt->size);
+ if (!cxt->virt_addr) {
+ pr_err("ioremap failed\n");
+ goto fail_mem_region;
+ }
+
+ err = pstore_register(&cxt->pstore);
+ if (err) {
+ pr_err("registering with pstore failed\n");
+ goto fail_iounmap;
+ }
+
+ /*
+ * Update the module parameter variables as well so they are visible
+ * through /sys/module/ramoops/parameters/
+ */
+ mem_size = pdata->mem_size;
+ mem_address = pdata->mem_address;
+ record_size = pdata->record_size;
+ dump_oops = pdata->dump_oops;
+
+ pr_info("attached 0x%lx@0x%llx (%ux0x%zx)\n",
+ cxt->size, (unsigned long long)cxt->phys_addr,
+ cxt->max_count, cxt->record_size);
+
+ return 0;
+
+fail_iounmap:
+ iounmap(cxt->virt_addr);
+fail_mem_region:
+ release_mem_region(cxt->phys_addr, cxt->size);
+fail_buf:
+ kfree(cxt->pstore.buf);
+fail_clear:
+ cxt->pstore.bufsize = 0;
+ cxt->max_count = 0;
+fail_out:
+ return err;
+}
+
+static int __exit ramoops_remove(struct platform_device *pdev)
+{
+#if 0
+ /* TODO(kees): We cannot unload ramoops since pstore doesn't support
+ * unregistering yet.
+ */
+ struct ramoops_context *cxt = &oops_cxt;
+
+ iounmap(cxt->virt_addr);
+ release_mem_region(cxt->phys_addr, cxt->size);
+ cxt->max_count = 0;
+
+ /* TODO(kees): When pstore supports unregistering, call it here. */
+ kfree(cxt->pstore.buf);
+ cxt->pstore.bufsize = 0;
+
+ return 0;
+#endif
+ return -EBUSY;
+}
+
+static struct platform_driver ramoops_driver = {
+ .remove = __exit_p(ramoops_remove),
+ .driver = {
+ .name = "ramoops",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ramoops_init(void)
+{
+ int ret;
+ ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
+ if (ret == -ENODEV) {
+ /*
+ * If we didn't find a platform device, we use module parameters
+ * building platform data on the fly.
+ */
+ pr_info("platform device not found, using module parameters\n");
+ dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
+ GFP_KERNEL);
+ if (!dummy_data)
+ return -ENOMEM;
+ dummy_data->mem_size = mem_size;
+ dummy_data->mem_address = mem_address;
+ dummy_data->record_size = record_size;
+ dummy_data->dump_oops = dump_oops;
+ dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
+ NULL, 0, dummy_data,
+ sizeof(struct ramoops_platform_data));
+
+ if (IS_ERR(dummy))
+ ret = PTR_ERR(dummy);
+ else
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void __exit ramoops_exit(void)
+{
+ platform_driver_unregister(&ramoops_driver);
+ kfree(dummy_data);
+}
+
+module_init(ramoops_init);
+module_exit(ramoops_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marco Stornelli <[email protected]>");
+MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
new file mode 100644
index 0000000..fa4cb02
--- /dev/null
+++ b/include/linux/pstore_ram.h
@@ -0,0 +1,17 @@
+#ifndef __LINUX_PSTORE_RAM_H__
+#define __LINUX_PSTORE_RAM_H__
+
+/*
+ * Ramoops platform data
+ * @mem_size memory size for ramoops
+ * @mem_address physical memory address to contain ramoops
+ */
+
+struct ramoops_platform_data {
+ unsigned long mem_size;
+ unsigned long mem_address;
+ unsigned long record_size;
+ int dump_oops;
+};
+
+#endif
diff --git a/include/linux/ramoops.h b/include/linux/ramoops.h
deleted file mode 100644
index 484fef8..0000000
--- a/include/linux/ramoops.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __RAMOOPS_H
-#define __RAMOOPS_H
-
-/*
- * Ramoops platform data
- * @mem_size memory size for ramoops
- * @mem_address physical memory address to contain ramoops
- */
-
-struct ramoops_platform_data {
- unsigned long mem_size;
- unsigned long mem_address;
- unsigned long record_size;
- int dump_oops;
-};
-
-#endif
--
1.7.9.2

2012-05-16 12:44:51

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 3/6] persistent_ram: Prepare for modular builds

This is a transition patch to keep things bisectable, just moves
some routines under '#ifndef MODULE'. The code inside the #ifndef
will go away soon, but so far we must support pstore and ram_console.

So, we are about to use persistent_ram with pstore, with the ability
to compile persistent_ram routines as modules. Some parts of
persistent_ram uses memblock_reserve() routine, which is should be
only used built-in code, and thus it is not exported.

These persistent_ram bits are only used by Android's ram_console,
which is always built-in.

Without this patch, we won't able to compile persistent_ram as a
module:

ERROR: "memblock_reserve" [fs/pstore/ramoops.ko] undefined!
make[1]: *** [__modpost] Error 1
make: *** [modules] Error 2

(As alternative, we could export memblock_reserve, but the thing
is: we won't need it later.)

Signed-off-by: Anton Vorontsov <[email protected]>
---
drivers/staging/android/persistent_ram.c | 46 ++++++++++++++++--------------
1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/drivers/staging/android/persistent_ram.c b/drivers/staging/android/persistent_ram.c
index 63481da..4b46eaa 100644
--- a/drivers/staging/android/persistent_ram.c
+++ b/drivers/staging/android/persistent_ram.c
@@ -384,28 +384,6 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
return 0;
}

-static int __init persistent_ram_buffer_init(const char *name,
- struct persistent_ram_zone *prz)
-{
- int i;
- struct persistent_ram *ram;
- struct persistent_ram_descriptor *desc;
- phys_addr_t start;
-
- list_for_each_entry(ram, &persistent_ram_list, node) {
- start = ram->start;
- for (i = 0; i < ram->num_descs; i++) {
- desc = &ram->descs[i];
- if (!strcmp(desc->name, name))
- return persistent_ram_buffer_map(start,
- desc->size, prz);
- start += desc->size;
- }
- }
-
- return -EINVAL;
-}
-
static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool ecc)
{
int ret;
@@ -478,6 +456,29 @@ err:
return ERR_PTR(ret);
}

+#ifndef MODULE
+static int __init persistent_ram_buffer_init(const char *name,
+ struct persistent_ram_zone *prz)
+{
+ int i;
+ struct persistent_ram *ram;
+ struct persistent_ram_descriptor *desc;
+ phys_addr_t start;
+
+ list_for_each_entry(ram, &persistent_ram_list, node) {
+ start = ram->start;
+ for (i = 0; i < ram->num_descs; i++) {
+ desc = &ram->descs[i];
+ if (!strcmp(desc->name, name))
+ return persistent_ram_buffer_map(start,
+ desc->size, prz);
+ start += desc->size;
+ }
+ }
+
+ return -EINVAL;
+}
+
static __init
struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
{
@@ -528,3 +529,4 @@ int __init persistent_ram_early_init(struct persistent_ram *ram)

return 0;
}
+#endif
--
1.7.9.2

2012-05-16 12:45:14

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 4/6] persistent_ram: Move to fs/pstore/ram_core.c

This is a first step for adding ECC support for pstore RAM backend: we
will use the persistent_ram routines, kindly provided by Google.

Basically, persistent_ram is a set of helper routines to deal with the
[optionally] ECC-protected persistent ram regions.

A bit of Makefile, Kconfig and header files adjustments were needed
because of the move.

Signed-off-by: Anton Vorontsov <[email protected]>
Acked-by: Kees Cook <[email protected]>
---
drivers/staging/android/Kconfig | 10 +-
drivers/staging/android/Makefile | 1 -
drivers/staging/android/persistent_ram.c | 532 ------------------------------
drivers/staging/android/persistent_ram.h | 82 -----
drivers/staging/android/ram_console.c | 2 +-
fs/pstore/Kconfig | 7 +-
fs/pstore/Makefile | 2 +-
fs/pstore/ram_core.c | 532 ++++++++++++++++++++++++++++++
include/linux/pstore_ram.h | 80 +++++
9 files changed, 620 insertions(+), 628 deletions(-)
delete mode 100644 drivers/staging/android/persistent_ram.c
delete mode 100644 drivers/staging/android/persistent_ram.h
create mode 100644 fs/pstore/ram_core.c

diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 42f0133..4bfcceb 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -25,17 +25,9 @@ config ANDROID_LOGGER
tristate "Android log driver"
default n

-config ANDROID_PERSISTENT_RAM
- bool
- depends on HAVE_MEMBLOCK
- select REED_SOLOMON
- select REED_SOLOMON_ENC8
- select REED_SOLOMON_DEC8
-
config ANDROID_RAM_CONSOLE
bool "Android RAM buffer console"
- depends on !S390 && !UML && HAVE_MEMBLOCK
- select ANDROID_PERSISTENT_RAM
+ depends on !S390 && !UML && HAVE_MEMBLOCK && PSTORE_RAM
default n

config ANDROID_TIMED_OUTPUT
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 2de5c10..98711e2 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -1,7 +1,6 @@
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj-$(CONFIG_ASHMEM) += ashmem.o
obj-$(CONFIG_ANDROID_LOGGER) += logger.o
-obj-$(CONFIG_ANDROID_PERSISTENT_RAM) += persistent_ram.o
obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o
obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
diff --git a/drivers/staging/android/persistent_ram.c b/drivers/staging/android/persistent_ram.c
deleted file mode 100644
index 4b46eaa..0000000
--- a/drivers/staging/android/persistent_ram.c
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * Copyright (C) 2012 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/list.h>
-#include <linux/memblock.h>
-#include <linux/rslib.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <asm/page.h>
-#include "persistent_ram.h"
-
-struct persistent_ram_buffer {
- uint32_t sig;
- atomic_t start;
- atomic_t size;
- uint8_t data[0];
-};
-
-#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
-
-static __initdata LIST_HEAD(persistent_ram_list);
-
-static inline size_t buffer_size(struct persistent_ram_zone *prz)
-{
- return atomic_read(&prz->buffer->size);
-}
-
-static inline size_t buffer_start(struct persistent_ram_zone *prz)
-{
- return atomic_read(&prz->buffer->start);
-}
-
-/* increase and wrap the start pointer, returning the old value */
-static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
-{
- int old;
- int new;
-
- do {
- old = atomic_read(&prz->buffer->start);
- new = old + a;
- while (unlikely(new > prz->buffer_size))
- new -= prz->buffer_size;
- } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
-
- return old;
-}
-
-/* increase the size counter until it hits the max size */
-static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
-{
- size_t old;
- size_t new;
-
- if (atomic_read(&prz->buffer->size) == prz->buffer_size)
- return;
-
- do {
- old = atomic_read(&prz->buffer->size);
- new = old + a;
- if (new > prz->buffer_size)
- new = prz->buffer_size;
- } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
-}
-
-static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
- uint8_t *data, size_t len, uint8_t *ecc)
-{
- int i;
- uint16_t par[prz->ecc_size];
-
- /* Initialize the parity buffer */
- memset(par, 0, sizeof(par));
- encode_rs8(prz->rs_decoder, data, len, par, 0);
- for (i = 0; i < prz->ecc_size; i++)
- ecc[i] = par[i];
-}
-
-static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
- void *data, size_t len, uint8_t *ecc)
-{
- int i;
- uint16_t par[prz->ecc_size];
-
- for (i = 0; i < prz->ecc_size; i++)
- par[i] = ecc[i];
- return decode_rs8(prz->rs_decoder, data, par, len,
- NULL, 0, NULL, 0, NULL);
-}
-
-static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
- unsigned int start, unsigned int count)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
- uint8_t *buffer_end = buffer->data + prz->buffer_size;
- uint8_t *block;
- uint8_t *par;
- int ecc_block_size = prz->ecc_block_size;
- int ecc_size = prz->ecc_size;
- int size = prz->ecc_block_size;
-
- if (!prz->ecc)
- return;
-
- block = buffer->data + (start & ~(ecc_block_size - 1));
- par = prz->par_buffer + (start / ecc_block_size) * prz->ecc_size;
-
- do {
- if (block + ecc_block_size > buffer_end)
- size = buffer_end - block;
- persistent_ram_encode_rs8(prz, block, size, par);
- block += ecc_block_size;
- par += ecc_size;
- } while (block < buffer->data + start + count);
-}
-
-static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
-
- if (!prz->ecc)
- return;
-
- persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
- prz->par_header);
-}
-
-static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
- uint8_t *block;
- uint8_t *par;
-
- if (!prz->ecc)
- return;
-
- block = buffer->data;
- par = prz->par_buffer;
- while (block < buffer->data + buffer_size(prz)) {
- int numerr;
- int size = prz->ecc_block_size;
- if (block + size > buffer->data + prz->buffer_size)
- size = buffer->data + prz->buffer_size - block;
- numerr = persistent_ram_decode_rs8(prz, block, size, par);
- if (numerr > 0) {
- pr_devel("persistent_ram: error in block %p, %d\n",
- block, numerr);
- prz->corrected_bytes += numerr;
- } else if (numerr < 0) {
- pr_devel("persistent_ram: uncorrectable error in block %p\n",
- block);
- prz->bad_blocks++;
- }
- block += prz->ecc_block_size;
- par += prz->ecc_size;
- }
-}
-
-static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
- size_t buffer_size)
-{
- int numerr;
- struct persistent_ram_buffer *buffer = prz->buffer;
- int ecc_blocks;
-
- if (!prz->ecc)
- return 0;
-
- prz->ecc_block_size = 128;
- prz->ecc_size = 16;
- prz->ecc_symsize = 8;
- prz->ecc_poly = 0x11d;
-
- ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
- prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
-
- if (prz->buffer_size > buffer_size) {
- pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
- buffer_size, prz->buffer_size);
- return -EINVAL;
- }
-
- prz->par_buffer = buffer->data + prz->buffer_size;
- prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
-
- /*
- * first consecutive root is 0
- * primitive element to generate roots = 1
- */
- prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
- prz->ecc_size);
- if (prz->rs_decoder == NULL) {
- pr_info("persistent_ram: init_rs failed\n");
- return -EINVAL;
- }
-
- prz->corrected_bytes = 0;
- prz->bad_blocks = 0;
-
- numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
- prz->par_header);
- if (numerr > 0) {
- pr_info("persistent_ram: error in header, %d\n", numerr);
- prz->corrected_bytes += numerr;
- } else if (numerr < 0) {
- pr_info("persistent_ram: uncorrectable error in header\n");
- prz->bad_blocks++;
- }
-
- return 0;
-}
-
-ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
- char *str, size_t len)
-{
- ssize_t ret;
-
- if (prz->corrected_bytes || prz->bad_blocks)
- ret = snprintf(str, len, ""
- "\n%d Corrected bytes, %d unrecoverable blocks\n",
- prz->corrected_bytes, prz->bad_blocks);
- else
- ret = snprintf(str, len, "\nNo errors detected\n");
-
- return ret;
-}
-
-static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
- const void *s, unsigned int start, unsigned int count)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
- memcpy(buffer->data + start, s, count);
- persistent_ram_update_ecc(prz, start, count);
-}
-
-static void __init
-persistent_ram_save_old(struct persistent_ram_zone *prz)
-{
- struct persistent_ram_buffer *buffer = prz->buffer;
- size_t size = buffer_size(prz);
- size_t start = buffer_start(prz);
- char *dest;
-
- persistent_ram_ecc_old(prz);
-
- dest = kmalloc(size, GFP_KERNEL);
- if (dest == NULL) {
- pr_err("persistent_ram: failed to allocate buffer\n");
- return;
- }
-
- prz->old_log = dest;
- prz->old_log_size = size;
- memcpy(prz->old_log, &buffer->data[start], size - start);
- memcpy(prz->old_log + size - start, &buffer->data[0], start);
-}
-
-int notrace persistent_ram_write(struct persistent_ram_zone *prz,
- const void *s, unsigned int count)
-{
- int rem;
- int c = count;
- size_t start;
-
- if (unlikely(c > prz->buffer_size)) {
- s += c - prz->buffer_size;
- c = prz->buffer_size;
- }
-
- buffer_size_add(prz, c);
-
- start = buffer_start_add(prz, c);
-
- rem = prz->buffer_size - start;
- if (unlikely(rem < c)) {
- persistent_ram_update(prz, s, start, rem);
- s += rem;
- c -= rem;
- start = 0;
- }
- persistent_ram_update(prz, s, start, c);
-
- persistent_ram_update_header_ecc(prz);
-
- return count;
-}
-
-size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
-{
- return prz->old_log_size;
-}
-
-void *persistent_ram_old(struct persistent_ram_zone *prz)
-{
- return prz->old_log;
-}
-
-void persistent_ram_free_old(struct persistent_ram_zone *prz)
-{
- kfree(prz->old_log);
- prz->old_log = NULL;
- prz->old_log_size = 0;
-}
-
-static void *persistent_ram_vmap(phys_addr_t start, size_t size)
-{
- struct page **pages;
- phys_addr_t page_start;
- unsigned int page_count;
- pgprot_t prot;
- unsigned int i;
- void *vaddr;
-
- page_start = start - offset_in_page(start);
- page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
-
- prot = pgprot_noncached(PAGE_KERNEL);
-
- pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
- if (!pages) {
- pr_err("%s: Failed to allocate array for %u pages\n", __func__,
- page_count);
- return NULL;
- }
-
- for (i = 0; i < page_count; i++) {
- phys_addr_t addr = page_start + i * PAGE_SIZE;
- pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
- }
- vaddr = vmap(pages, page_count, VM_MAP, prot);
- kfree(pages);
-
- return vaddr;
-}
-
-static void *persistent_ram_iomap(phys_addr_t start, size_t size)
-{
- if (!request_mem_region(start, size, "persistent_ram")) {
- pr_err("request mem region (0x%llx@0x%llx) failed\n",
- (unsigned long long)size, (unsigned long long)start);
- return NULL;
- }
-
- return ioremap(start, size);
-}
-
-static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
- struct persistent_ram_zone *prz)
-{
- prz->paddr = start;
- prz->size = size;
-
- if (pfn_valid(start >> PAGE_SHIFT))
- prz->vaddr = persistent_ram_vmap(start, size);
- else
- prz->vaddr = persistent_ram_iomap(start, size);
-
- if (!prz->vaddr) {
- pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__,
- (unsigned long long)size, (unsigned long long)start);
- return -ENOMEM;
- }
-
- prz->buffer = prz->vaddr + offset_in_page(start);
- prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
-
- return 0;
-}
-
-static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool ecc)
-{
- int ret;
-
- prz->ecc = ecc;
-
- ret = persistent_ram_init_ecc(prz, prz->buffer_size);
- if (ret)
- return ret;
-
- if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
- if (buffer_size(prz) > prz->buffer_size ||
- buffer_start(prz) > buffer_size(prz))
- pr_info("persistent_ram: found existing invalid buffer,"
- " size %zu, start %zu\n",
- buffer_size(prz), buffer_start(prz));
- else {
- pr_info("persistent_ram: found existing buffer,"
- " size %zu, start %zu\n",
- buffer_size(prz), buffer_start(prz));
- persistent_ram_save_old(prz);
- }
- } else {
- pr_info("persistent_ram: no valid data in buffer"
- " (sig = 0x%08x)\n", prz->buffer->sig);
- }
-
- prz->buffer->sig = PERSISTENT_RAM_SIG;
- atomic_set(&prz->buffer->start, 0);
- atomic_set(&prz->buffer->size, 0);
-
- return 0;
-}
-
-void persistent_ram_free(struct persistent_ram_zone *prz)
-{
- if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
- vunmap(prz->vaddr);
- } else {
- iounmap(prz->vaddr);
- release_mem_region(prz->paddr, prz->size);
- }
- persistent_ram_free_old(prz);
- kfree(prz);
-}
-
-struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
- size_t size,
- bool ecc)
-{
- struct persistent_ram_zone *prz;
- int ret = -ENOMEM;
-
- prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
- if (!prz) {
- pr_err("persistent_ram: failed to allocate persistent ram zone\n");
- goto err;
- }
-
- ret = persistent_ram_buffer_map(start, size, prz);
- if (ret)
- goto err;
-
- persistent_ram_post_init(prz, ecc);
- persistent_ram_update_header_ecc(prz);
-
- return prz;
-err:
- kfree(prz);
- return ERR_PTR(ret);
-}
-
-#ifndef MODULE
-static int __init persistent_ram_buffer_init(const char *name,
- struct persistent_ram_zone *prz)
-{
- int i;
- struct persistent_ram *ram;
- struct persistent_ram_descriptor *desc;
- phys_addr_t start;
-
- list_for_each_entry(ram, &persistent_ram_list, node) {
- start = ram->start;
- for (i = 0; i < ram->num_descs; i++) {
- desc = &ram->descs[i];
- if (!strcmp(desc->name, name))
- return persistent_ram_buffer_map(start,
- desc->size, prz);
- start += desc->size;
- }
- }
-
- return -EINVAL;
-}
-
-static __init
-struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
-{
- struct persistent_ram_zone *prz;
- int ret = -ENOMEM;
-
- prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
- if (!prz) {
- pr_err("persistent_ram: failed to allocate persistent ram zone\n");
- goto err;
- }
-
- ret = persistent_ram_buffer_init(dev_name(dev), prz);
- if (ret) {
- pr_err("persistent_ram: failed to initialize buffer\n");
- goto err;
- }
-
- persistent_ram_post_init(prz, ecc);
-
- return prz;
-err:
- kfree(prz);
- return ERR_PTR(ret);
-}
-
-struct persistent_ram_zone * __init
-persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
-{
- return __persistent_ram_init(dev, ecc);
-}
-
-int __init persistent_ram_early_init(struct persistent_ram *ram)
-{
- int ret;
-
- ret = memblock_reserve(ram->start, ram->size);
- if (ret) {
- pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
- (long)ram->start, (long)(ram->start + ram->size - 1));
- return ret;
- }
-
- list_add_tail(&ram->node, &persistent_ram_list);
-
- pr_info("Initialized persistent memory from %08lx-%08lx\n",
- (long)ram->start, (long)(ram->start + ram->size - 1));
-
- return 0;
-}
-#endif
diff --git a/drivers/staging/android/persistent_ram.h b/drivers/staging/android/persistent_ram.h
deleted file mode 100644
index d23850c..0000000
--- a/drivers/staging/android/persistent_ram.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2011 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef __LINUX_PERSISTENT_RAM_H__
-#define __LINUX_PERSISTENT_RAM_H__
-
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-struct persistent_ram_buffer;
-
-struct persistent_ram_descriptor {
- const char *name;
- phys_addr_t size;
-};
-
-struct persistent_ram {
- phys_addr_t start;
- phys_addr_t size;
-
- int num_descs;
- struct persistent_ram_descriptor *descs;
-
- struct list_head node;
-};
-
-struct persistent_ram_zone {
- phys_addr_t paddr;
- size_t size;
- void *vaddr;
- struct persistent_ram_buffer *buffer;
- size_t buffer_size;
-
- /* ECC correction */
- bool ecc;
- char *par_buffer;
- char *par_header;
- struct rs_control *rs_decoder;
- int corrected_bytes;
- int bad_blocks;
- int ecc_block_size;
- int ecc_size;
- int ecc_symsize;
- int ecc_poly;
-
- char *old_log;
- size_t old_log_size;
-};
-
-int persistent_ram_early_init(struct persistent_ram *ram);
-
-struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
- size_t size,
- bool ecc);
-void persistent_ram_free(struct persistent_ram_zone *prz);
-struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev,
- bool ecc);
-
-int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
- unsigned int count);
-
-size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
-void *persistent_ram_old(struct persistent_ram_zone *prz);
-void persistent_ram_free_old(struct persistent_ram_zone *prz);
-ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
- char *str, size_t len);
-
-#endif
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index ce140ff..82323bb 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -21,7 +21,7 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#include "persistent_ram.h"
+#include <linux/pstore_ram.h>
#include "ram_console.h"

static struct persistent_ram_zone *ram_console_zone;
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index b75ee51..23ade26 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -14,9 +14,12 @@ config PSTORE

config PSTORE_RAM
tristate "Log panic/oops to a RAM buffer"
- depends on HAS_IOMEM
depends on PSTORE
- default n
+ depends on HAS_IOMEM
+ depends on HAVE_MEMBLOCK
+ select REED_SOLOMON
+ select REED_SOLOMON_ENC8
+ select REED_SOLOMON_DEC8
help
This enables panic and oops messages to be logged to a circular
buffer in RAM where it can be read back at some later point.
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index 2ab3d0d..278a44e 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -6,5 +6,5 @@ obj-y += pstore.o

pstore-objs += inode.o platform.o

-ramoops-objs += ram.o
+ramoops-objs += ram.o ram_core.o
obj-$(CONFIG_PSTORE_RAM) += ramoops.o
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
new file mode 100644
index 0000000..31f8d18
--- /dev/null
+++ b/fs/pstore/ram_core.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/rslib.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/pstore_ram.h>
+#include <asm/page.h>
+
+struct persistent_ram_buffer {
+ uint32_t sig;
+ atomic_t start;
+ atomic_t size;
+ uint8_t data[0];
+};
+
+#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
+
+static __initdata LIST_HEAD(persistent_ram_list);
+
+static inline size_t buffer_size(struct persistent_ram_zone *prz)
+{
+ return atomic_read(&prz->buffer->size);
+}
+
+static inline size_t buffer_start(struct persistent_ram_zone *prz)
+{
+ return atomic_read(&prz->buffer->start);
+}
+
+/* increase and wrap the start pointer, returning the old value */
+static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
+{
+ int old;
+ int new;
+
+ do {
+ old = atomic_read(&prz->buffer->start);
+ new = old + a;
+ while (unlikely(new > prz->buffer_size))
+ new -= prz->buffer_size;
+ } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
+
+ return old;
+}
+
+/* increase the size counter until it hits the max size */
+static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
+{
+ size_t old;
+ size_t new;
+
+ if (atomic_read(&prz->buffer->size) == prz->buffer_size)
+ return;
+
+ do {
+ old = atomic_read(&prz->buffer->size);
+ new = old + a;
+ if (new > prz->buffer_size)
+ new = prz->buffer_size;
+ } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
+}
+
+static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
+ uint8_t *data, size_t len, uint8_t *ecc)
+{
+ int i;
+ uint16_t par[prz->ecc_size];
+
+ /* Initialize the parity buffer */
+ memset(par, 0, sizeof(par));
+ encode_rs8(prz->rs_decoder, data, len, par, 0);
+ for (i = 0; i < prz->ecc_size; i++)
+ ecc[i] = par[i];
+}
+
+static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
+ void *data, size_t len, uint8_t *ecc)
+{
+ int i;
+ uint16_t par[prz->ecc_size];
+
+ for (i = 0; i < prz->ecc_size; i++)
+ par[i] = ecc[i];
+ return decode_rs8(prz->rs_decoder, data, par, len,
+ NULL, 0, NULL, 0, NULL);
+}
+
+static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
+ unsigned int start, unsigned int count)
+{
+ struct persistent_ram_buffer *buffer = prz->buffer;
+ uint8_t *buffer_end = buffer->data + prz->buffer_size;
+ uint8_t *block;
+ uint8_t *par;
+ int ecc_block_size = prz->ecc_block_size;
+ int ecc_size = prz->ecc_size;
+ int size = prz->ecc_block_size;
+
+ if (!prz->ecc)
+ return;
+
+ block = buffer->data + (start & ~(ecc_block_size - 1));
+ par = prz->par_buffer + (start / ecc_block_size) * prz->ecc_size;
+
+ do {
+ if (block + ecc_block_size > buffer_end)
+ size = buffer_end - block;
+ persistent_ram_encode_rs8(prz, block, size, par);
+ block += ecc_block_size;
+ par += ecc_size;
+ } while (block < buffer->data + start + count);
+}
+
+static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
+{
+ struct persistent_ram_buffer *buffer = prz->buffer;
+
+ if (!prz->ecc)
+ return;
+
+ persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
+ prz->par_header);
+}
+
+static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
+{
+ struct persistent_ram_buffer *buffer = prz->buffer;
+ uint8_t *block;
+ uint8_t *par;
+
+ if (!prz->ecc)
+ return;
+
+ block = buffer->data;
+ par = prz->par_buffer;
+ while (block < buffer->data + buffer_size(prz)) {
+ int numerr;
+ int size = prz->ecc_block_size;
+ if (block + size > buffer->data + prz->buffer_size)
+ size = buffer->data + prz->buffer_size - block;
+ numerr = persistent_ram_decode_rs8(prz, block, size, par);
+ if (numerr > 0) {
+ pr_devel("persistent_ram: error in block %p, %d\n",
+ block, numerr);
+ prz->corrected_bytes += numerr;
+ } else if (numerr < 0) {
+ pr_devel("persistent_ram: uncorrectable error in block %p\n",
+ block);
+ prz->bad_blocks++;
+ }
+ block += prz->ecc_block_size;
+ par += prz->ecc_size;
+ }
+}
+
+static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
+ size_t buffer_size)
+{
+ int numerr;
+ struct persistent_ram_buffer *buffer = prz->buffer;
+ int ecc_blocks;
+
+ if (!prz->ecc)
+ return 0;
+
+ prz->ecc_block_size = 128;
+ prz->ecc_size = 16;
+ prz->ecc_symsize = 8;
+ prz->ecc_poly = 0x11d;
+
+ ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
+ prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
+
+ if (prz->buffer_size > buffer_size) {
+ pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
+ buffer_size, prz->buffer_size);
+ return -EINVAL;
+ }
+
+ prz->par_buffer = buffer->data + prz->buffer_size;
+ prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
+
+ /*
+ * first consecutive root is 0
+ * primitive element to generate roots = 1
+ */
+ prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
+ prz->ecc_size);
+ if (prz->rs_decoder == NULL) {
+ pr_info("persistent_ram: init_rs failed\n");
+ return -EINVAL;
+ }
+
+ prz->corrected_bytes = 0;
+ prz->bad_blocks = 0;
+
+ numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
+ prz->par_header);
+ if (numerr > 0) {
+ pr_info("persistent_ram: error in header, %d\n", numerr);
+ prz->corrected_bytes += numerr;
+ } else if (numerr < 0) {
+ pr_info("persistent_ram: uncorrectable error in header\n");
+ prz->bad_blocks++;
+ }
+
+ return 0;
+}
+
+ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+ char *str, size_t len)
+{
+ ssize_t ret;
+
+ if (prz->corrected_bytes || prz->bad_blocks)
+ ret = snprintf(str, len, ""
+ "\n%d Corrected bytes, %d unrecoverable blocks\n",
+ prz->corrected_bytes, prz->bad_blocks);
+ else
+ ret = snprintf(str, len, "\nNo errors detected\n");
+
+ return ret;
+}
+
+static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
+ const void *s, unsigned int start, unsigned int count)
+{
+ struct persistent_ram_buffer *buffer = prz->buffer;
+ memcpy(buffer->data + start, s, count);
+ persistent_ram_update_ecc(prz, start, count);
+}
+
+static void __init
+persistent_ram_save_old(struct persistent_ram_zone *prz)
+{
+ struct persistent_ram_buffer *buffer = prz->buffer;
+ size_t size = buffer_size(prz);
+ size_t start = buffer_start(prz);
+ char *dest;
+
+ persistent_ram_ecc_old(prz);
+
+ dest = kmalloc(size, GFP_KERNEL);
+ if (dest == NULL) {
+ pr_err("persistent_ram: failed to allocate buffer\n");
+ return;
+ }
+
+ prz->old_log = dest;
+ prz->old_log_size = size;
+ memcpy(prz->old_log, &buffer->data[start], size - start);
+ memcpy(prz->old_log + size - start, &buffer->data[0], start);
+}
+
+int notrace persistent_ram_write(struct persistent_ram_zone *prz,
+ const void *s, unsigned int count)
+{
+ int rem;
+ int c = count;
+ size_t start;
+
+ if (unlikely(c > prz->buffer_size)) {
+ s += c - prz->buffer_size;
+ c = prz->buffer_size;
+ }
+
+ buffer_size_add(prz, c);
+
+ start = buffer_start_add(prz, c);
+
+ rem = prz->buffer_size - start;
+ if (unlikely(rem < c)) {
+ persistent_ram_update(prz, s, start, rem);
+ s += rem;
+ c -= rem;
+ start = 0;
+ }
+ persistent_ram_update(prz, s, start, c);
+
+ persistent_ram_update_header_ecc(prz);
+
+ return count;
+}
+
+size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
+{
+ return prz->old_log_size;
+}
+
+void *persistent_ram_old(struct persistent_ram_zone *prz)
+{
+ return prz->old_log;
+}
+
+void persistent_ram_free_old(struct persistent_ram_zone *prz)
+{
+ kfree(prz->old_log);
+ prz->old_log = NULL;
+ prz->old_log_size = 0;
+}
+
+static void *persistent_ram_vmap(phys_addr_t start, size_t size)
+{
+ struct page **pages;
+ phys_addr_t page_start;
+ unsigned int page_count;
+ pgprot_t prot;
+ unsigned int i;
+ void *vaddr;
+
+ page_start = start - offset_in_page(start);
+ page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
+
+ prot = pgprot_noncached(PAGE_KERNEL);
+
+ pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
+ if (!pages) {
+ pr_err("%s: Failed to allocate array for %u pages\n", __func__,
+ page_count);
+ return NULL;
+ }
+
+ for (i = 0; i < page_count; i++) {
+ phys_addr_t addr = page_start + i * PAGE_SIZE;
+ pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
+ }
+ vaddr = vmap(pages, page_count, VM_MAP, prot);
+ kfree(pages);
+
+ return vaddr;
+}
+
+static void *persistent_ram_iomap(phys_addr_t start, size_t size)
+{
+ if (!request_mem_region(start, size, "persistent_ram")) {
+ pr_err("request mem region (0x%llx@0x%llx) failed\n",
+ (unsigned long long)size, (unsigned long long)start);
+ return NULL;
+ }
+
+ return ioremap(start, size);
+}
+
+static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
+ struct persistent_ram_zone *prz)
+{
+ prz->paddr = start;
+ prz->size = size;
+
+ if (pfn_valid(start >> PAGE_SHIFT))
+ prz->vaddr = persistent_ram_vmap(start, size);
+ else
+ prz->vaddr = persistent_ram_iomap(start, size);
+
+ if (!prz->vaddr) {
+ pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__,
+ (unsigned long long)size, (unsigned long long)start);
+ return -ENOMEM;
+ }
+
+ prz->buffer = prz->vaddr + offset_in_page(start);
+ prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
+
+ return 0;
+}
+
+static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool ecc)
+{
+ int ret;
+
+ prz->ecc = ecc;
+
+ ret = persistent_ram_init_ecc(prz, prz->buffer_size);
+ if (ret)
+ return ret;
+
+ if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
+ if (buffer_size(prz) > prz->buffer_size ||
+ buffer_start(prz) > buffer_size(prz))
+ pr_info("persistent_ram: found existing invalid buffer,"
+ " size %zu, start %zu\n",
+ buffer_size(prz), buffer_start(prz));
+ else {
+ pr_info("persistent_ram: found existing buffer,"
+ " size %zu, start %zu\n",
+ buffer_size(prz), buffer_start(prz));
+ persistent_ram_save_old(prz);
+ }
+ } else {
+ pr_info("persistent_ram: no valid data in buffer"
+ " (sig = 0x%08x)\n", prz->buffer->sig);
+ }
+
+ prz->buffer->sig = PERSISTENT_RAM_SIG;
+ atomic_set(&prz->buffer->start, 0);
+ atomic_set(&prz->buffer->size, 0);
+
+ return 0;
+}
+
+void persistent_ram_free(struct persistent_ram_zone *prz)
+{
+ if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
+ vunmap(prz->vaddr);
+ } else {
+ iounmap(prz->vaddr);
+ release_mem_region(prz->paddr, prz->size);
+ }
+ persistent_ram_free_old(prz);
+ kfree(prz);
+}
+
+struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
+ size_t size,
+ bool ecc)
+{
+ struct persistent_ram_zone *prz;
+ int ret = -ENOMEM;
+
+ prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
+ if (!prz) {
+ pr_err("persistent_ram: failed to allocate persistent ram zone\n");
+ goto err;
+ }
+
+ ret = persistent_ram_buffer_map(start, size, prz);
+ if (ret)
+ goto err;
+
+ persistent_ram_post_init(prz, ecc);
+ persistent_ram_update_header_ecc(prz);
+
+ return prz;
+err:
+ kfree(prz);
+ return ERR_PTR(ret);
+}
+
+#ifndef MODULE
+static int __init persistent_ram_buffer_init(const char *name,
+ struct persistent_ram_zone *prz)
+{
+ int i;
+ struct persistent_ram *ram;
+ struct persistent_ram_descriptor *desc;
+ phys_addr_t start;
+
+ list_for_each_entry(ram, &persistent_ram_list, node) {
+ start = ram->start;
+ for (i = 0; i < ram->num_descs; i++) {
+ desc = &ram->descs[i];
+ if (!strcmp(desc->name, name))
+ return persistent_ram_buffer_map(start,
+ desc->size, prz);
+ start += desc->size;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static __init
+struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
+{
+ struct persistent_ram_zone *prz;
+ int ret = -ENOMEM;
+
+ prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
+ if (!prz) {
+ pr_err("persistent_ram: failed to allocate persistent ram zone\n");
+ goto err;
+ }
+
+ ret = persistent_ram_buffer_init(dev_name(dev), prz);
+ if (ret) {
+ pr_err("persistent_ram: failed to initialize buffer\n");
+ goto err;
+ }
+
+ persistent_ram_post_init(prz, ecc);
+
+ return prz;
+err:
+ kfree(prz);
+ return ERR_PTR(ret);
+}
+
+struct persistent_ram_zone * __init
+persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
+{
+ return __persistent_ram_init(dev, ecc);
+}
+
+int __init persistent_ram_early_init(struct persistent_ram *ram)
+{
+ int ret;
+
+ ret = memblock_reserve(ram->start, ram->size);
+ if (ret) {
+ pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
+ (long)ram->start, (long)(ram->start + ram->size - 1));
+ return ret;
+ }
+
+ list_add_tail(&ram->node, &persistent_ram_list);
+
+ pr_info("Initialized persistent memory from %08lx-%08lx\n",
+ (long)ram->start, (long)(ram->start + ram->size - 1));
+
+ return 0;
+}
+#endif
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index fa4cb02..ffe24a5 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -1,6 +1,86 @@
+/*
+ * Copyright (C) 2010 Marco Stornelli <[email protected]>
+ * Copyright (C) 2011 Kees Cook <[email protected]>
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
#ifndef __LINUX_PSTORE_RAM_H__
#define __LINUX_PSTORE_RAM_H__

+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+struct persistent_ram_buffer;
+
+struct persistent_ram_descriptor {
+ const char *name;
+ phys_addr_t size;
+};
+
+struct persistent_ram {
+ phys_addr_t start;
+ phys_addr_t size;
+
+ int num_descs;
+ struct persistent_ram_descriptor *descs;
+
+ struct list_head node;
+};
+
+struct persistent_ram_zone {
+ phys_addr_t paddr;
+ size_t size;
+ void *vaddr;
+ struct persistent_ram_buffer *buffer;
+ size_t buffer_size;
+
+ /* ECC correction */
+ bool ecc;
+ char *par_buffer;
+ char *par_header;
+ struct rs_control *rs_decoder;
+ int corrected_bytes;
+ int bad_blocks;
+ int ecc_block_size;
+ int ecc_size;
+ int ecc_symsize;
+ int ecc_poly;
+
+ char *old_log;
+ size_t old_log_size;
+};
+
+int persistent_ram_early_init(struct persistent_ram *ram);
+
+struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
+ size_t size,
+ bool ecc);
+void persistent_ram_free(struct persistent_ram_zone *prz);
+struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev,
+ bool ecc);
+
+int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
+ unsigned int count);
+
+size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
+void *persistent_ram_old(struct persistent_ram_zone *prz);
+void persistent_ram_free_old(struct persistent_ram_zone *prz);
+ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
+ char *str, size_t len);
+
/*
* Ramoops platform data
* @mem_size memory size for ramoops
--
1.7.9.2

2012-05-16 12:45:32

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 5/6] pstore/ram: Switch to persistent_ram routines

The patch switches pstore RAM backend to use persistent_ram routines,
one step closer to the ECC support.

Signed-off-by: Anton Vorontsov <[email protected]>
Acked-by: Marco Stornelli <[email protected]>
---
fs/pstore/ram.c | 106 +++++++++++++++++++++++++++++++------------------------
1 file changed, 59 insertions(+), 47 deletions(-)

diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index e443c9c..62b13ed 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(dump_oops,
"set to 1 to dump oopses, 0 to only dump panics (default 1)");

struct ramoops_context {
- void *virt_addr;
+ struct persistent_ram_zone **przs;
phys_addr_t phys_addr;
unsigned long size;
size_t record_size;
@@ -85,39 +85,56 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
struct pstore_info *psi)
{
ssize_t size;
- char *rambuf;
struct ramoops_context *cxt = psi->data;
+ struct persistent_ram_zone *prz;

if (cxt->read_count >= cxt->max_count)
return -EINVAL;
+
*id = cxt->read_count++;
+ prz = cxt->przs[*id];
+
/* Only supports dmesg output so far. */
*type = PSTORE_TYPE_DMESG;
/* TODO(kees): Bogus time for the moment. */
time->tv_sec = 0;
time->tv_nsec = 0;

- rambuf = cxt->virt_addr + (*id * cxt->record_size);
- size = strnlen(rambuf, cxt->record_size);
+ size = persistent_ram_old_size(prz);
*buf = kmalloc(size, GFP_KERNEL);
if (*buf == NULL)
return -ENOMEM;
- memcpy(*buf, rambuf, size);
+ memcpy(*buf, persistent_ram_old(prz), size);

return size;
}

+static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
+{
+ char *hdr;
+ struct timeval timestamp;
+ size_t len;
+
+ do_gettimeofday(&timestamp);
+ hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
+ (long)timestamp.tv_sec, (long)timestamp.tv_usec);
+ WARN_ON_ONCE(!hdr);
+ len = hdr ? strlen(hdr) : 0;
+ persistent_ram_write(prz, hdr, len);
+ kfree(hdr);
+
+ return len;
+}
+
static int ramoops_pstore_write(enum pstore_type_id type,
enum kmsg_dump_reason reason,
u64 *id,
unsigned int part,
size_t size, struct pstore_info *psi)
{
- char *buf;
- size_t res;
- struct timeval timestamp;
struct ramoops_context *cxt = psi->data;
- size_t available = cxt->record_size;
+ struct persistent_ram_zone *prz = cxt->przs[cxt->count];
+ size_t hlen;

/* Currently ramoops is designed to only store dmesg dumps. */
if (type != PSTORE_TYPE_DMESG)
@@ -142,22 +159,10 @@ static int ramoops_pstore_write(enum pstore_type_id type,
if (part != 1)
return -ENOSPC;

- buf = cxt->virt_addr + (cxt->count * cxt->record_size);
-
- res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
- buf += res;
- available -= res;
-
- do_gettimeofday(&timestamp);
- res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
- buf += res;
- available -= res;
-
- if (size > available)
- size = available;
-
- memcpy(buf, cxt->pstore.buf, size);
- memset(buf + size, '\0', available - size);
+ hlen = ramoops_write_kmsg_hdr(prz);
+ if (size + hlen > prz->buffer_size)
+ size = prz->buffer_size - hlen;
+ persistent_ram_write(prz, cxt->pstore.buf, size);

cxt->count = (cxt->count + 1) % cxt->max_count;

@@ -167,14 +172,12 @@ static int ramoops_pstore_write(enum pstore_type_id type,
static int ramoops_pstore_erase(enum pstore_type_id type, u64 id,
struct pstore_info *psi)
{
- char *buf;
struct ramoops_context *cxt = psi->data;

if (id >= cxt->max_count)
return -EINVAL;

- buf = cxt->virt_addr + (id * cxt->record_size);
- memset(buf, '\0', cxt->record_size);
+ persistent_ram_free_old(cxt->przs[id]);

return 0;
}
@@ -192,9 +195,11 @@ static struct ramoops_context oops_cxt = {

static int __init ramoops_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct ramoops_platform_data *pdata = pdev->dev.platform_data;
struct ramoops_context *cxt = &oops_cxt;
int err = -EINVAL;
+ int i;

/* Only a single ramoops area allowed at a time, so fail extra
* probes.
@@ -232,8 +237,28 @@ static int __init ramoops_probe(struct platform_device *pdev)
cxt->record_size = pdata->record_size;
cxt->dump_oops = pdata->dump_oops;

+ cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_count, GFP_KERNEL);
+ if (!cxt->przs) {
+ err = -ENOMEM;
+ dev_err(dev, "failed to initialize a prz array\n");
+ goto fail_out;
+ }
+
+ for (i = 0; i < cxt->max_count; i++) {
+ size_t sz = cxt->record_size;
+ phys_addr_t start = cxt->phys_addr + sz * i;
+
+ cxt->przs[i] = persistent_ram_new(start, sz, 0);
+ if (IS_ERR(cxt->przs[i])) {
+ err = PTR_ERR(cxt->przs[i]);
+ dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
+ sz, (unsigned long long)start, err);
+ goto fail_przs;
+ }
+ }
+
cxt->pstore.data = cxt;
- cxt->pstore.bufsize = cxt->record_size;
+ cxt->pstore.bufsize = cxt->przs[0]->buffer_size;
cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
spin_lock_init(&cxt->pstore.buf_lock);
if (!cxt->pstore.buf) {
@@ -241,23 +266,10 @@ static int __init ramoops_probe(struct platform_device *pdev)
goto fail_clear;
}

- if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
- pr_err("request mem region (0x%lx@0x%llx) failed\n",
- cxt->size, (unsigned long long)cxt->phys_addr);
- err = -EINVAL;
- goto fail_buf;
- }
-
- cxt->virt_addr = ioremap(cxt->phys_addr, cxt->size);
- if (!cxt->virt_addr) {
- pr_err("ioremap failed\n");
- goto fail_mem_region;
- }
-
err = pstore_register(&cxt->pstore);
if (err) {
pr_err("registering with pstore failed\n");
- goto fail_iounmap;
+ goto fail_buf;
}

/*
@@ -275,15 +287,15 @@ static int __init ramoops_probe(struct platform_device *pdev)

return 0;

-fail_iounmap:
- iounmap(cxt->virt_addr);
-fail_mem_region:
- release_mem_region(cxt->phys_addr, cxt->size);
fail_buf:
kfree(cxt->pstore.buf);
fail_clear:
cxt->pstore.bufsize = 0;
cxt->max_count = 0;
+fail_przs:
+ for (i = 0; cxt->przs[i]; i++)
+ persistent_ram_free(cxt->przs[i]);
+ kfree(cxt->przs);
fail_out:
return err;
}
--
1.7.9.2

2012-05-16 12:45:59

by Anton Vorontsov

[permalink] [raw]
Subject: [PATCH 6/6] pstore/ram: Add ECC support

This is now straightforward: just introduce a module parameter and pass
the needed value to persistent_ram_new().

Signed-off-by: Anton Vorontsov <[email protected]>
Acked-by: Marco Stornelli <[email protected]>
Acked-by: Kees Cook <[email protected]>
---
Documentation/ramoops.txt | 6 ++++++
fs/pstore/ram.c | 15 ++++++++++++---
include/linux/pstore_ram.h | 1 +
3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
index 470d2c4..4ba7db2 100644
--- a/Documentation/ramoops.txt
+++ b/Documentation/ramoops.txt
@@ -30,6 +30,11 @@ variable while setting 0 in that variable dumps only the panics.
The module uses a counter to record multiple dumps but the counter gets reset
on restart (i.e. new dumps after the restart will overwrite old ones).

+Ramoops also supports software ECC protection of persistent memory regions.
+This might be useful when a hardware reset was used to bring the machine back
+to life (i.e. a watchdog triggered). In such cases, RAM may be somewhat
+corrupt, but usually it is restorable.
+
2. Setting the parameters

Setting the ramoops parameters can be done in 2 different manners:
@@ -46,6 +51,7 @@ static struct ramoops_platform_data ramoops_data = {
.mem_address = <...>,
.record_size = <...>,
.dump_oops = <...>,
+ .ecc = <...>,
};

static struct platform_device ramoops_dev = {
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 62b13ed..9123cce 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -56,12 +56,18 @@ module_param(dump_oops, int, 0600);
MODULE_PARM_DESC(dump_oops,
"set to 1 to dump oopses, 0 to only dump panics (default 1)");

+static int ramoops_ecc;
+module_param_named(ecc, ramoops_ecc, int, 0600);
+MODULE_PARM_DESC(ramoops_ecc,
+ "set to 1 to enable ECC support");
+
struct ramoops_context {
struct persistent_ram_zone **przs;
phys_addr_t phys_addr;
unsigned long size;
size_t record_size;
int dump_oops;
+ bool ecc;
unsigned int count;
unsigned int max_count;
unsigned int read_count;
@@ -236,6 +242,7 @@ static int __init ramoops_probe(struct platform_device *pdev)
cxt->phys_addr = pdata->mem_address;
cxt->record_size = pdata->record_size;
cxt->dump_oops = pdata->dump_oops;
+ cxt->ecc = pdata->ecc;

cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_count, GFP_KERNEL);
if (!cxt->przs) {
@@ -248,7 +255,7 @@ static int __init ramoops_probe(struct platform_device *pdev)
size_t sz = cxt->record_size;
phys_addr_t start = cxt->phys_addr + sz * i;

- cxt->przs[i] = persistent_ram_new(start, sz, 0);
+ cxt->przs[i] = persistent_ram_new(start, sz, cxt->ecc);
if (IS_ERR(cxt->przs[i])) {
err = PTR_ERR(cxt->przs[i]);
dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
@@ -281,9 +288,10 @@ static int __init ramoops_probe(struct platform_device *pdev)
record_size = pdata->record_size;
dump_oops = pdata->dump_oops;

- pr_info("attached 0x%lx@0x%llx (%ux0x%zx)\n",
+ pr_info("attached 0x%lx@0x%llx (%ux0x%zx), ecc: %s\n",
cxt->size, (unsigned long long)cxt->phys_addr,
- cxt->max_count, cxt->record_size);
+ cxt->max_count, cxt->record_size,
+ ramoops_ecc ? "on" : "off");

return 0;

@@ -347,6 +355,7 @@ static int __init ramoops_init(void)
dummy_data->mem_address = mem_address;
dummy_data->record_size = record_size;
dummy_data->dump_oops = dump_oops;
+ dummy_data->ecc = ramoops_ecc;
dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
NULL, 0, dummy_data,
sizeof(struct ramoops_platform_data));
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index ffe24a5..7ed7fd4 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -92,6 +92,7 @@ struct ramoops_platform_data {
unsigned long mem_address;
unsigned long record_size;
int dump_oops;
+ bool ecc;
};

#endif
--
1.7.9.2

2012-05-16 12:54:47

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH 2/6] ramoops: Move to fs/pstore/ram.c

On Wed, May 16, 2012 at 5:43 AM, Anton Vorontsov
<[email protected]> wrote:
> Since ramoops was converted to pstore, it has nothing to do with character
> devices nowadays. Instead, today it is just a RAM backend for pstore.
>
> The patch just moves things around. There are a few changes were needed
> because of the move:
>
> 1. Kconfig and Makefiles fixups, of course.
>
> 2. In pstore/ram.c we have to play a bit with MODULE_PARAM_PREFIX, this
> ? is needed to keep user experience the same as with ramoops driver
> ? (i.e. so that ramoops.foo kernel command line arguments would still
> ? work).
>
> Signed-off-by: Anton Vorontsov <[email protected]>
> Acked-by: Marco Stornelli <[email protected]>

Acked-by: Kees Cook <[email protected]>

--
Kees Cook
Chrome OS Security

2012-05-16 13:17:58

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 2/6] ramoops: Move to fs/pstore/ram.c

On Wed, May 16, 2012 at 05:43:08AM -0700, Anton Vorontsov wrote:
> Since ramoops was converted to pstore, it has nothing to do with character
> devices nowadays. Instead, today it is just a RAM backend for pstore.
>
> The patch just moves things around. There are a few changes were needed
> because of the move:
>
> 1. Kconfig and Makefiles fixups, of course.
>
> 2. In pstore/ram.c we have to play a bit with MODULE_PARAM_PREFIX, this
> is needed to keep user experience the same as with ramoops driver
> (i.e. so that ramoops.foo kernel command line arguments would still
> work).
>
> Signed-off-by: Anton Vorontsov <[email protected]>
> Acked-by: Marco Stornelli <[email protected]>
> Acked-by: Kees Cook <[email protected]>
> ---
> Documentation/ramoops.txt | 2 +-
> drivers/char/Kconfig | 9 --
> drivers/char/Makefile | 1 -
> drivers/char/ramoops.c | 362 --------------------------------------------
> fs/pstore/Kconfig | 14 ++
> fs/pstore/Makefile | 3 +
> fs/pstore/ram.c | 362 ++++++++++++++++++++++++++++++++++++++++++++
> include/linux/pstore_ram.h | 17 +++
> include/linux/ramoops.h | 17 ---
> 9 files changed, 397 insertions(+), 390 deletions(-)
> delete mode 100644 drivers/char/ramoops.c
> create mode 100644 fs/pstore/ram.c
> create mode 100644 include/linux/pstore_ram.h
> delete mode 100644 include/linux/ramoops.h

This patch fails to apply to my staging-next tree due to problems with
drivers/char/Kconfig and drivers/char/ramoops.c. What tree are you
making this patch against?

> --- a/drivers/char/Kconfig
> +++ b/drivers/char/Kconfig
> @@ -585,15 +585,6 @@ config DEVPORT
>
> source "drivers/s390/char/Kconfig"
>
> -config RAMOOPS
> - tristate "Log panic/oops to a RAM buffer"
> - depends on HAS_IOMEM
> - depends on PSTORE

This "depends on PSTORE" line is not in my staging-next tree, where did
it come from?

I'm guessing that because of this, is why the other conflict happens,
right?

Any ideas on what I can do to resolve it? As you are moving a file, I
want to make sure I move the correct version of it :)

thanks,

greg k-h

2012-05-16 13:20:05

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH v2 0/6] Merge ramoops and persistent_ram, generic pstore RAM backend

On Wed, May 16, 2012 at 05:41:09AM -0700, Anton Vorontsov wrote:
> Hi all,
>
> Here is v2 of the previous patch set. The series do not include
> patches that were already merged.
>
> I believe I addressed all the previous comments, plus now the
> series include another small cleanup patch.

I've applied patches 1 and 3 of this series to my staging-next tree, the
others would not apply due to the failure in patch 2. Care to fix that
up and resend so that I can apply them?

thanks,

greg k-h

2012-05-16 13:59:22

by Anton Vorontsov

[permalink] [raw]
Subject: Re: [PATCH 2/6] ramoops: Move to fs/pstore/ram.c

On Wed, May 16, 2012 at 06:17:51AM -0700, Greg Kroah-Hartman wrote:
[...]
> > --- a/drivers/char/Kconfig
> > +++ b/drivers/char/Kconfig
> > @@ -585,15 +585,6 @@ config DEVPORT
> >
> > source "drivers/s390/char/Kconfig"
> >
> > -config RAMOOPS
> > - tristate "Log panic/oops to a RAM buffer"
> > - depends on HAS_IOMEM
> > - depends on PSTORE
>
> This "depends on PSTORE" line is not in my staging-next tree, where did
> it come from?

The thing is that ramoops switched to pstore just recently, and the
patch is in -mm tree.

(Just for the record, I use linux-next-20120504, HEAD at commit
44449d2b34aca3b1)

> I'm guessing that because of this, is why the other conflict happens,
> right?

Yep.

> Any ideas on what I can do to resolve it? As you are moving a file, I
> want to make sure I move the correct version of it :)

There's a cross-tree dependency with -mm tree, as it appears.

So, I'm not sure which is better:

1. Push the whole pile of patches via -mm; or

2. You apply the two patches from -mm tree before my series:
"ramoops: use pstore interface"
linux-next commit 60aad9fc1f04ca19e800c5984ad84f405d133a11
and
"ramoops: fix printk format warnings"
linux-next commit f2a28afdb529c43a7eb21fd0c991cab5676ef011

http://userweb.kernel.org/~akpm/mmotm/ seem to not respond at the
moment, so I guess the easiest way to grab the patches would
be to cherry-pick the two commits above from the linux-next
repository. That way Andrew would automatically drop them
from his tree.

Thanks!

--
Anton Vorontsov
Email: [email protected]

2012-05-16 14:11:58

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 2/6] ramoops: Move to fs/pstore/ram.c

On Wed, May 16, 2012 at 06:57:49AM -0700, Anton Vorontsov wrote:
> On Wed, May 16, 2012 at 06:17:51AM -0700, Greg Kroah-Hartman wrote:
> [...]
> > > --- a/drivers/char/Kconfig
> > > +++ b/drivers/char/Kconfig
> > > @@ -585,15 +585,6 @@ config DEVPORT
> > >
> > > source "drivers/s390/char/Kconfig"
> > >
> > > -config RAMOOPS
> > > - tristate "Log panic/oops to a RAM buffer"
> > > - depends on HAS_IOMEM
> > > - depends on PSTORE
> >
> > This "depends on PSTORE" line is not in my staging-next tree, where did
> > it come from?
>
> The thing is that ramoops switched to pstore just recently, and the
> patch is in -mm tree.
>
> (Just for the record, I use linux-next-20120504, HEAD at commit
> 44449d2b34aca3b1)
>
> > I'm guessing that because of this, is why the other conflict happens,
> > right?
>
> Yep.
>
> > Any ideas on what I can do to resolve it? As you are moving a file, I
> > want to make sure I move the correct version of it :)
>
> There's a cross-tree dependency with -mm tree, as it appears.
>
> So, I'm not sure which is better:
>
> 1. Push the whole pile of patches via -mm; or
>
> 2. You apply the two patches from -mm tree before my series:
> "ramoops: use pstore interface"
> linux-next commit 60aad9fc1f04ca19e800c5984ad84f405d133a11
> and
> "ramoops: fix printk format warnings"
> linux-next commit f2a28afdb529c43a7eb21fd0c991cab5676ef011
>
> http://userweb.kernel.org/~akpm/mmotm/ seem to not respond at the
> moment, so I guess the easiest way to grab the patches would
> be to cherry-pick the two commits above from the linux-next
> repository. That way Andrew would automatically drop them
> from his tree.

Ok, I'll pick from linux-next, that seems to be the easiest way. I'll
do that later this morning and let you know how it goes...

greg k-h

2012-05-16 15:05:56

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 4/6] staging: android: persistent_ram: Move to fs/pstore/ram_core.c

On Wed, May 16, 2012 at 05:43:38AM -0700, Anton Vorontsov wrote:
> This is a first step for adding ECC support for pstore RAM backend: we
> will use the persistent_ram routines, kindly provided by Google.
>
> Basically, persistent_ram is a set of helper routines to deal with the
> [optionally] ECC-protected persistent ram regions.
>
> A bit of Makefile, Kconfig and header files adjustments were needed
> because of the move.
>
> Signed-off-by: Anton Vorontsov <[email protected]>
> Acked-by: Kees Cook <[email protected]>
> ---
> drivers/staging/android/Kconfig | 10 +-
> drivers/staging/android/Makefile | 1 -
> drivers/staging/android/persistent_ram.c | 532 ------------------------------
> drivers/staging/android/persistent_ram.h | 82 -----
> drivers/staging/android/ram_console.c | 2 +-
> fs/pstore/Kconfig | 7 +-
> fs/pstore/Makefile | 2 +-
> fs/pstore/ram_core.c | 532 ++++++++++++++++++++++++++++++
> include/linux/pstore_ram.h | 80 +++++
> 9 files changed, 620 insertions(+), 628 deletions(-)
> delete mode 100644 drivers/staging/android/persistent_ram.c
> delete mode 100644 drivers/staging/android/persistent_ram.h
> create mode 100644 fs/pstore/ram_core.c

After applying this patch, and building things, I get the following
errors:

drivers/built-in.o: In function `ram_console_write':
ram_console.c:(.text+0x1690b9): undefined reference to `persistent_ram_write'
drivers/built-in.o: In function `ram_console_read_old':
ram_console.c:(.text+0x1690f7): undefined reference to `persistent_ram_old_size'
ram_console.c:(.text+0x169103): undefined reference to `persistent_ram_old'
ram_console.c:(.text+0x169136): undefined reference to `persistent_ram_ecc_string'
ram_console.c:(.text+0x169177): undefined reference to `persistent_ram_ecc_string'
drivers/built-in.o: In function `ram_console_probe':
ram_console.c:(.init.text+0xc9ea): undefined reference to `persistent_ram_init_ringbuffer'
drivers/built-in.o: In function `ram_console_late_init':
ram_console.c:(.init.text+0xca6c): undefined reference to `persistent_ram_old_size'
ram_console.c:(.init.text+0xcaa2): undefined reference to `persistent_ram_free_old'
ram_console.c:(.init.text+0xcab4): undefined reference to `persistent_ram_old_size'
ram_console.c:(.init.text+0xcac3): undefined reference to `persistent_ram_ecc_string'
make: *** [.tmp_vmlinux1] Error 1

What went wrong?

I've now applied the first 3 patches in this series to my tree, plus the
2 others from the linux-next tree, so care to just fix up these last
three and resend them?

thanks,

greg k-h

2012-05-16 16:29:52

by Shuah Khan

[permalink] [raw]
Subject: Re: [PATCH 4/6] staging: android: persistent_ram: Move to fs/pstore/ram_core.c

On Wed, 2012-05-16 at 08:05 -0700, Greg Kroah-Hartman wrote:

>
> After applying this patch, and building things, I get the following
> errors:

Greg,

> What went wrong?
>
> I've now applied the first 3 patches in this series to my tree, plus the
> 2 others from the linux-next tree, so care to just fix up these last
> three and resend them?

Picking [PATCH 5/6] staging/android: Remove ram_console driver should
fix this problem. This patches removes ram_console.c from the staging
area.

-- Shuah

2012-05-16 17:53:29

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 4/6] staging: android: persistent_ram: Move to fs/pstore/ram_core.c

On Wed, May 16, 2012 at 10:29:46AM -0600, Shuah Khan wrote:
> On Wed, 2012-05-16 at 08:05 -0700, Greg Kroah-Hartman wrote:
>
> >
> > After applying this patch, and building things, I get the following
> > errors:
>
> Greg,
>
> > What went wrong?
> >
> > I've now applied the first 3 patches in this series to my tree, plus the
> > 2 others from the linux-next tree, so care to just fix up these last
> > three and resend them?
>
> Picking [PATCH 5/6] staging/android: Remove ram_console driver should
> fix this problem. This patches removes ram_console.c from the staging
> area.

That's nice, but you CAN NOT BREAK THE BUILD at any step of a patch
series progress.

So please rework this to prevent this from happening, as it is, I can
not accept these.

greg k-h

2012-05-16 23:46:31

by Arve Hjønnevåg

[permalink] [raw]
Subject: Re: [PATCH 4/6] persistent_ram: Move to fs/pstore/ram_core.c

On Wed, May 16, 2012 at 5:43 AM, Anton Vorontsov
<[email protected]> wrote:
> This is a first step for adding ECC support for pstore RAM backend: we
> will use the persistent_ram routines, kindly provided by Google.
>
> Basically, persistent_ram is a set of helper routines to deal with the
> [optionally] ECC-protected persistent ram regions.
>
...
> +static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
> + ? ? ? size_t buffer_size)
> +{
> + ? ? ? int numerr;
> + ? ? ? struct persistent_ram_buffer *buffer = prz->buffer;
> + ? ? ? int ecc_blocks;
> +
> + ? ? ? if (!prz->ecc)
> + ? ? ? ? ? ? ? return 0;
> +
> + ? ? ? prz->ecc_block_size = 128;
> + ? ? ? prz->ecc_size = 16;

I realize you are just moving code here, but 16 ecc bytes for per 128
bytes of data can only correct 8 bad bytes, which is not always
sufficient. At some point this will need to be made configurable
again.

--
Arve Hj?nnev?g

2012-05-17 00:51:46

by Anton Vorontsov

[permalink] [raw]
Subject: Re: [PATCH 4/6] staging: android: persistent_ram: Move to fs/pstore/ram_core.c

On Wed, May 16, 2012 at 08:05:50AM -0700, Greg Kroah-Hartman wrote:
[...]
> After applying this patch, and building things, I get the following
> errors:
>
> drivers/built-in.o: In function `ram_console_write':
> ram_console.c:(.text+0x1690b9): undefined reference to `persistent_ram_write'
> drivers/built-in.o: In function `ram_console_read_old':
> ram_console.c:(.text+0x1690f7): undefined reference to `persistent_ram_old_size'
> ram_console.c:(.text+0x169103): undefined reference to `persistent_ram_old'
> ram_console.c:(.text+0x169136): undefined reference to `persistent_ram_ecc_string'
> ram_console.c:(.text+0x169177): undefined reference to `persistent_ram_ecc_string'
> drivers/built-in.o: In function `ram_console_probe':
> ram_console.c:(.init.text+0xc9ea): undefined reference to `persistent_ram_init_ringbuffer'
> drivers/built-in.o: In function `ram_console_late_init':
> ram_console.c:(.init.text+0xca6c): undefined reference to `persistent_ram_old_size'
> ram_console.c:(.init.text+0xcaa2): undefined reference to `persistent_ram_free_old'
> ram_console.c:(.init.text+0xcab4): undefined reference to `persistent_ram_old_size'
> ram_console.c:(.init.text+0xcac3): undefined reference to `persistent_ram_ecc_string'
> make: *** [.tmp_vmlinux1] Error 1
>
> What went wrong?

I believe that error caused by two missing bytes: '=' and 'y'. :-)
RAM_CONSOLE is a bool, so it should be enabled only when PSTORE_RAM
is also =y. (For some reason I keep foregetting that bool's 'depends on'
may be satisfied by tristates' =m option, which easily lead to the
errors above.)

Thanks for catching this!

I've applied the following hunk to this patch and will resend the left
over patches soon:

diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 4bfcceb..0e16b59 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -27,7 +27,7 @@ config ANDROID_LOGGER

config ANDROID_RAM_CONSOLE
bool "Android RAM buffer console"
- depends on !S390 && !UML && HAVE_MEMBLOCK && PSTORE_RAM
+ depends on !S390 && !UML && HAVE_MEMBLOCK && PSTORE_RAM=y
default n

config ANDROID_TIMED_OUTPUT

--
Anton Vorontsov
Email: [email protected]