All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw@hitachi.com>
To: Anton Vorontsov <anton@enomsg.org>,
	Colin Cross <ccross@android.com>,
	Kees Cook <keescook@chromium.org>,
	Tony Luck <tony.luck@intel.com>
Cc: linux-kernel@vger.kernel.org,
	Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw@hitachi.com>,
	Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>,
	Jonathan Corbet <corbet@lwn.net>,
	Mark Salyzyn <salyzyn@android.com>,
	Seiji Aguchi <seiji.aguchi.tr@hitachi.com>
Subject: [PATCH v4 2nd 3/4] ramoops: support multiple pmsg instances
Date: Tue, 31 Jan 2017 10:58:34 +0900	[thread overview]
Message-ID: <1485827915-9620-4-git-send-email-nobuhiro.iwamatsu.kw@hitachi.com> (raw)
In-Reply-To: <1485827915-9620-1-git-send-email-nobuhiro.iwamatsu.kw@hitachi.com>

This enables ramoops to deal with multiple pmsg instances.
A User 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>
Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw@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>

V4:
  - Rebase.

V3:
  - Rebase.
  - Update documentiation of DT binding.
  - Update parsing function of ramoops_pmsg_size, add NULL-terminated.
  - Update module parameters for pmsg_size list.
---
 Documentation/admin-guide/ramoops.rst              |  22 ++
 .../bindings/reserved-memory/ramoops.txt           |   6 +-
 fs/pstore/ram.c                                    | 223 ++++++++++++++++++---
 include/linux/pstore_ram.h                         |   8 +-
 4 files changed, 231 insertions(+), 28 deletions(-)

diff --git a/Documentation/admin-guide/ramoops.rst b/Documentation/admin-guide/ramoops.rst
index 4efd7ce77565..611ee1d7d9ba 100644
--- a/Documentation/admin-guide/ramoops.rst
+++ b/Documentation/admin-guide/ramoops.rst
@@ -154,3 +154,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/Documentation/devicetree/bindings/reserved-memory/ramoops.txt b/Documentation/devicetree/bindings/reserved-memory/ramoops.txt
index 0eba562fe5c6..e270221b98df 100644
--- a/Documentation/devicetree/bindings/reserved-memory/ramoops.txt
+++ b/Documentation/devicetree/bindings/reserved-memory/ramoops.txt
@@ -39,7 +39,11 @@ Optional properties:
 - ftrace-size: size in bytes of log buffer reserved for function tracing and
   profiling (defaults to 0: disabled)
 
-- pmsg-size: size in bytes of log buffer reserved for userspace messages
+- pmsg-size: array of value that are used to size in bytes of log buffer
+  reserved for userspace messages.
+
+	pmsg-size = <0x10000 0x10000>;
+
   (defaults to 0: disabled)
 
 - unbuffered: if present, use unbuffered mappings to map the reserved region
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 72072e8123e3..50bc78aff6b8 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -53,8 +53,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 unsigned long long mem_address;
@@ -88,14 +88,14 @@ struct ramoops_context {
 	struct persistent_ram_zone **dprzs;	/* Oops dump zones */
 	struct persistent_ram_zone *cprz;	/* Console zone */
 	struct persistent_ram_zone **fprzs;	/* Ftrace zones */
-	struct persistent_ram_zone *mprz;	/* PMSG zone */
+	struct persistent_ram_zone **mprzs;	/* PMSG zone */
 	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;
 	u32 flags;
 	struct persistent_ram_ecc_info ecc_info;
@@ -275,9 +275,11 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
 		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
 					   1, id, type, PSTORE_TYPE_CONSOLE, 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->pstore.num_pmsg && !prz_ok(prz))
