linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] pstore: ramoops: support multiple pmsg instances
@ 2015-11-05  2:36 Hiraku Toyooka
  2015-11-05  2:36 ` [PATCH 1/5] ramoops: use persistent_ram_free() instead of kfree() for freeing prz Hiraku Toyooka
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Hiraku Toyooka @ 2015-11-05  2:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tony Luck, Kees Cook, Anton Vorontsov, Mark Salyzyn, Colin Cross,
	Seiji Aguchi

The following series implements multiple pmsg. This feature allows
userspace program to control individual content aging or priority.

If a pstore backend module(e.g. ramoops) requires the multiple pmsg
instances when registering itself to pstore, multiple /dev/pmsg[ID]
are created. Writes to each /dev/pmsg[ID] are isolated each other. After
reboot, the contents are available in /sys/fs/pstore/pmsg-[backend]-[ID].

In addition, we add multiple pmsg support for ramoops. We can
specify multiple pmsg area size by its module parameter as follows.

 pmsg_size=0x1000,0x2000,...

---

Hiraku Toyooka (5):
      ramoops: use persistent_ram_free() instead of kfree() for freeing prz
      ramoops: introduce generic init/free functions for prz
      pstore: support multiple pmsg instances
      ramoops: support multiple pmsg instances
      selftests/pstore: add testcases for multiple pmsg instances


 Documentation/ramoops.txt                          |   22 ++
 fs/pstore/pmsg.c                                   |   20 ++
 fs/pstore/ram.c                                    |  213 +++++++++++++++-----
 include/linux/pstore.h                             |    1 
 include/linux/pstore_ram.h                         |    8 +
 tools/testing/selftests/pstore/common_tests        |   21 ++
 .../selftests/pstore/pstore_post_reboot_tests      |   27 +--
 tools/testing/selftests/pstore/pstore_tests        |   16 +-
 8 files changed, 257 insertions(+), 71 deletions(-)

--
Hiraku Toyooka

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] ramoops: use persistent_ram_free() instead of kfree() for freeing prz
  2015-11-05  2:36 [PATCH 0/5] pstore: ramoops: support multiple pmsg instances Hiraku Toyooka
@ 2015-11-05  2:36 ` Hiraku Toyooka
  2015-11-05  2:36 ` [PATCH 2/5] ramoops: introduce generic init/free functions for prz Hiraku Toyooka
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Hiraku Toyooka @ 2015-11-05  2:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tony Luck, Kees Cook, Seiji Aguchi, Mark Salyzyn,
	Anton Vorontsov, Colin Cross

persistent_ram_zone(=prz) structures are allocated by
persistent_ram_new(), which includes vmap() or ioremap(). But they
are currently freed by kfree(). We should use persistent_ram_free()
to correct this asymmetry usage.

Signed-off-by: Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>
Cc: Anton Vorontsov <anton@enomsg.org>
Cc: Colin Cross <ccross@android.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Mark Salyzyn <salyzyn@android.com>
Cc: Seiji Aguchi <seiji.aguchi.tr@hitachi.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: linux-kernel@vger.kernel.org
---
 fs/pstore/ram.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 6c26c4d..6363768 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -567,11 +567,11 @@ fail_buf:
 	kfree(cxt->pstore.buf);
 fail_clear:
 	cxt->pstore.bufsize = 0;
-	kfree(cxt->mprz);
+	persistent_ram_free(cxt->mprz);
 fail_init_mprz:
-	kfree(cxt->fprz);
+	persistent_ram_free(cxt->fprz);
 fail_init_fprz:
-	kfree(cxt->cprz);
+	persistent_ram_free(cxt->cprz);
 fail_init_cprz:
 	ramoops_free_przs(cxt);
 fail_out:


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] ramoops: introduce generic init/free functions for prz
  2015-11-05  2:36 [PATCH 0/5] pstore: ramoops: support multiple pmsg instances Hiraku Toyooka
  2015-11-05  2:36 ` [PATCH 1/5] ramoops: use persistent_ram_free() instead of kfree() for freeing prz Hiraku Toyooka
@ 2015-11-05  2:36 ` Hiraku Toyooka
  2015-11-05  2:36 ` [PATCH 3/5] pstore: support multiple pmsg instances Hiraku Toyooka
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Hiraku Toyooka @ 2015-11-05  2:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tony Luck, Kees Cook, Seiji Aguchi, Mark Salyzyn,
	Anton Vorontsov, Colin Cross

We modifies initialization and freeing code for prz for generic usage.
This change

 * add generic function __ramoops_init_prz() to reduce redundancy
   between ramoops_init_prz() and ramoops_init_przs().
 * rename 'przs' member in struct ramoops_context to 'dprzs' so that
   it stands for 'dump przs'.
 * rename ramoops_init_prz() to ramoops_init_dprzs().
 * change parameter of ramoops_free_przs() from struct ramoops_context *
   into struct persistent_ram_zone * in order to make it available for
   all prz array.

