2015-11-05 02:36:48

by Hiraku Toyooka

[permalink] [raw]
Subject: [PATCH 0/5] pstore: ramoops: support multiple pmsg instances

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


2015-11-05 02:36:54

by Hiraku Toyooka

[permalink] [raw]
Subject: [PATCH 1/5] ramoops: use persistent_ram_free() instead of kfree() for freeing prz

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 <[email protected]>
Cc: Anton Vorontsov <[email protected]>
Cc: Colin Cross <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Mark Salyzyn <[email protected]>
Cc: Seiji Aguchi <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
---
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:

2015-11-05 02:38:28

by Hiraku Toyooka

[permalink] [raw]
Subject: [PATCH 2/5] ramoops: introduce generic init/free functions for prz

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 <[email protected]>
Cc: Anton Vorontsov <[email protected]>
Cc: Colin Cross <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Mark Salyzyn <[email protected]>
Cc: Seiji Aguchi <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
---
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;
}

2015-11-05 02:36:58

by Hiraku Toyooka

[permalink] [raw]
Subject: [PATCH 3/5] pstore: support multiple pmsg instances

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 <[email protected]>
Cc: Anton Vorontsov <[email protected]>
Cc: Colin Cross <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Mark Salyzyn <[email protected]>
Cc: Seiji Aguchi <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
---
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,

2015-11-05 02:37:01

by Hiraku Toyooka

[permalink] [raw]
Subject: [PATCH 4/5] ramoops: support multiple pmsg instances

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 <[email protected]>
Cc: Jonathan Corbet <[email protected]>
Cc: Anton Vorontsov <[email protected]>
Cc: Colin Cross <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Mark Salyzyn <[email protected]>
Cc: Seiji Aguchi <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
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;
};

2015-11-05 02:37:20

by Hiraku Toyooka

[permalink] [raw]
Subject: [PATCH 5/5] selftests/pstore: add testcases for multiple pmsg instances

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 <[email protected]>
Cc: Anton Vorontsov <[email protected]>
Cc: Colin Cross <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Mark Salyzyn <[email protected]>
Cc: Seiji Aguchi <[email protected]>
Cc: Shuah Khan <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
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