From cac2eb7b580c95e3871a71276c99e2bd751a1624 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sat, 26 May 2012 06:20:20 -0700 Subject: pstore/ram: Give proper names to dump-related variables We're about to add support for other message types, so let's rename some variables to not be confused later. Signed-off-by: Anton Vorontsov Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 453030f9c5b..9b274b98bf3 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -68,9 +68,9 @@ struct ramoops_context { size_t record_size; int dump_oops; bool ecc; - unsigned int count; - unsigned int max_count; - unsigned int read_count; + unsigned int max_dump_cnt; + unsigned int dump_write_cnt; + unsigned int dump_read_cnt; struct pstore_info pstore; }; @@ -81,7 +81,7 @@ static int ramoops_pstore_open(struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; - cxt->read_count = 0; + cxt->dump_read_cnt = 0; return 0; } @@ -94,10 +94,10 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, struct ramoops_context *cxt = psi->data; struct persistent_ram_zone *prz; - if (cxt->read_count >= cxt->max_count) + if (cxt->dump_read_cnt >= cxt->max_dump_cnt) return -EINVAL; - *id = cxt->read_count++; + *id = cxt->dump_read_cnt++; prz = cxt->przs[*id]; /* Only supports dmesg output so far. */ @@ -141,7 +141,7 @@ static int ramoops_pstore_write(enum pstore_type_id type, size_t size, struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; - struct persistent_ram_zone *prz = cxt->przs[cxt->count]; + struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt]; size_t hlen; /* Currently ramoops is designed to only store dmesg dumps. */ @@ -172,7 +172,7 @@ static int ramoops_pstore_write(enum pstore_type_id type, size = prz->buffer_size - hlen; persistent_ram_write(prz, cxt->pstore.buf, size); - cxt->count = (cxt->count + 1) % cxt->max_count; + cxt->dump_write_cnt = (cxt->dump_write_cnt + 1) % cxt->max_dump_cnt; return 0; } @@ -182,7 +182,7 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, { struct ramoops_context *cxt = psi->data; - if (id >= cxt->max_count) + if (id >= cxt->max_dump_cnt) return -EINVAL; persistent_ram_free_old(cxt->przs[id]); @@ -213,7 +213,7 @@ static int __init ramoops_probe(struct platform_device *pdev) /* Only a single ramoops area allowed at a time, so fail extra * probes. */ - if (cxt->max_count) + if (cxt->max_dump_cnt) goto fail_out; if (!pdata->mem_size || !pdata->record_size) { @@ -239,22 +239,22 @@ static int __init ramoops_probe(struct platform_device *pdev) goto fail_out; } - cxt->max_count = pdata->mem_size / pdata->record_size; - cxt->count = 0; + cxt->max_dump_cnt = pdata->mem_size / pdata->record_size; + cxt->dump_read_cnt = 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->ecc = pdata->ecc; - cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_count, GFP_KERNEL); + cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt, 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++) { + for (i = 0; i < cxt->max_dump_cnt; i++) { size_t sz = cxt->record_size; phys_addr_t start = cxt->phys_addr + sz * i; @@ -293,7 +293,7 @@ static int __init ramoops_probe(struct platform_device *pdev) 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_dump_cnt, cxt->record_size, ramoops_ecc ? "on" : "off"); return 0; @@ -302,7 +302,7 @@ fail_buf: kfree(cxt->pstore.buf); fail_clear: cxt->pstore.bufsize = 0; - cxt->max_count = 0; + cxt->max_dump_cnt = 0; fail_przs: for (i = 0; cxt->przs[i]; i++) persistent_ram_free(cxt->przs[i]); @@ -321,7 +321,7 @@ static int __exit ramoops_remove(struct platform_device *pdev) iounmap(cxt->virt_addr); release_mem_region(cxt->phys_addr, cxt->size); - cxt->max_count = 0; + cxt->max_dump_cnt = 0; /* TODO(kees): When pstore supports unregistering, call it here. */ kfree(cxt->pstore.buf); -- cgit v1.2.3 From f4c5d2423c64266ba0daa9cc803d1d5ba469fe36 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sat, 26 May 2012 06:20:21 -0700 Subject: pstore/ram: Factor dmesg przs initialization out of probe() This will help make code clearer when we'll add support for other message types. This also makes probe() much shorter and understandable, plus makes mem/record size checking a bit easier. Implementation detail: we now use a paddr pointer, this will be used for allocating persistent ram zones for other message types. Signed-off-by: Anton Vorontsov Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 99 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 37 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 9b274b98bf3..6b767673849 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -202,13 +202,65 @@ static struct ramoops_context oops_cxt = { }, }; +static void ramoops_free_przs(struct ramoops_context *cxt) +{ + int i; + + if (!cxt->przs) + return; + + for (i = 0; cxt->przs[i]; i++) + persistent_ram_free(cxt->przs[i]); + kfree(cxt->przs); +} + +static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, + phys_addr_t *paddr, size_t dump_mem_sz) +{ + int err = -ENOMEM; + int i; + + if (!cxt->record_size) + return 0; + + cxt->max_dump_cnt = dump_mem_sz / cxt->record_size; + if (!cxt->max_dump_cnt) + return -ENOMEM; + + cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt, + GFP_KERNEL); + if (!cxt->przs) { + dev_err(dev, "failed to initialize a prz array for dumps\n"); + return -ENOMEM; + } + + for (i = 0; i < cxt->max_dump_cnt; i++) { + size_t sz = cxt->record_size; + + cxt->przs[i] = persistent_ram_new(*paddr, 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", + sz, (unsigned long long)*paddr, err); + goto fail_prz; + } + *paddr += sz; + } + + return 0; +fail_prz: + ramoops_free_przs(cxt); + return err; +} + 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; + size_t dump_mem_sz; + phys_addr_t paddr; int err = -EINVAL; - int i; /* Only a single ramoops area allowed at a time, so fail extra * probes. @@ -225,21 +277,6 @@ static int __init ramoops_probe(struct platform_device *pdev) 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_dump_cnt = pdata->mem_size / pdata->record_size; cxt->dump_read_cnt = 0; cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; @@ -247,24 +284,14 @@ static int __init ramoops_probe(struct platform_device *pdev) cxt->dump_oops = pdata->dump_oops; cxt->ecc = pdata->ecc; - cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt, 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_dump_cnt; i++) { - size_t sz = cxt->record_size; - phys_addr_t start = cxt->phys_addr + sz * i; + paddr = cxt->phys_addr; - 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", - sz, (unsigned long long)start, err); - goto fail_przs; - } + dump_mem_sz = cxt->size; + err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); + if (err) { + pr_err("memory size too small, minimum is %lu\n", + cxt->record_size); + goto fail_count; } cxt->pstore.data = cxt; @@ -303,10 +330,8 @@ fail_buf: fail_clear: cxt->pstore.bufsize = 0; cxt->max_dump_cnt = 0; -fail_przs: - for (i = 0; cxt->przs[i]; i++) - persistent_ram_free(cxt->przs[i]); - kfree(cxt->przs); +fail_count: + ramoops_free_przs(cxt); fail_out: return err; } -- cgit v1.2.3 From 755d66b48fe5a1f2a07802fcc8704e8b9e775e7d Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sat, 26 May 2012 06:20:22 -0700 Subject: pstore/ram: Factor ramoops_get_next_prz() out of ramoops_pstore_read() This will help make code clearer when we'll add support for other message types. The patch also changes return value from -EINVAL to 0 in case of end-of-records. The exact value doesn't matter for pstore (it should be just <= 0), but 0 feels more correct. Signed-off-by: Anton Vorontsov Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 6b767673849..d770d7266e9 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -85,6 +85,33 @@ static int ramoops_pstore_open(struct pstore_info *psi) return 0; } +static struct persistent_ram_zone * +ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, + u64 *id, + enum pstore_type_id *typep, enum pstore_type_id type, + bool update) +{ + struct persistent_ram_zone *prz; + int i = (*c)++; + + if (i >= max) + return NULL; + + prz = przs[i]; + + if (update) { + /* Update old/shadowed buffer. */ + persistent_ram_save_old(prz); + if (!persistent_ram_old_size(prz)) + return NULL; + } + + *typep = type; + *id = i; + + return prz; +} + static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, struct timespec *time, char **buf, @@ -94,20 +121,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, struct ramoops_context *cxt = psi->data; struct persistent_ram_zone *prz; - if (cxt->dump_read_cnt >= cxt->max_dump_cnt) - return -EINVAL; - - *id = cxt->dump_read_cnt++; - prz = cxt->przs[*id]; + prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt, + cxt->max_dump_cnt, id, type, + PSTORE_TYPE_DMESG, 1); + if (!prz) + return 0; - /* 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; - /* Update old/shadowed buffer. */ - persistent_ram_save_old(prz); size = persistent_ram_old_size(prz); *buf = kmalloc(size, GFP_KERNEL); if (*buf == NULL) -- cgit v1.2.3 From b5d38e9bf1b0c4db19e336b59b38dfb5d28bf1bf Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sat, 26 May 2012 06:20:23 -0700 Subject: pstore/ram: Add console messages handling The console log size is configurable via ramoops.console_size module option, and the log itself is available via /console-ramoops file. Signed-off-by: Anton Vorontsov Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 14 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index d770d7266e9..c7acf94ff47 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -41,6 +41,10 @@ module_param(record_size, ulong, 0400); MODULE_PARM_DESC(record_size, "size of each dump done on oops/panic"); +static ulong ramoops_console_size = MIN_MEM_SIZE; +module_param_named(console_size, ramoops_console_size, ulong, 0400); +MODULE_PARM_DESC(console_size, "size of kernel console log"); + static ulong mem_address; module_param(mem_address, ulong, 0400); MODULE_PARM_DESC(mem_address, @@ -63,14 +67,17 @@ MODULE_PARM_DESC(ramoops_ecc, struct ramoops_context { struct persistent_ram_zone **przs; + struct persistent_ram_zone *cprz; phys_addr_t phys_addr; unsigned long size; size_t record_size; + size_t console_size; int dump_oops; bool ecc; unsigned int max_dump_cnt; unsigned int dump_write_cnt; unsigned int dump_read_cnt; + unsigned int console_read_cnt; struct pstore_info pstore; }; @@ -82,6 +89,7 @@ static int ramoops_pstore_open(struct pstore_info *psi) struct ramoops_context *cxt = psi->data; cxt->dump_read_cnt = 0; + cxt->console_read_cnt = 0; return 0; } @@ -124,6 +132,9 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt, cxt->max_dump_cnt, id, type, PSTORE_TYPE_DMESG, 1); + if (!prz) + prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt, + 1, id, type, PSTORE_TYPE_CONSOLE, 0); if (!prz) return 0; @@ -167,7 +178,13 @@ static int ramoops_pstore_write(enum pstore_type_id type, struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt]; size_t hlen; - /* Currently ramoops is designed to only store dmesg dumps. */ + if (type == PSTORE_TYPE_CONSOLE) { + if (!cxt->cprz) + return -ENOMEM; + persistent_ram_write(cxt->cprz, cxt->pstore.buf, size); + return 0; + } + if (type != PSTORE_TYPE_DMESG) return -EINVAL; @@ -204,12 +221,23 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; + struct persistent_ram_zone *prz; - if (id >= cxt->max_dump_cnt) + switch (type) { + case PSTORE_TYPE_DMESG: + if (id >= cxt->max_dump_cnt) + return -EINVAL; + prz = cxt->przs[id]; + break; + case PSTORE_TYPE_CONSOLE: + prz = cxt->cprz; + break; + default: return -EINVAL; + } - persistent_ram_free_old(cxt->przs[id]); - persistent_ram_zap(cxt->przs[id]); + persistent_ram_free_old(prz); + persistent_ram_zap(prz); return 0; } @@ -276,6 +304,32 @@ fail_prz: 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) +{ + if (!sz) + return 0; + + if (*paddr + sz > *paddr + cxt->size) + return -ENOMEM; + + *prz = persistent_ram_new(*paddr, sz, cxt->ecc); + if (IS_ERR(*prz)) { + int err = PTR_ERR(*prz); + + dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", + sz, (unsigned long long)*paddr, err); + return err; + } + + persistent_ram_zap(*prz); + + *paddr += sz; + + return 0; +} + static int __init ramoops_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -291,34 +345,50 @@ static int __init ramoops_probe(struct platform_device *pdev) if (cxt->max_dump_cnt) goto fail_out; - if (!pdata->mem_size || !pdata->record_size) { - pr_err("The memory size and the record size must be " + if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size)) { + pr_err("The memory size and the record/console 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); + pdata->console_size = rounddown_pow_of_two(pdata->console_size); cxt->dump_read_cnt = 0; cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; cxt->record_size = pdata->record_size; + cxt->console_size = pdata->console_size; cxt->dump_oops = pdata->dump_oops; cxt->ecc = pdata->ecc; paddr = cxt->phys_addr; - dump_mem_sz = cxt->size; + dump_mem_sz = cxt->size - cxt->console_size; err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); - if (err) { + if (err) + goto fail_out; + + err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr, cxt->console_size); + if (err) + goto fail_init_cprz; + + if (!cxt->przs && !cxt->cprz) { pr_err("memory size too small, minimum is %lu\n", - cxt->record_size); - goto fail_count; + cxt->console_size + cxt->record_size); + goto fail_cnt; } cxt->pstore.data = cxt; - cxt->pstore.bufsize = cxt->przs[0]->buffer_size; + /* + * Console can handle any buffer size, so prefer dumps buffer + * size since usually it is smaller. + */ + if (cxt->przs) + cxt->pstore.bufsize = cxt->przs[0]->buffer_size; + else + cxt->pstore.bufsize = cxt->cprz->buffer_size; cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); spin_lock_init(&cxt->pstore.buf_lock); if (!cxt->pstore.buf) { @@ -341,9 +411,8 @@ 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), ecc: %s\n", + pr_info("attached 0x%lx@0x%llx, ecc: %s\n", cxt->size, (unsigned long long)cxt->phys_addr, - cxt->max_dump_cnt, cxt->record_size, ramoops_ecc ? "on" : "off"); return 0; @@ -353,7 +422,9 @@ fail_buf: fail_clear: cxt->pstore.bufsize = 0; cxt->max_dump_cnt = 0; -fail_count: +fail_cnt: + kfree(cxt->cprz); +fail_init_cprz: ramoops_free_przs(cxt); fail_out: return err; @@ -405,6 +476,7 @@ static int __init ramoops_init(void) dummy_data->mem_size = mem_size; dummy_data->mem_address = mem_address; dummy_data->record_size = record_size; + dummy_data->console_size = ramoops_console_size; dummy_data->dump_oops = dump_oops; dummy_data->ecc = ramoops_ecc; dummy = platform_create_bundle(&ramoops_driver, ramoops_probe, -- cgit v1.2.3 From 924d37118f9e18825294b2012a10c6245d6c25e1 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 18 Jun 2012 19:15:50 -0700 Subject: pstore/ram: Probe as early as possible Registering the platform driver before module_init allows us to log oopses that happen during device probing. This requires changing module_init to postcore_initcall, and switching from platform_driver_probe to platform_driver_register because the platform device is not registered when the platform driver is registered; and because we use driver_register, now can't use create_bundle() (since it will try to register the same driver once again), so we have to switch to platform_device_register_data(). Also, some __init -> __devinit changes were needed. Overall, the registration logic is now much clearer, since we have only one driver registration point, and just an optional dummy device, which is created from the module parameters. Suggested-by: Colin Cross Signed-off-by: Anton Vorontsov Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 63 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 31 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index c7acf94ff47..0b36e91978e 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -330,7 +330,7 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, return 0; } -static int __init ramoops_probe(struct platform_device *pdev) +static int __devinit ramoops_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ramoops_platform_data *pdata = pdev->dev.platform_data; @@ -452,6 +452,7 @@ static int __exit ramoops_remove(struct platform_device *pdev) } static struct platform_driver ramoops_driver = { + .probe = ramoops_probe, .remove = __exit_p(ramoops_remove), .driver = { .name = "ramoops", @@ -459,46 +460,46 @@ static struct platform_driver ramoops_driver = { }, }; -static int __init ramoops_init(void) +static void ramoops_register_dummy(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->console_size = ramoops_console_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)); - - if (IS_ERR(dummy)) - ret = PTR_ERR(dummy); - else - ret = 0; + if (!mem_size) + return; + + pr_info("using module parameters\n"); + + dummy_data = kzalloc(sizeof(*dummy_data), GFP_KERNEL); + if (!dummy_data) { + pr_info("could not allocate pdata\n"); + return; } - return ret; + dummy_data->mem_size = mem_size; + dummy_data->mem_address = mem_address; + dummy_data->record_size = record_size; + dummy_data->console_size = ramoops_console_size; + dummy_data->dump_oops = dump_oops; + dummy_data->ecc = ramoops_ecc; + + dummy = platform_device_register_data(NULL, "ramoops", -1, + dummy_data, sizeof(struct ramoops_platform_data)); + if (IS_ERR(dummy)) { + pr_info("could not create platform device: %ld\n", + PTR_ERR(dummy)); + } +} + +static int __init ramoops_init(void) +{ + ramoops_register_dummy(); + return platform_driver_register(&ramoops_driver); } +postcore_initcall(ramoops_init); 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"); -- cgit v1.2.3 From 90b58d96907e0a45555429c0d3a79c85cea4b9fc Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 18 Jun 2012 19:15:51 -0700 Subject: pstore/ram: Fix error handling during przs allocation persistent_ram_new() returns ERR_PTR() value on errors, so during freeing of the przs we should check for both NULL and IS_ERR() entries, otherwise bad things will happen. Signed-off-by: Anton Vorontsov Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 0b36e91978e..58b93fbd117 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -260,7 +260,7 @@ static void ramoops_free_przs(struct ramoops_context *cxt) if (!cxt->przs) return; - for (i = 0; cxt->przs[i]; i++) + for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++) persistent_ram_free(cxt->przs[i]); kfree(cxt->przs); } -- cgit v1.2.3 From 5ca5d4e61d0cac15f36160ab48425c6e43bf2e2f Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 9 Jul 2012 17:03:19 -0700 Subject: pstore/ram: Make ECC size configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is now pretty straightforward: instead of using bool, just pass an integer. For backwards compatibility ramoops.ecc=1 means 16 bytes ECC (using 1 byte for ECC isn't much of use anyway). Suggested-by: Arve Hjønnevåg Signed-off-by: Anton Vorontsov Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 58b93fbd117..b39aebbaeb8 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -63,7 +63,9 @@ MODULE_PARM_DESC(dump_oops, static int ramoops_ecc; module_param_named(ecc, ramoops_ecc, int, 0600); MODULE_PARM_DESC(ramoops_ecc, - "set to 1 to enable ECC support"); + "if non-zero, the option enables ECC support and specifies " + "ECC buffer size in bytes (1 is a special value, means 16 " + "bytes ECC)"); struct ramoops_context { struct persistent_ram_zone **przs; @@ -73,7 +75,7 @@ struct ramoops_context { size_t record_size; size_t console_size; int dump_oops; - bool ecc; + int ecc_size; unsigned int max_dump_cnt; unsigned int dump_write_cnt; unsigned int dump_read_cnt; @@ -288,7 +290,7 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, for (i = 0; i < cxt->max_dump_cnt; i++) { size_t sz = cxt->record_size; - cxt->przs[i] = persistent_ram_new(*paddr, sz, cxt->ecc); + cxt->przs[i] = persistent_ram_new(*paddr, sz, cxt->ecc_size); 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", @@ -314,7 +316,7 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, if (*paddr + sz > *paddr + cxt->size) return -ENOMEM; - *prz = persistent_ram_new(*paddr, sz, cxt->ecc); + *prz = persistent_ram_new(*paddr, sz, cxt->ecc_size); if (IS_ERR(*prz)) { int err = PTR_ERR(*prz); @@ -361,7 +363,7 @@ static int __devinit ramoops_probe(struct platform_device *pdev) cxt->record_size = pdata->record_size; cxt->console_size = pdata->console_size; cxt->dump_oops = pdata->dump_oops; - cxt->ecc = pdata->ecc; + cxt->ecc_size = pdata->ecc_size; paddr = cxt->phys_addr; @@ -411,9 +413,9 @@ static int __devinit ramoops_probe(struct platform_device *pdev) record_size = pdata->record_size; dump_oops = pdata->dump_oops; - pr_info("attached 0x%lx@0x%llx, ecc: %s\n", + pr_info("attached 0x%lx@0x%llx, ecc: %d\n", cxt->size, (unsigned long long)cxt->phys_addr, - ramoops_ecc ? "on" : "off"); + cxt->ecc_size); return 0; @@ -478,7 +480,11 @@ static void ramoops_register_dummy(void) dummy_data->record_size = record_size; dummy_data->console_size = ramoops_console_size; dummy_data->dump_oops = dump_oops; - dummy_data->ecc = ramoops_ecc; + /* + * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC + * (using 1 byte for ECC isn't much of use anyway). + */ + dummy_data->ecc_size = ramoops_ecc == 1 ? 16 : ramoops_ecc; dummy = platform_device_register_data(NULL, "ramoops", -1, dummy_data, sizeof(struct ramoops_platform_data)); -- cgit v1.2.3 From c2b7113261c5bb49031a15b833e59ea2d8ec4074 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 9 Jul 2012 17:10:43 -0700 Subject: pstore/ram: Convert to write_buf callback Don't use pstore.buf directly, instead convert the code to write_buf callback which passes a pointer to a buffer as an argument. Signed-off-by: Anton Vorontsov Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index b39aebbaeb8..74f4111bd0d 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -170,11 +170,12 @@ static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) 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) + +static int ramoops_pstore_write_buf(enum pstore_type_id type, + enum kmsg_dump_reason reason, + u64 *id, unsigned int part, + const char *buf, size_t size, + struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt]; @@ -183,7 +184,7 @@ static int ramoops_pstore_write(enum pstore_type_id type, if (type == PSTORE_TYPE_CONSOLE) { if (!cxt->cprz) return -ENOMEM; - persistent_ram_write(cxt->cprz, cxt->pstore.buf, size); + persistent_ram_write(cxt->cprz, buf, size); return 0; } @@ -212,7 +213,7 @@ static int ramoops_pstore_write(enum pstore_type_id type, 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); + persistent_ram_write(prz, buf, size); cxt->dump_write_cnt = (cxt->dump_write_cnt + 1) % cxt->max_dump_cnt; @@ -250,7 +251,7 @@ static struct ramoops_context oops_cxt = { .name = "ramoops", .open = ramoops_pstore_open, .read = ramoops_pstore_read, - .write = ramoops_pstore_write, + .write_buf = ramoops_pstore_write_buf, .erase = ramoops_pstore_erase, }, }; -- cgit v1.2.3 From a694d1b5916a486ce25fb5f2b39f2627f7afd5f3 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 9 Jul 2012 17:10:44 -0700 Subject: pstore/ram: Add ftrace messages handling The ftrace log size is configurable via ramoops.ftrace_size module option, and the log itself is available via /ftrace-ramoops file. Signed-off-by: Anton Vorontsov Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 74f4111bd0d..1dd108e0cc6 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -45,6 +45,10 @@ static ulong ramoops_console_size = MIN_MEM_SIZE; module_param_named(console_size, ramoops_console_size, ulong, 0400); MODULE_PARM_DESC(console_size, "size of kernel console log"); +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 mem_address; module_param(mem_address, ulong, 0400); MODULE_PARM_DESC(mem_address, @@ -70,16 +74,19 @@ MODULE_PARM_DESC(ramoops_ecc, struct ramoops_context { struct persistent_ram_zone **przs; struct persistent_ram_zone *cprz; + struct persistent_ram_zone *fprz; phys_addr_t phys_addr; unsigned long size; size_t record_size; size_t console_size; + size_t ftrace_size; int dump_oops; int ecc_size; unsigned int max_dump_cnt; unsigned int dump_write_cnt; unsigned int dump_read_cnt; unsigned int console_read_cnt; + unsigned int ftrace_read_cnt; struct pstore_info pstore; }; @@ -137,6 +144,9 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, if (!prz) prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt, 1, id, type, PSTORE_TYPE_CONSOLE, 0); + if (!prz) + prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt, + 1, id, type, PSTORE_TYPE_FTRACE, 0); if (!prz) return 0; @@ -186,6 +196,11 @@ static int ramoops_pstore_write_buf(enum pstore_type_id type, return -ENOMEM; persistent_ram_write(cxt->cprz, buf, size); return 0; + } else if (type == PSTORE_TYPE_FTRACE) { + if (!cxt->fprz) + return -ENOMEM; + persistent_ram_write(cxt->fprz, buf, size); + return 0; } if (type != PSTORE_TYPE_DMESG) @@ -235,6 +250,9 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, case PSTORE_TYPE_CONSOLE: prz = cxt->cprz; break; + case PSTORE_TYPE_FTRACE: + prz = cxt->fprz; + break; default: return -EINVAL; } @@ -348,7 +366,8 @@ static int __devinit ramoops_probe(struct platform_device *pdev) if (cxt->max_dump_cnt) goto fail_out; - if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size)) { + if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && + !pdata->ftrace_size)) { pr_err("The memory size and the record/console size must be " "non-zero\n"); goto fail_out; @@ -357,18 +376,20 @@ static int __devinit ramoops_probe(struct platform_device *pdev) pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); pdata->record_size = rounddown_pow_of_two(pdata->record_size); pdata->console_size = rounddown_pow_of_two(pdata->console_size); + pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); cxt->dump_read_cnt = 0; cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; cxt->record_size = pdata->record_size; cxt->console_size = pdata->console_size; + cxt->ftrace_size = pdata->ftrace_size; cxt->dump_oops = pdata->dump_oops; cxt->ecc_size = pdata->ecc_size; paddr = cxt->phys_addr; - dump_mem_sz = cxt->size - cxt->console_size; + dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size; err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); if (err) goto fail_out; @@ -377,9 +398,14 @@ static int __devinit ramoops_probe(struct platform_device *pdev) if (err) goto fail_init_cprz; - if (!cxt->przs && !cxt->cprz) { + err = ramoops_init_prz(dev, cxt, &cxt->fprz, &paddr, cxt->ftrace_size); + if (err) + goto fail_init_fprz; + + if (!cxt->przs && !cxt->cprz && !cxt->fprz) { pr_err("memory size too small, minimum is %lu\n", - cxt->console_size + cxt->record_size); + cxt->console_size + cxt->record_size + + cxt->ftrace_size); goto fail_cnt; } @@ -426,6 +452,8 @@ fail_clear: cxt->pstore.bufsize = 0; cxt->max_dump_cnt = 0; fail_cnt: + kfree(cxt->fprz); +fail_init_fprz: kfree(cxt->cprz); fail_init_cprz: ramoops_free_przs(cxt); @@ -480,6 +508,7 @@ static void ramoops_register_dummy(void) dummy_data->mem_address = mem_address; dummy_data->record_size = record_size; dummy_data->console_size = ramoops_console_size; + dummy_data->ftrace_size = ramoops_ftrace_size; dummy_data->dump_oops = dump_oops; /* * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC -- cgit v1.2.3 From cbe7cbf5a666ad9dfe2e0c276066131af73769ab Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 17 Jul 2012 12:11:12 -0700 Subject: pstore/ram: Make tracing log versioned Decoding the binary trace w/ a different kernel might be troublesome since we convert addresses to symbols. For kernels with minimal changes, the mappings would probably match, but it's not guaranteed at all. (But still we could convert the addresses by hand, since we do print raw addresses.) If we use modules, the symbols could be loaded at different addresses from the previously booted kernel, and so this would also fail, but there's nothing we can do about it. Also, the binary data format that pstore/ram is using in its ringbuffer may change between the kernels, so here we too must ensure that we're running the same kernel. So, there are two questions really: 1. How to compute the unique kernel tag; 2. Where to store it. In this patch we're using LINUX_VERSION_CODE, just as hibernation (suspend-to-disk) does. This way we are protecting from the kernel version mismatch, making sure that we're running the same kernel version and patch level. We could use CRC of a symbol table (as suggested by Tony Luck), but for now let's not be that strict. And as for storing, we are using a small trick here. Instead of allocating a dedicated buffer for the tag (i.e. another prz), or hacking ram_core routines to "reserve" some control data in the buffer, we are just encoding the tag into the buffer signature (and XOR'ing it with the actual signature value, so that buffers not needing a tag can just pass zero, which will result into the plain old PRZ signature). Suggested-by: Steven Rostedt Suggested-by: Tony Luck Suggested-by: Colin Cross Signed-off-by: Anton Vorontsov Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 1dd108e0cc6..0b311bc1891 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -309,7 +310,7 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, for (i = 0; i < cxt->max_dump_cnt; i++) { size_t sz = cxt->record_size; - cxt->przs[i] = persistent_ram_new(*paddr, sz, cxt->ecc_size); + cxt->przs[i] = persistent_ram_new(*paddr, sz, 0, cxt->ecc_size); 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", @@ -327,7 +328,7 @@ fail_prz: static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, struct persistent_ram_zone **prz, - phys_addr_t *paddr, size_t sz) + phys_addr_t *paddr, size_t sz, u32 sig) { if (!sz) return 0; @@ -335,7 +336,7 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, if (*paddr + sz > *paddr + cxt->size) return -ENOMEM; - *prz = persistent_ram_new(*paddr, sz, cxt->ecc_size); + *prz = persistent_ram_new(*paddr, sz, sig, cxt->ecc_size); if (IS_ERR(*prz)) { int err = PTR_ERR(*prz); @@ -394,11 +395,13 @@ static int __devinit ramoops_probe(struct platform_device *pdev) if (err) goto fail_out; - err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr, cxt->console_size); + err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr, + cxt->console_size, 0); if (err) goto fail_init_cprz; - err = ramoops_init_prz(dev, cxt, &cxt->fprz, &paddr, cxt->ftrace_size); + err = ramoops_init_prz(dev, cxt, &cxt->fprz, &paddr, cxt->ftrace_size, + LINUX_VERSION_CODE); if (err) goto fail_init_fprz; -- cgit v1.2.3 From a384f6411734e763daa4bae30e8ff170d7d4c3e2 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 19 Jul 2012 15:47:11 -0700 Subject: pstore/ram: Fix possible NULL dereference We can dereference 'cxt->cprz' if console and dump logging are disabled (which is unlikely, but still possible to do). This patch fixes the issue by changing the code so that we don't dereference przs at all, we can just calculate bufsize from console_size and record_size values. Plus, while at it, the patch improves the buffer size calculation. After Kay's printk rework, we know the optimal buffer size for console logging -- it is LOG_LINE_MAX (defined privately in printk.c). Previously, if only console logging was enabled, we would allocate unnecessary large buffer in pstore, while we only need LOG_LINE_MAX. (Pstore console logging is still capable of handling buffers > LOG_LINE_MAX, it will just do multiple calls to psinfo->write). Note that I don't export the constant, since we will do even a better thing soon: we will switch console logging to a new write_buf API, which will eliminate the need for the additional buffer; and so we won't need the constant. Reported-by: Dan Carpenter Signed-off-by: Anton Vorontsov Acked-by: Kees Cook --- fs/pstore/ram.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 0b311bc1891..bcd1bbd4259 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -414,13 +414,14 @@ static int __devinit ramoops_probe(struct platform_device *pdev) cxt->pstore.data = cxt; /* - * Console can handle any buffer size, so prefer dumps buffer - * size since usually it is smaller. + * 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 + * for ftrace, bufsize is irrelevant (if bufsize is 0, buf will be + * ZERO_SIZE_PTR). */ - if (cxt->przs) - cxt->pstore.bufsize = cxt->przs[0]->buffer_size; - else - cxt->pstore.bufsize = cxt->cprz->buffer_size; + if (cxt->console_size) + cxt->pstore.bufsize = 1024; /* LOG_LINE_MAX */ + cxt->pstore.bufsize = max(cxt->record_size, cxt->pstore.bufsize); cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); spin_lock_init(&cxt->pstore.buf_lock); if (!cxt->pstore.buf) { -- cgit v1.2.3 From 0427193b691edc81c846c7d0ebd2561cae8709d8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 3 Aug 2012 17:02:48 -0700 Subject: pstore/ram: Fix printk format warning Fix printk format warning (on i386) in pstore: fs/pstore/ram.c:409:3: warning: format '%lu' expects type 'long unsigned int', but argument 2 has type 'size_t' Signed-off-by: Randy Dunlap Acked-by: Kees Cook Signed-off-by: Anton Vorontsov --- fs/pstore/ram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index bcd1bbd4259..fba8c725692 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -406,7 +406,7 @@ static int __devinit ramoops_probe(struct platform_device *pdev) goto fail_init_fprz; if (!cxt->przs && !cxt->cprz && !cxt->fprz) { - pr_err("memory size too small, minimum is %lu\n", + pr_err("memory size too small, minimum is %zu\n", cxt->console_size + cxt->record_size + cxt->ftrace_size); goto fail_cnt; -- cgit v1.2.3 From 242030365eacb649161023a3a024373198c34d59 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 17 Jul 2012 19:49:37 -0700 Subject: pstore/ram: Mark ramoops_pstore_write_buf() as notrace write_buf() should be marked as notrace, otherwise it is prone to recursion. Though, yet the issue is never triggered in real life, because we run inside the function tracer, where ftrace does its own recurse protection. But it's still no good, plus soon we might switch to our own tracer ops, and then the issue will be fatal. So, let's fix it. Signed-off-by: Anton Vorontsov --- fs/pstore/ram.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index fba8c725692..91016049e55 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #define RAMOOPS_KERNMSG_HDR "====" @@ -181,12 +182,11 @@ static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) return len; } - -static int ramoops_pstore_write_buf(enum pstore_type_id type, - enum kmsg_dump_reason reason, - u64 *id, unsigned int part, - const char *buf, size_t size, - struct pstore_info *psi) +static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, + enum kmsg_dump_reason reason, + u64 *id, unsigned int part, + const char *buf, size_t size, + struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt]; -- cgit v1.2.3 From b4a871bce619dc5ca03cc6c78e1c467ceacb8e7e Mon Sep 17 00:00:00 2001 From: Jovi Zhang Date: Mon, 20 Aug 2012 14:58:26 +0800 Subject: pstore/ram: Add missing platform_device_unregister We need to unregister platform device when module exit, this commit fixes the issue. Signed-off-by: Jovi Zhang Acked-by: Kees Cook Signed-off-by: Anton Vorontsov --- fs/pstore/ram.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 91016049e55..1a4f6da58ea 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -538,6 +538,7 @@ postcore_initcall(ramoops_init); static void __exit ramoops_exit(void) { platform_driver_unregister(&ramoops_driver); + platform_device_unregister(dummy); kfree(dummy_data); } module_exit(ramoops_exit); -- cgit v1.2.3 From 53f21a8ea1d76a002103ce20abd168fe83b20ee7 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 17 Oct 2012 09:39:49 +0200 Subject: pstore/ram: Fixup section annotations The compiler complained about missing section annotations. Fix it. Signed-off-by: Hannes Reinecke Cc: Colin Cross Cc: Tony Luck Acked-by: Kees Cook Signed-off-by: Anton Vorontsov --- fs/pstore/ram.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 1a4f6da58ea..2b6ebbca352 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -287,8 +287,9 @@ static void ramoops_free_przs(struct ramoops_context *cxt) kfree(cxt->przs); } -static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, - phys_addr_t *paddr, size_t dump_mem_sz) +static int __devinit ramoops_init_przs(struct device *dev, + struct ramoops_context *cxt, + phys_addr_t *paddr, size_t dump_mem_sz) { int err = -ENOMEM; int i; @@ -326,9 +327,10 @@ fail_prz: 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) +static int __devinit ramoops_init_prz(struct device *dev, + struct ramoops_context *cxt, + struct persistent_ram_zone **prz, + phys_addr_t *paddr, size_t sz, u32 sig) { if (!sz) return 0; -- cgit v1.2.3 From b042e47491ba5f487601b5141a3f1d8582304170 Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Mon, 22 Oct 2012 11:19:28 +0200 Subject: pstore/ram: Fix undefined usage of rounddown_pow_of_two(0) record_size / console_size / ftrace_size can be 0 (this is how you disable the feature), but rounddown_pow_of_two(0) is undefined. As suggested by Kees Cook, use !is_power_of_2() as a condition to call rounddown_pow_of_two and avoid its undefined behavior on the value 0. This issue has been present since commit 1894a253 (ramoops: Move to fs/pstore/ram.c). Cc: stable@vger.kernel.org Signed-off-by: Maxime Bizon Signed-off-by: Florian Fainelli Acked-by: Kees Cook Signed-off-by: Anton Vorontsov --- fs/pstore/ram.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 2b6ebbca352..8741cea6253 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -376,10 +376,14 @@ static int __devinit ramoops_probe(struct platform_device *pdev) goto fail_out; } - pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); - pdata->record_size = rounddown_pow_of_two(pdata->record_size); - pdata->console_size = rounddown_pow_of_two(pdata->console_size); - pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); + if (!is_power_of_2(pdata->mem_size)) + pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); + if (!is_power_of_2(pdata->record_size)) + pdata->record_size = rounddown_pow_of_two(pdata->record_size); + if (!is_power_of_2(pdata->console_size)) + pdata->console_size = rounddown_pow_of_two(pdata->console_size); + if (!is_power_of_2(pdata->ftrace_size)) + pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); cxt->dump_read_cnt = 0; cxt->size = pdata->mem_size; -- cgit v1.2.3 From a9efd39cd547223597cfe7c53acec44c099b9264 Mon Sep 17 00:00:00 2001 From: Seiji Aguchi Date: Wed, 14 Nov 2012 20:27:28 +0000 Subject: efi_pstore: Add ctime to argument of erase callback [Issue] Currently, a variable name, which is used to identify each log entry, consists of type, id and ctime. But an erase callback does not use ctime. If efi_pstore supported just one log, type and id were enough. However, in case of supporting multiple logs, it doesn't work because it can't distinguish each entry without ctime at erasing time. As you can see below, efi_pstore can't differentiate first event from second one without ctime. a variable name of first event: dump-type0-1-12345678 a variable name of second event: dump-type0-1-23456789 type:0 id:1 ctime:12345678, 23456789 [Solution] This patch adds ctime to an argument of an erase callback. It works across reboots because ctime of pstore means the date that the record was originally stored. To do this, efi_pstore saves the ctime to variable name at writing time and passes it to pstore at reading time. Signed-off-by: Seiji Aguchi Acked-by: Mike Waychison Signed-off-by: Tony Luck --- fs/pstore/ram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 1a4f6da58ea..749693fcb75 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -237,7 +237,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, } static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, - struct pstore_info *psi) + struct timespec time, struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; struct persistent_ram_zone *prz; -- cgit v1.2.3 From 755d4fe46529018ae45bc7c86df682de45ace764 Mon Sep 17 00:00:00 2001 From: Seiji Aguchi Date: Mon, 26 Nov 2012 16:07:44 -0800 Subject: efi_pstore: Add a sequence counter to a variable name [Issue] Currently, a variable name, which identifies each entry, consists of type, id and ctime. But if multiple events happens in a short time, a second/third event may fail to log because efi_pstore can't distinguish each event with current variable name. [Solution] A reasonable way to identify all events precisely is introducing a sequence counter to the variable name. The sequence counter has already supported in a pstore layer with "oopscount". So, this patch adds it to a variable name. Also, it is passed to read/erase callbacks of platform drivers in accordance with the modification of the variable name. a variable name of first event: dump-type0-1-12345678 a variable name of second event: dump-type0-1-12345678 type:0 id:1 ctime:12345678 If multiple events happen in a short time, efi_pstore can't distinguish them because variable names are same among them. it can be distinguishable by adding a sequence counter as follows. a variable name of first event: dump-type0-1-1-12345678 a variable name of Second event: dump-type0-1-2-12345678 type:0 id:1 sequence counter: 1(first event), 2(second event) ctime:12345678 In case of a write callback executed in pstore_console_write(), "0" is added to an argument of the write callback because it just logs all kernel messages and doesn't need to care about multiple events. Signed-off-by: Seiji Aguchi Acked-by: Rafael J. Wysocki Acked-by: Mike Waychison Signed-off-by: Tony Luck --- fs/pstore/ram.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 749693fcb75..2bfa36e0ffe 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -132,9 +132,8 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, } static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, - struct timespec *time, - char **buf, - struct pstore_info *psi) + int *count, struct timespec *time, + char **buf, struct pstore_info *psi) { ssize_t size; struct ramoops_context *cxt = psi->data; @@ -236,7 +235,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, return 0; } -static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, +static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count, struct timespec time, struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; -- cgit v1.2.3 From c628937803c652132d21f383736375e2feee4bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Tue, 11 Dec 2012 17:49:24 -0800 Subject: pstore/ram: Fix bounds checks for mem_size, record_size, console_size and ftrace_size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bounds check in ramoops_init_prz was incorrect and ramoops_init_przs had no check. Additionally, ramoops_init_przs allows record_size to be 0, but ramoops_pstore_write_buf would always crash in this case. Signed-off-by: Arve Hjønnevåg Signed-off-by: Anton Vorontsov --- fs/pstore/ram.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 8741cea6253..dba70e53b72 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -189,7 +189,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; - struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt]; + struct persistent_ram_zone *prz; size_t hlen; if (type == PSTORE_TYPE_CONSOLE) { @@ -226,6 +226,11 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, if (part != 1) return -ENOSPC; + if (!cxt->przs) + return -ENOSPC; + + prz = cxt->przs[cxt->dump_write_cnt]; + hlen = ramoops_write_kmsg_hdr(prz); if (size + hlen > prz->buffer_size) size = prz->buffer_size - hlen; @@ -297,6 +302,11 @@ static int __devinit ramoops_init_przs(struct device *dev, if (!cxt->record_size) return 0; + if (*paddr + dump_mem_sz - cxt->phys_addr > cxt->size) { + dev_err(dev, "no room for dumps\n"); + return -ENOMEM; + } + cxt->max_dump_cnt = dump_mem_sz / cxt->record_size; if (!cxt->max_dump_cnt) return -ENOMEM; @@ -335,8 +345,12 @@ static int __devinit ramoops_init_prz(struct device *dev, if (!sz) return 0; - if (*paddr + sz > *paddr + cxt->size) + if (*paddr + sz - cxt->phys_addr > cxt->size) { + dev_err(dev, "no room for mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n", + sz, (unsigned long long)*paddr, + cxt->size, (unsigned long long)cxt->phys_addr); return -ENOMEM; + } *prz = persistent_ram_new(*paddr, sz, sig, cxt->ecc_size); if (IS_ERR(*prz)) { -- cgit v1.2.3 From f568f6ca811fe681ecfd11c4ce78b6aa488020c0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 21 Dec 2012 15:02:05 -0800 Subject: pstore: remove __dev* attributes. CONFIG_HOTPLUG is going away as an option. As a result, the __dev* markings need to be removed. This change removes the use of __devinit from the pstore filesystem. Based on patches originally written by Bill Pemberton, but redone by me in order to handle some of the coding style issues better, by hand. Cc: Bill Pemberton Cc: Anton Vorontsov Cc: Colin Cross Cc: Kees Cook Cc: Tony Luck Signed-off-by: Greg Kroah-Hartman --- fs/pstore/ram.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'fs/pstore/ram.c') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index f883e7e7430..7003e5266f2 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -291,9 +291,8 @@ static void ramoops_free_przs(struct ramoops_context *cxt) kfree(cxt->przs); } -static int __devinit ramoops_init_przs(struct device *dev, - struct ramoops_context *cxt, - phys_addr_t *paddr, size_t dump_mem_sz) +static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, + phys_addr_t *paddr, size_t dump_mem_sz) { int err = -ENOMEM; int i; @@ -336,10 +335,9 @@ fail_prz: return err; } -static int __devinit ramoops_init_prz(struct device *dev, - struct ramoops_context *cxt, - struct persistent_ram_zone **prz, - phys_addr_t *paddr, size_t sz, u32 sig) +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) { if (!sz) return 0; @@ -367,7 +365,7 @@ static int __devinit ramoops_init_prz(struct device *dev, return 0; } -static int __devinit ramoops_probe(struct platform_device *pdev) +static int ramoops_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ramoops_platform_data *pdata = pdev->dev.platform_data; -- cgit v1.2.3