Signed-off-by: Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>
Cc: Anton Vorontsov <anton@enomsg.org>
Cc: Colin Cross <ccross@android.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Mark Salyzyn <salyzyn@android.com>
Cc: Seiji Aguchi <seiji.aguchi.tr@hitachi.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: linux-kernel@vger.kernel.org
---
 fs/pstore/ram.c |   63 +++++++++++++++++++++++++++++++------------------------
 1 file changed, 35 insertions(+), 28 deletions(-)

diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 6363768..89cc90e 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -83,7 +83,7 @@ MODULE_PARM_DESC(ramoops_ecc,
 		"bytes ECC)");
 
 struct ramoops_context {
-	struct persistent_ram_zone **przs;
+	struct persistent_ram_zone **dprzs;
 	struct persistent_ram_zone *cprz;
 	struct persistent_ram_zone *fprz;
 	struct persistent_ram_zone *mprz;
@@ -199,7 +199,7 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
 
 	/* Find the next valid persistent_ram_zone for DMESG */
 	while (cxt->dump_read_cnt < cxt->max_dump_cnt && !prz) {
-		prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
+		prz = ramoops_get_next_prz(cxt->dprzs, &cxt->dump_read_cnt,
 					   cxt->max_dump_cnt, id, type,
 					   PSTORE_TYPE_DMESG, 1);
 		if (!prz_ok(prz))
@@ -314,10 +314,10 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
 	if (part != 1)
 		return -ENOSPC;
 
-	if (!cxt->przs)
+	if (!cxt->dprzs)
 		return -ENOSPC;
 
-	prz = cxt->przs[cxt->dump_write_cnt];
+	prz = cxt->dprzs[cxt->dump_write_cnt];
 
 	hlen = ramoops_write_kmsg_hdr(prz, compressed);
 	if (size + hlen > prz->buffer_size)
@@ -339,7 +339,7 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
 	case PSTORE_TYPE_DMESG:
 		if (id >= cxt->max_dump_cnt)
 			return -EINVAL;
-		prz = cxt->przs[id];
+		prz = cxt->dprzs[id];
 		break;
 	case PSTORE_TYPE_CONSOLE:
 		prz = cxt->cprz;
@@ -371,21 +371,24 @@ static struct ramoops_context oops_cxt = {
 	},
 };
 
-static void ramoops_free_przs(struct ramoops_context *cxt)
+static void ramoops_free_przs(struct persistent_ram_zone **przs)
 {
 	int i;
 
-	cxt->max_dump_cnt = 0;
-	if (!cxt->przs)
+	if (!przs)
 		return;
 
-	for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++)
-		persistent_ram_free(cxt->przs[i]);
-	kfree(cxt->przs);
+	for (i = 0; i < !IS_ERR_OR_NULL(przs[i]); i++)
+		persistent_ram_free(przs[i]);
+	kfree(przs);
 }
 
-static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
-			     phys_addr_t *paddr, size_t dump_mem_sz)
+static int __ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
+			      struct persistent_ram_zone **prz,
+			      phys_addr_t *paddr, size_t sz, u32 sig, bool zap);
+
+static int ramoops_init_dprzs(struct device *dev, struct ramoops_context *cxt,
+			      phys_addr_t *paddr, size_t dump_mem_sz)
 {
 	int err = -ENOMEM;
 	int i;
@@ -402,29 +405,24 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
 	if (!cxt->max_dump_cnt)
 		return -ENOMEM;
 
-	cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt,
+	cxt->dprzs = kcalloc(cxt->max_dump_cnt, sizeof(*cxt->dprzs),
 			     GFP_KERNEL);
-	if (!cxt->przs) {
+	if (!cxt->dprzs) {
 		dev_err(dev, "failed to initialize a prz array for dumps\n");
 		goto fail_prz;
 	}
 
 	for (i = 0; i < cxt->max_dump_cnt; i++) {
-		cxt->przs[i] = persistent_ram_new(*paddr, cxt->record_size, 0,
-						  &cxt->ecc_info,
-						  cxt->memtype);
-		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",
-				cxt->record_size, (unsigned long long)*paddr, err);
+		err = __ramoops_init_prz(dev, cxt, &cxt->dprzs[i], paddr,
+					 cxt->record_size, 0, false);
+		if (err)
 			goto fail_prz;
-		}
-		*paddr += cxt->record_size;
 	}
 
 	return 0;
 fail_prz:
-	ramoops_free_przs(cxt);
+	cxt->max_dump_cnt = 0;
+	ramoops_free_przs(cxt->dprzs);
 	return err;
 }
 