+		/* get pmsg prz */
+		prz = ramoops_get_next_prz(cxt->mprzs, &cxt->pmsg_read_cnt,
+					   cxt->pstore.num_pmsg, id, type,
+					   PSTORE_TYPE_PMSG, 0);
 
 	/* ftrace is last since it may want to dynamically allocate memory. */
 	if (!prz_ok(prz)) {
@@ -455,9 +457,9 @@ static int notrace ramoops_pstore_write_buf_user(enum pstore_type_id type,
 	if (type == PSTORE_TYPE_PMSG) {
 		struct ramoops_context *cxt = psi->data;
 
-		if (!cxt->mprz)
+		if (!cxt->mprzs)
 			return -ENOMEM;
-		return persistent_ram_write_user(cxt->mprz, buf, size);
+		return persistent_ram_write_user(cxt->mprzs[part], buf, size);
 	}
 
 	return -EINVAL;
@@ -484,7 +486,9 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
 		prz = cxt->fprzs[id];
 		break;
 	case PSTORE_TYPE_PMSG:
-		prz = cxt->mprz;
+		if (id >= cxt->pstore.num_pmsg)
+			return -EINVAL;
+		prz = cxt->mprzs[id];
 		break;
 	default:
 		return -EINVAL;
@@ -634,6 +638,40 @@ static int ramoops_init_przs(const char *name,
 	return err;
 }
 
+/* int function for pmsg przs */
+static int ramoops_init_mprzs(const char *name,
+			      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->pstore.num_pmsg, sizeof(*cxt->mprzs),
+			     GFP_KERNEL);
+	if (!cxt->mprzs)
+		return -ENOMEM;
+
+	for (i = 0; i < cxt->pstore.num_pmsg; i++) {
+		err = __ramoops_init_prz(name, dev, cxt, &cxt->mprzs[i], paddr,
+					 cxt->pmsg_size[i], 0, 0, true);
+		if (err)
+			goto fail_mprz;
+	}
+
+	return 0;
+fail_mprz:
+	ramoops_free_przs(cxt->mprzs);
+	return err;
+}
+
 static int ramoops_init_prz(const char *name,
 			    struct device *dev, struct ramoops_context *cxt,
 			    struct persistent_ram_zone **prz,
@@ -670,7 +708,8 @@ static int ramoops_parse_dt(struct platform_device *pdev,
 	struct device_node *of_node = pdev->dev.of_node;
 	struct resource *res;
 	u32 value;
-	int ret;
+	int ret, i;
+	unsigned int num_pmsg;
 
 	dev_dbg(&pdev->dev, "using Device Tree\n");
 
@@ -696,12 +735,71 @@ static int ramoops_parse_dt(struct platform_device *pdev,
 	parse_size("record-size", pdata->record_size);
 	parse_size("console-size", pdata->console_size);
 	parse_size("ftrace-size", pdata->ftrace_size);
-	parse_size("pmsg-size", pdata->pmsg_size);
 	parse_size("ecc-size", pdata->ecc_info.ecc_size);
 	parse_size("flags", pdata->flags);
 
 #undef parse_size
 
+	/* Parse pmesg size */
+	if (!of_find_property(of_node, "pmsg-size", &num_pmsg))
+		return 0; /* no data */
+
+	num_pmsg = num_pmsg / sizeof(u32);
+
+	pdata->pmsg_size =
+		devm_kzalloc(&pdev->dev, sizeof(size_t) * (num_pmsg + 1),
+			     GFP_KERNEL);
+	if (!pdata->pmsg_size)
+		return -ENOMEM;
+
+	for (i = 0; i < num_pmsg; i++) {
+		ret = of_property_read_u32_index(of_node, "pmsg-size",
+						 i, &value);
+		if (ret) {
+			dev_warn(&pdev->dev,
+				"%s: failed to read pmsg-size[%d]: %d\n",
+				 __func__, i, ret);
+			return -EINVAL;
+		}
+
+		/* CHECK INT_MAX */
+		if (value > INT_MAX) {
+			dev_err(&pdev->dev, "value %x > INT_MAX\n", value);
+			return -EOVERFLOW;
+		}
+		pdata->pmsg_size[i] = value;
+	}
+
+	return 0;
+}
+
+#define ADDR_STRING_SIZE	10 /* "0x00000000" */
+static int update_pmsg_size_mod_param(size_t *pmsg_size, int num)
+{
+	int i, len;
+
+	/* string size + commas count + NULL-terminated */
+	len = ADDR_STRING_SIZE * num + (num - 1) + 1;
+
+	/* using commandline or already allocation buffer.*/
+	if (ramoops_pmsg_size_str)
+		goto out;
+
+	ramoops_pmsg_size_str = kzalloc(len, GFP_KERNEL);
+	if (!ramoops_pmsg_size_str)
+		return -ENOMEM;
+
+	for (i = 0 ; i < num; i++) {
+		char str[ADDR_STRING_SIZE + 1];
+
+		memset(str, 0, sizeof(str));
+		if (i == num - 1)
+			snprintf(str, sizeof(str), "0x%x", pmsg_size[i]);
+		else
+			snprintf(str, sizeof(str), "0x%x,", pmsg_size[i]);
+		strcat(ramoops_pmsg_size_str, str);
+	}
+out:
 	return 0;
 }
 
@@ -713,6 +811,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;
 
 	if (dev_of_node(dev) && !pdata) {
 		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
@@ -755,8 +855,20 @@ 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;
@@ -764,20 +876,29 @@ 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->flags = pdata->flags;
 	cxt->ecc_info = pdata->ecc_info;
+	cxt->pstore.num_pmsg = num_pmsg;
 
-	paddr = cxt->phys_addr;
+	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_przs("dump", dev, cxt, &cxt->dprzs, &paddr,
 				dump_mem_sz, cxt->record_size,
 				&cxt->max_dump_cnt, 0, 0);
 	if (err)
-		goto fail_out;
+		goto fail_init_dprzs;
 
 	err = ramoops_init_prz("console", dev, cxt, &cxt->cprz, &paddr,
 			       cxt->console_size, 0);
@@ -795,10 +916,9 @@ static int ramoops_probe(struct platform_device *pdev)
 	if (err)
 		goto fail_init_fprz;
 
-	err = ramoops_init_prz("pmsg", dev, cxt, &cxt->mprz, &paddr,
-				cxt->pmsg_size, 0);
+	err = ramoops_init_mprzs("pmsg", dev, cxt, &paddr, pmsg_size_total);
 	if (err)
-		goto fail_init_mprz;
+		goto fail_init_mprzs;
 
 	cxt->pstore.data = cxt;
 	/*
@@ -841,8 +961,8 @@ 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;
+	update_pmsg_size_mod_param(cxt->pmsg_size, cxt->pstore.num_pmsg);
 
 	pr_info("attached 0x%lx@0x%llx, ecc: %d/%d\n",
 		cxt->size, (unsigned long long)cxt->phys_addr,
@@ -854,8 +974,8 @@ static int ramoops_probe(struct platform_device *pdev)
 	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:
 	cxt->max_ftrace_cnt = 0;
 	ramoops_free_przs(cxt->fprzs);
 fail_init_fprz:
@@ -863,6 +983,8 @@ static int ramoops_probe(struct platform_device *pdev)
 fail_init_cprz:
 	cxt->max_dump_cnt = 0;
 	ramoops_free_przs(cxt->dprzs);
+fail_init_dprzs:
+	kfree(cxt->pmsg_size);
 fail_out:
 	return err;
 }
@@ -875,8 +997,10 @@ static int ramoops_remove(struct platform_device *pdev)
 
 	kfree(cxt->pstore.buf);
 	cxt->pstore.bufsize = 0;
+	kfree(cxt->pmsg_size);
 
-	persistent_ram_free(cxt->mprz);
+	ramoops_free_przs(cxt->mprzs);
+	cxt->pstore.num_pmsg = 0;
 	persistent_ram_free(cxt->cprz);
 
 	/* Free ftrace PRZs */
@@ -903,6 +1027,43 @@ 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++;
+	}
+
+	/* Add NULL-terminated */
+	count++;
+
+	size_array = kcalloc(count, 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)
@@ -922,7 +1083,10 @@ 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;
 	dummy_data->flags = RAMOOPS_FLAG_FTRACE_PER_CPU;
 
@@ -937,7 +1101,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)
@@ -951,6 +1121,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 9395f06e8372..030fa45af2bf 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -84,6 +84,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.
  */
 
 #define RAMOOPS_FLAG_FTRACE_PER_CPU	BIT(0)
@@ -95,7 +101,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;
 	u32		flags;
 	struct persistent_ram_ecc_info ecc_info;
-- 
2.11.0

  parent reply	other threads:[~2017-01-31  1:59 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-31  1:58 [PATCH v4 2nd 0/4] pstore: ramoops: support multiple pmsg instances Nobuhiro Iwamatsu
2017-01-31  1:58 ` [PATCH v4 2nd 1/4] ramoops: Add __ramoops_init_prz() as generic function Nobuhiro Iwamatsu
2017-02-02 22:13   ` Mark Salyzyn
2017-02-07  8:51     ` 岩松信洋 / IWAMATSU,NOBUHIRO
2017-02-07 16:05       ` Mark Salyzyn
2017-01-31  1:58 ` [PATCH v4 2nd 2/4] pstore: support multiple pmsg instances Nobuhiro Iwamatsu
2017-02-01 20:28   ` Kees Cook
2017-02-07  8:44     ` 岩松信洋 / IWAMATSU,NOBUHIRO
2017-02-02 22:17   ` Mark Salyzyn
2017-02-07  8:47     ` 岩松信洋 / IWAMATSU,NOBUHIRO
2017-01-31  1:58 ` Nobuhiro Iwamatsu [this message]
2017-01-31  1:58 ` [PATCH v4 2nd 4/4] selftests/pstore: add testcases for " Nobuhiro Iwamatsu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1485827915-9620-4-git-send-email-nobuhiro.iwamatsu.kw@hitachi.com \
    --to=nobuhiro.iwamatsu.kw@hitachi.com \
    --cc=anton@enomsg.org \
    --cc=ccross@android.com \
    --cc=corbet@lwn.net \
    --cc=hiraku.toyooka.gu@hitachi.com \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=salyzyn@android.com \
    --cc=seiji.aguchi.tr@hitachi.com \
    --cc=tony.luck@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.