@@ -432,6 +430,13 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
 			    struct persistent_ram_zone **prz,
 			    phys_addr_t *paddr, size_t sz, u32 sig)
 {
+	return __ramoops_init_prz(dev, cxt, prz, paddr, sz, sig, true);
+}
+
+static int __ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
+			      struct persistent_ram_zone **prz,
+			      phys_addr_t *paddr, size_t sz, u32 sig, bool zap)
+{
 	if (!sz)
 		return 0;
 
@@ -451,7 +456,8 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
 		return err;
 	}
 
-	persistent_ram_zap(*prz);
+	if (zap)
+		persistent_ram_zap(*prz);
 
 	*paddr += sz;
 
@@ -503,7 +509,7 @@ static int ramoops_probe(struct platform_device *pdev)
 
 	dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size
 			- cxt->pmsg_size;
-	err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz);
+	err = ramoops_init_dprzs(dev, cxt, &paddr, dump_mem_sz);
 	if (err)
 		goto fail_out;
 
@@ -573,7 +579,8 @@ fail_init_mprz:
 fail_init_fprz:
 	persistent_ram_free(cxt->cprz);
 fail_init_cprz:
-	ramoops_free_przs(cxt);
+	cxt->max_dump_cnt = 0;
+	ramoops_free_przs(cxt->dprzs);
 fail_out:
 	return err;
 }


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] pstore: support multiple pmsg instances
  2015-11-05  2:36 [PATCH 0/5] pstore: ramoops: support multiple pmsg instances Hiraku Toyooka
  2015-11-05  2:36 ` [PATCH 1/5] ramoops: use persistent_ram_free() instead of kfree() for freeing prz Hiraku Toyooka
  2015-11-05  2:36 ` [PATCH 2/5] ramoops: introduce generic init/free functions for prz Hiraku Toyooka
@ 2015-11-05  2:36 ` Hiraku Toyooka
  2015-11-05  2:36 ` [PATCH 4/5] ramoops: " Hiraku Toyooka
  2015-11-05  2:36 ` [PATCH 5/5] selftests/pstore: add testcases for " Hiraku Toyooka
  4 siblings, 0 replies; 6+ messages in thread
From: Hiraku Toyooka @ 2015-11-05  2:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tony Luck, Kees Cook, Seiji Aguchi, Mark Salyzyn,
	Anton Vorontsov, Colin Cross

This patch enables pmsg to deal with multiple instances. One possible
use is content priority control on limited persistent store space. By
using different buffers, we can prevent important messages from being
overwritten by less important messages.

When a pstore backend module specifies the number of instances (num_pmsg)
in pstore_info, multiple /dev/pmsg[ID] appear. (ID is an integer
starting at 0. It corresponds to minor number of the each char device.)
Writes to each /dev/pmsg[ID] are isolated each other. After reboot, the
contents are available in /sys/fs/pstore/pmsg-[backend]-[ID].

Signed-off-by: Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>
Cc: Anton Vorontsov <anton@enomsg.org>
Cc: Colin Cross <ccross@android.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Mark Salyzyn <salyzyn@android.com>
Cc: Seiji Aguchi <seiji.aguchi.tr@hitachi.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: linux-kernel@vger.kernel.org
---
 fs/pstore/pmsg.c       |   20 ++++++++++++++++++--
 include/linux/pstore.h |    1 +
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/fs/pstore/pmsg.c b/fs/pstore/pmsg.c
index feb5dd2..3467d63 100644
--- a/fs/pstore/pmsg.c
+++ b/fs/pstore/pmsg.c
@@ -50,8 +50,8 @@ static ssize_t write_pmsg(struct file *file, const char __user *buf,
 			vfree(buffer);
 			return -EFAULT;
 		}
-		psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id, 0, buffer, 0, c,
-				  psinfo);
+		psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id,
+				  iminor(file->f_inode), buffer, 0, c, psinfo);
 
 		i += c;
 	}
@@ -83,6 +83,7 @@ static char *pmsg_devnode(struct device *dev, umode_t *mode)
 void pstore_register_pmsg(void)
 {
 	struct device *pmsg_device;
+	int i = 0;
 
 	pmsg_major = register_chrdev(0, PMSG_NAME, &pmsg_fops);
 	if (pmsg_major < 0) {
@@ -103,9 +104,24 @@ void pstore_register_pmsg(void)
 		pr_err("failed to create device\n");
 		goto err_device;
 	}
+
+	/* allocate additional /dev/pmsg[ID] */
+	for (i = 1; i < psinfo->num_pmsg; i++) {
+		struct device *pmsg_device;
+
+		pmsg_device = device_create(pmsg_class, NULL,
+					    MKDEV(pmsg_major, i), NULL, "%s%d",
+					    PMSG_NAME, i);
+		if (IS_ERR(pmsg_device)) {
+			pr_err("failed to create device\n");
+			goto err_device;
+		}
+	}
 	return;
 
 err_device:
+	for (i--; i >= 0; i--)
+		device_destroy(pmsg_class, MKDEV(pmsg_major, i));
 	class_destroy(pmsg_class);
 err_class:
 	unregister_chrdev(pmsg_major, PMSG_NAME);
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index 8e7a25b..7cffc9d 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -54,6 +54,7 @@ struct pstore_info {
 	size_t		bufsize;
 	struct mutex	read_mutex;	/* serialize open/read/close */
 	int		flags;
+	unsigned int	num_pmsg;
 	int		(*open)(struct pstore_info *psi);
 	int		(*close)(struct pstore_info *psi);
 	ssize_t		(*read)(u64 *id, enum pstore_type_id *type,


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] ramoops: support multiple pmsg instances
  2015-11-05  2:36 [PATCH 0/5] pstore: ramoops: support multiple pmsg instances Hiraku Toyooka
                   ` (2 preceding siblings ...)
  2015-11-05  2:36 ` [PATCH 3/5] pstore: support multiple pmsg instances Hiraku Toyooka
@ 2015-11-05  2:36 ` Hiraku Toyooka
  2015-11-05  2:36 ` [PATCH 5/5] selftests/pstore: add testcases for " Hiraku Toyooka
  4 siblings, 0 replies; 6+ messages in thread
From: Hiraku Toyooka @ 2015-11-05  2:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: Jonathan Corbet, Tony Luck, Kees Cook, linux-doc,
	Anton Vorontsov, Mark Salyzyn, Colin Cross, Seiji Aguchi

This patch enables ramoops to deal with multiple pmsg instances.
We can configure the size of each buffers by its module parameter
as follows.

  pmsg_size=0x1000,0x2000,...

Then, the ramoops allocates multiple buffers and tells the number
of buffers to pstore to create multiple /dev/pmsg[ID].

Signed-off-by: Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Anton Vorontsov <anton@enomsg.org>
Cc: Colin Cross <ccross@android.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Mark Salyzyn <salyzyn@android.com>
Cc: Seiji Aguchi <seiji.aguchi.tr@hitachi.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
 Documentation/ramoops.txt  |   22 +++++++
 fs/pstore/ram.c            |  146 ++++++++++++++++++++++++++++++++++++++------
 include/linux/pstore_ram.h |    8 ++
 3 files changed, 154 insertions(+), 22 deletions(-)

diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
index 5d86756..cff6ac7 100644
--- a/Documentation/ramoops.txt
+++ b/Documentation/ramoops.txt
@@ -126,3 +126,25 @@ file. Here is an example of usage:
  0 ffffffff811d9c54  ffffffff8101a7a0  __const_udelay <- native_machine_emergency_restart+0x110/0x1e0
  0 ffffffff811d9c34  ffffffff811d9c80  __delay <- __const_udelay+0x30/0x40
  0 ffffffff811d9d14  ffffffff811d9c3f  delay_tsc <- __delay+0xf/0x20
+
+6. Pmsg support
+
+Ramoops supports pmsg - logging userspace mesages in persistent store. By
+default, one pmsg area becomes available in ramoops. You can write data into
+/dev/pmsg0, e.g.:
+
+ # echo foo > /dev/pmsg0
+
+After reboot, the stored data can be read from pmsg-ramoops-0 on the pstore
+filesystem.
+
+You can specify size of the pmsg area by additional kernel command line, e.g.:
+
+ "ramoops.pmsg_size=0x1000"
+
+You can also use multiple pmsg areas, e.g.:
+
+ "ramoops.pmsg_size=0x1000,0x2000,..."
+
+Then, pmsg0, pmsg1, ... will appear on /dev. This is useful to control
+individual content aging or priority.
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 89cc90e..1d1378c 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -51,8 +51,8 @@ static ulong ramoops_ftrace_size = MIN_MEM_SIZE;
 module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400);
 MODULE_PARM_DESC(ftrace_size, "size of ftrace log");
 
-static ulong ramoops_pmsg_size = MIN_MEM_SIZE;
-module_param_named(pmsg_size, ramoops_pmsg_size, ulong, 0400);
+static char *ramoops_pmsg_size_str;
+module_param_named(pmsg_size, ramoops_pmsg_size_str, charp, 0400);
 MODULE_PARM_DESC(pmsg_size, "size of user space message log");
 
 static ulong mem_address;
@@ -86,14 +86,14 @@ struct ramoops_context {
 	struct persistent_ram_zone **dprzs;
 	struct persistent_ram_zone *cprz;
 	struct persistent_ram_zone *fprz;
-	struct persistent_ram_zone *mprz;
+	struct persistent_ram_zone **mprzs;
 	phys_addr_t phys_addr;
 	unsigned long size;
 	unsigned int memtype;
 	size_t record_size;
 	size_t console_size;
 	size_t ftrace_size;
-	size_t pmsg_size;
+	size_t *pmsg_size;
 	int dump_oops;
 	struct persistent_ram_ecc_info ecc_info;
 	unsigned int max_dump_cnt;
@@ -103,6 +103,7 @@ struct ramoops_context {
 	unsigned int console_read_cnt;
 	unsigned int ftrace_read_cnt;
 	unsigned int pmsg_read_cnt;
+	unsigned int num_pmsg;
 	struct pstore_info pstore;
 };
 
@@ -220,9 +221,10 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
 	if (!prz_ok(prz))
 		prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
 					   1, id, type, PSTORE_TYPE_FTRACE, 0);
-	if (!prz_ok(prz))
-		prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
-					   1, id, type, PSTORE_TYPE_PMSG, 0);
+	while (cxt->pmsg_read_cnt < cxt->num_pmsg && !prz)
+		prz = ramoops_get_next_prz(cxt->mprzs, &cxt->pmsg_read_cnt,
+					   cxt->num_pmsg, id, type,
+					   PSTORE_TYPE_PMSG, 0);
 	if (!prz_ok(prz))
 		return 0;
 
@@ -286,9 +288,11 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
 		persistent_ram_write(cxt->fprz, buf, size);
 		return 0;
 	} else if (type == PSTORE_TYPE_PMSG) {
-		if (!cxt->mprz)
+		if (part >= cxt->num_pmsg)
+			return -EINVAL;
+		if (!cxt->mprzs || !cxt->mprzs[part])
 			return -ENOMEM;
-		persistent_ram_write(cxt->mprz, buf, size);
+		persistent_ram_write(cxt->mprzs[part], buf, size);
 		return 0;
 	}
 
@@ -348,7 +352,9 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
 		prz = cxt->fprz;
 		break;
 	case PSTORE_TYPE_PMSG:
-		prz = cxt->mprz;
+		if (id >= cxt->num_pmsg)
+			return -EINVAL;
+		prz = cxt->mprzs[id];
 		break;
 	default:
 		return -EINVAL;
@@ -426,6 +432,39 @@ fail_prz:
 	return err;
 }
 
+static int ramoops_init_mprzs(struct device *dev, struct ramoops_context *cxt,
+			      phys_addr_t *paddr, unsigned long total)
+{
+	int err = -ENOMEM;
+	int i;
+
+	if (!total)
+		return 0;
+
+	if (*paddr + total - cxt->phys_addr > cxt->size) {
+		dev_err(dev, "no room for pmsg\n");
+		return -ENOMEM;
+	}
+
+	cxt->mprzs = kcalloc(cxt->num_pmsg, sizeof(*cxt->mprzs), GFP_KERNEL);
+	if (!cxt->mprzs) {
+		dev_err(dev, "failed to initialize a mprz array for pmsg\n");
+		goto fail_prz;
+	}
+
+	for (i = 0; i < cxt->num_pmsg; i++) {
+		err = __ramoops_init_prz(dev, cxt, &cxt->mprzs[i], paddr,
+					 cxt->pmsg_size[i], 0, true);
+		if (err)
+			goto fail_prz;
+	}
+
+	return 0;
+fail_prz:
+	ramoops_free_przs(cxt->mprzs);
+	return err;
+}
+
 static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
 			    struct persistent_ram_zone **prz,
 			    phys_addr_t *paddr, size_t sz, u32 sig)
@@ -472,6 +511,8 @@ static int ramoops_probe(struct platform_device *pdev)
 	size_t dump_mem_sz;
 	phys_addr_t paddr;
 	int err = -EINVAL;
+	unsigned long pmsg_size_total = 0;
+	unsigned int num_pmsg = 0;
 
 	/* Only a single ramoops area allowed at a time, so fail extra
 	 * probes.
@@ -492,8 +533,18 @@ static int ramoops_probe(struct platform_device *pdev)
 		pdata->console_size = rounddown_pow_of_two(pdata->console_size);
 	if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size))
 		pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
-	if (pdata->pmsg_size && !is_power_of_2(pdata->pmsg_size))
-		pdata->pmsg_size = rounddown_pow_of_two(pdata->pmsg_size);
+	if (pdata->pmsg_size) {
+		for (;; num_pmsg++) {
+			unsigned long size = pdata->pmsg_size[num_pmsg];
+
+			if (!size)
+				break;
+			if (!is_power_of_2(size))
+				pdata->pmsg_size[num_pmsg]
+					= rounddown_pow_of_two(size);
+			pmsg_size_total += size;
+		}
+	}
 
 	cxt->size = pdata->mem_size;
 	cxt->phys_addr = pdata->mem_address;
@@ -501,17 +552,26 @@ static int ramoops_probe(struct platform_device *pdev)
 	cxt->record_size = pdata->record_size;
 	cxt->console_size = pdata->console_size;
 	cxt->ftrace_size = pdata->ftrace_size;
-	cxt->pmsg_size = pdata->pmsg_size;
 	cxt->dump_oops = pdata->dump_oops;
 	cxt->ecc_info = pdata->ecc_info;
+	cxt->num_pmsg = num_pmsg;
+	if (num_pmsg) {
+		cxt->pmsg_size = kcalloc(num_pmsg, sizeof(size_t), GFP_KERNEL);
+		if (!cxt->pmsg_size) {
+			err = -ENOMEM;
+			goto fail_out;
+		}
+		memcpy(cxt->pmsg_size, pdata->pmsg_size,
+		       sizeof(size_t) * num_pmsg);
+	}
 
 	paddr = cxt->phys_addr;
 
 	dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size
-			- cxt->pmsg_size;
+			- pmsg_size_total;
 	err = ramoops_init_dprzs(dev, cxt, &paddr, dump_mem_sz);
 	if (err)
-		goto fail_out;
+		goto fail_init_dprzs;
 
 	err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr,
 			       cxt->console_size, 0);
@@ -523,11 +583,12 @@ static int ramoops_probe(struct platform_device *pdev)
 	if (err)
 		goto fail_init_fprz;
 
-	err = ramoops_init_prz(dev, cxt, &cxt->mprz, &paddr, cxt->pmsg_size, 0);
+	err = ramoops_init_mprzs(dev, cxt, &paddr, pmsg_size_total);
 	if (err)
-		goto fail_init_mprz;
+		goto fail_init_mprzs;
 
 	cxt->pstore.data = cxt;
+	cxt->pstore.num_pmsg = num_pmsg;
 	/*
 	 * Console can handle any buffer size, so prefer LOG_LINE_MAX. If we
 	 * have to handle dumps, we must have at least record_size buffer. And
@@ -560,7 +621,6 @@ static int ramoops_probe(struct platform_device *pdev)
 	record_size = pdata->record_size;
 	dump_oops = pdata->dump_oops;
 	ramoops_console_size = pdata->console_size;
-	ramoops_pmsg_size = pdata->pmsg_size;
 	ramoops_ftrace_size = pdata->ftrace_size;
 
 	pr_info("attached 0x%lx@0x%llx, ecc: %d/%d\n",
@@ -573,14 +633,16 @@ fail_buf:
 	kfree(cxt->pstore.buf);
 fail_clear:
 	cxt->pstore.bufsize = 0;
-	persistent_ram_free(cxt->mprz);
-fail_init_mprz:
+	ramoops_free_przs(cxt->mprzs);
+fail_init_mprzs:
 	persistent_ram_free(cxt->fprz);
 fail_init_fprz:
 	persistent_ram_free(cxt->cprz);
 fail_init_cprz:
 	cxt->max_dump_cnt = 0;
 	ramoops_free_przs(cxt->dprzs);
+fail_init_dprzs:
+	kfree(cxt->pmsg_size);
 fail_out:
 	return err;
 }
@@ -600,6 +662,7 @@ static int __exit ramoops_remove(struct platform_device *pdev)
 	/* TODO(kees): When pstore supports unregistering, call it here. */
 	kfree(cxt->pstore.buf);
 	cxt->pstore.bufsize = 0;
+	kfree(cxt->pmsg_size);
 
 	return 0;
 #endif
@@ -614,6 +677,38 @@ static struct platform_driver ramoops_driver = {
 	},
 };
 
+static unsigned long *parse_size_str(char *size_str)
+{
+	int i, ret;
+	unsigned long *size_array, count = 1;
+
+	if (size_str) {
+		char *s = size_str;
+		/* Necessary array size is the number of commas + 1 */
+		for (; (s = strchr(s, ',')); s++)
+			count++;
+	}
+
+	size_array = kcalloc(count + 1, sizeof(unsigned long), GFP_KERNEL);
+	if (!size_array)
+		goto out;
+
+	if (size_str) {
+		for (i = 0; i < count; i++) {
+			ret = get_option(&size_str, (int *)&size_array[i]);
+			if (ret == 1)
+				break;
+			else if (ret != 2) {
+				size_array[i] = 0;
+				break;
+			}
+		}
+	} else
+		size_array[0] = MIN_MEM_SIZE;
+out:
+	return size_array;
+}
+
 static void ramoops_register_dummy(void)
 {
 	if (!mem_size)
@@ -633,7 +728,9 @@ static void ramoops_register_dummy(void)
 	dummy_data->record_size = record_size;
 	dummy_data->console_size = ramoops_console_size;
 	dummy_data->ftrace_size = ramoops_ftrace_size;
-	dummy_data->pmsg_size = ramoops_pmsg_size;
+	dummy_data->pmsg_size = parse_size_str(ramoops_pmsg_size_str);
+	if (!dummy_data->pmsg_size)
+		goto fail_pmsg_size;
 	dummy_data->dump_oops = dump_oops;
 	/*
 	 * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC
@@ -646,7 +743,13 @@ static void ramoops_register_dummy(void)
 	if (IS_ERR(dummy)) {
 		pr_info("could not create platform device: %ld\n",
 			PTR_ERR(dummy));
+		goto fail_pdev;
 	}
+	return;
+fail_pdev:
+	kfree(dummy_data->pmsg_size);
+fail_pmsg_size:
+	kfree(dummy_data);
 }
 
 static int __init ramoops_init(void)
@@ -660,6 +763,7 @@ static void __exit ramoops_exit(void)
 {
 	platform_driver_unregister(&ramoops_driver);
 	platform_device_unregister(dummy);
+	kfree(dummy_data->pmsg_size);
 	kfree(dummy_data);
 }
 module_exit(ramoops_exit);
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index 9c9d6c1..e808789 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -72,6 +72,12 @@ ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
  * Ramoops platform data
  * @mem_size	memory size for ramoops
  * @mem_address	physical memory address to contain ramoops
+ * @pmsg_size	array containing size of each pmsg area. 0 value in the array
+ *		indicates the end of the content. For example, if the following
+ *		array is given,
+ *		    .pmsg_size = { 0x1000, 0x2000, 0x0, 0x3000, };
+ *		then, pmsg areas are allocated for the first two size values
+ *		and '0x3000' is just ignored.
  */
 
 struct ramoops_platform_data {
@@ -81,7 +87,7 @@ struct ramoops_platform_data {
 	unsigned long	record_size;
 	unsigned long	console_size;
 	unsigned long	ftrace_size;
-	unsigned long	pmsg_size;
+	unsigned long	*pmsg_size;
 	int		dump_oops;
 	struct persistent_ram_ecc_info ecc_info;
 };


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] selftests/pstore: add testcases for multiple pmsg instances
  2015-11-05  2:36 [PATCH 0/5] pstore: ramoops: support multiple pmsg instances Hiraku Toyooka
                   ` (3 preceding siblings ...)
  2015-11-05  2:36 ` [PATCH 4/5] ramoops: " Hiraku Toyooka
@ 2015-11-05  2:36 ` Hiraku Toyooka
  4 siblings, 0 replies; 6+ messages in thread
From: Hiraku Toyooka @ 2015-11-05  2:36 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tony Luck, Kees Cook, linux-api, Anton Vorontsov, Shuah Khan,
	Mark Salyzyn, Colin Cross, Seiji Aguchi

To test multiple pmsg, we should check that /dev/pmsg[N] (N > 0) is
available. After reboot, we should check that pmsg-[backend]-[N] which
keeps content is detected even if pmsg-[backend]-[N-M] (0 < M <= N)
doesn't exist due to lack of contents.

So we add the following testcases.
 - pstore_tests
   - Write unique string to the last /dev/pmsgN
 - pstore_post_reboot_tests
   - Check the last pmsg area is detected

Signed-off-by: Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>
Cc: Anton Vorontsov <anton@enomsg.org>
Cc: Colin Cross <ccross@android.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Mark Salyzyn <salyzyn@android.com>
Cc: Seiji Aguchi <seiji.aguchi.tr@hitachi.com>
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
 tools/testing/selftests/pstore/common_tests        |   21 ++++++++++++++--
 .../selftests/pstore/pstore_post_reboot_tests      |   27 +++++++++++---------
 tools/testing/selftests/pstore/pstore_tests        |   16 ++++++++++--
 3 files changed, 47 insertions(+), 17 deletions(-)

diff --git a/tools/testing/selftests/pstore/common_tests b/tools/testing/selftests/pstore/common_tests
index 3ea64d7..566a25d 100755
--- a/tools/testing/selftests/pstore/common_tests
+++ b/tools/testing/selftests/pstore/common_tests
@@ -27,9 +27,9 @@ show_result() { # result_value
 }
 
 check_files_exist() { # type of pstorefs file
-    if [ -e ${1}-${backend}-0 ]; then
+    if [ -e ${1}0 ]; then
 	prlog "ok"
-	for f in `ls ${1}-${backend}-*`; do
+	for f in `ls ${1}*`; do
             prlog -e "\t${f}"
 	done
     else
@@ -53,6 +53,23 @@ operate_files() { # tested value, files, operation
     fi
 }
 
+check_pmsg_content() { # pmsg filename
+    prev_uuid=`cat $TOP_DIR/prev_uuid`
+    if [ $? -eq 0 ]; then
+	nr_matched=`grep -c "$TEST_STRING_PATTERN" $1`
+	if [ "$nr_matched" = "1" ]; then
+	    grep -q "$TEST_STRING_PATTERN"$prev_uuid $1
+	    show_result $?
+	else
+	    prlog "FAIL"
+	    rc=1
+	fi
+    else
+	prlog "FAIL"
+	rc=1
+    fi
+}
+
 # Parameters
 TEST_STRING_PATTERN="Testing pstore: uuid="
 UUID=`cat /proc/sys/kernel/random/uuid`
diff --git a/tools/testing/selftests/pstore/pstore_post_reboot_tests b/tools/testing/selftests/pstore/pstore_post_reboot_tests
index 6ccb154..272498f 100755
--- a/tools/testing/selftests/pstore/pstore_post_reboot_tests
+++ b/tools/testing/selftests/pstore/pstore_post_reboot_tests
@@ -35,13 +35,13 @@ fi
 cd ${mount_point}
 
 prlog -n "Checking dmesg files exist in pstore filesystem ... "
-check_files_exist dmesg
+check_files_exist dmesg-${backend}-
 
 prlog -n "Checking console files exist in pstore filesystem ... "
-check_files_exist console
+check_files_exist console-${backend}-
 
 prlog -n "Checking pmsg files exist in pstore filesystem ... "
-check_files_exist pmsg
+check_files_exist pmsg-${backend}-
 
 prlog -n "Checking dmesg files contain oops end marker"
 grep_end_trace() {
@@ -54,16 +54,19 @@ prlog -n "Checking console file contains oops end marker ... "
 grep -q "\---\[ end trace" console-${backend}-0
 show_result $?
 
-prlog -n "Checking pmsg file properly keeps the content written before crash ... "
-prev_uuid=`cat $TOP_DIR/prev_uuid`
-if [ $? -eq 0 ]; then
-    nr_matched=`grep -c "$TEST_STRING_PATTERN" pmsg-${backend}-0`
-    if [ $nr_matched -eq 1 ]; then
-	grep -q "$TEST_STRING_PATTERN"$prev_uuid pmsg-${backend}-0
-	show_result $?
+prlog -n "Checking pmsg-"${backend}"-0 properly keeps the content written before crash ... "
+check_pmsg_content pmsg-${backend}-0
+
+prlog -n "Checking the last pmsg area is detected "
+last_num_pmsg=`ls -v pmsg-* | tail -n1 | sed -e "s/^pmsg-${backend}-\([0-9]*\).*$/\1/"`
+last_num_devpmsg=`ls -v /dev/pmsg* | tail -n1 | sed -e "s/^\/dev\/pmsg\([0-9]*\).*$/\1/"`
+#checks the last number of pmsg-*-* and /dev/pmsg* correspond.
+if [ "$last_num_pmsg" -eq "$last_num_devpmsg" ]; then
+    if [ "$last_num_pmsg" = "0" ]; then
+	prlog "... No multiple pmsg-*-* exists. We skip this testcase."
     else
-	prlog "FAIL"
-	rc=1
+	prlog -n "(pmsg-${backend}-${last_num_pmsg}) ... "
+	check_pmsg_content pmsg-${backend}-${last_num_pmsg}
     fi
 else
     prlog "FAIL"
diff --git a/tools/testing/selftests/pstore/pstore_tests b/tools/testing/selftests/pstore/pstore_tests
index f25d2a3..5abf0e5 100755
--- a/tools/testing/selftests/pstore/pstore_tests
+++ b/tools/testing/selftests/pstore/pstore_tests
@@ -13,9 +13,8 @@ prlog -n "Checking pstore console is registered ... "
 dmesg | grep -q "console \[pstore"
 show_result $?
 
-prlog -n "Checking /dev/pmsg0 exists ... "
-test -e /dev/pmsg0
-show_result $?
+prlog -n "Checking /dev/pmsg files exist ... "
+check_files_exist /dev/pmsg
 
 prlog -n "Writing unique string to /dev/pmsg0 ... "
 if [ -e "/dev/pmsg0" ]; then
@@ -27,4 +26,15 @@ else
     rc=1
 fi
 
+last_devpmsg=`ls -v /dev/pmsg* | tail -n1`
+prlog -n "Writing unique string to the last /dev/pmsgN "
+if [ "$last_devpmsg" = "/dev/pmsg0" ]; then
+    prlog "... No multiple /dev/pmsg* exists. We skip this testcase."
+else
+    prlog -n "(${last_devpmsg}) ... "
+    echo "${TEST_STRING_PATTERN}""$UUID" > ${last_devpmsg}
+    show_result $?
+
+fi
+
 exit $rc


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-11-05  2:38 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-05  2:36 [PATCH 0/5] pstore: ramoops: support multiple pmsg instances Hiraku Toyooka
2015-11-05  2:36 ` [PATCH 1/5] ramoops: use persistent_ram_free() instead of kfree() for freeing prz Hiraku Toyooka
2015-11-05  2:36 ` [PATCH 2/5] ramoops: introduce generic init/free functions for prz Hiraku Toyooka
2015-11-05  2:36 ` [PATCH 3/5] pstore: support multiple pmsg instances Hiraku Toyooka
2015-11-05  2:36 ` [PATCH 4/5] ramoops: " Hiraku Toyooka
2015-11-05  2:36 ` [PATCH 5/5] selftests/pstore: add testcases for " Hiraku Toyooka

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).