diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/pstore/Kconfig | 7 | ||||
-rw-r--r-- | fs/pstore/inode.c | 3 | ||||
-rw-r--r-- | fs/pstore/platform.c | 54 | ||||
-rw-r--r-- | fs/pstore/ram.c | 307 | ||||
-rw-r--r-- | fs/pstore/ram_core.c | 126 |
5 files changed, 303 insertions, 194 deletions
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 23ade2680a4a..d044de6ee308 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -12,6 +12,13 @@ config PSTORE If you don't have a platform persistent store driver, say N. +config PSTORE_CONSOLE + bool "Log kernel console messages" + depends on PSTORE + help + When the option is enabled, pstore will log all kernel + messages, even if no oops or panic happened. + config PSTORE_RAM tristate "Log panic/oops to a RAM buffer" depends on PSTORE diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 11a2aa2a56c4..45bff5441b04 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -212,6 +212,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, case PSTORE_TYPE_DMESG: sprintf(name, "dmesg-%s-%lld", psname, id); break; + case PSTORE_TYPE_CONSOLE: + sprintf(name, "console-%s", psname); + break; case PSTORE_TYPE_MCE: sprintf(name, "mce-%s-%lld", psname, id); break; diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 03ce7a9b81cc..6b3ff045fe6e 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -1,6 +1,7 @@ /* * Persistent Storage - platform driver interface parts. * + * Copyright (C) 2007-2008 Google, Inc. * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com> * * This program is free software; you can redistribute it and/or modify @@ -22,6 +23,7 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/kmsg_dump.h> +#include <linux/console.h> #include <linux/module.h> #include <linux/pstore.h> #include <linux/string.h> @@ -29,6 +31,7 @@ #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/hardirq.h> +#include <linux/jiffies.h> #include <linux/workqueue.h> #include "internal.h" @@ -38,7 +41,12 @@ * whether the system is actually still running well enough * to let someone see the entry */ -#define PSTORE_INTERVAL (60 * HZ) +static int pstore_update_ms = -1; +module_param_named(update_ms, pstore_update_ms, int, 0600); +MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content " + "(default is -1, which means runtime updates are disabled; " + "enabling this option is not safe, it may lead to further " + "corruption on Oopses)"); static int pstore_new_entry; @@ -146,6 +154,40 @@ static struct kmsg_dumper pstore_dumper = { .dump = pstore_dump, }; +#ifdef CONFIG_PSTORE_CONSOLE +static void pstore_console_write(struct console *con, const char *s, unsigned c) +{ + const char *e = s + c; + + while (s < e) { + unsigned long flags; + + if (c > psinfo->bufsize) + c = psinfo->bufsize; + spin_lock_irqsave(&psinfo->buf_lock, flags); + memcpy(psinfo->buf, s, c); + psinfo->write(PSTORE_TYPE_CONSOLE, 0, NULL, 0, c, psinfo); + spin_unlock_irqrestore(&psinfo->buf_lock, flags); + s += c; + c = e - s; + } +} + +static struct console pstore_console = { + .name = "pstore", + .write = pstore_console_write, + .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME, + .index = -1, +}; + +static void pstore_register_console(void) +{ + register_console(&pstore_console); +} +#else +static void pstore_register_console(void) {} +#endif + /* * platform specific persistent storage driver registers with * us here. If pstore is already mounted, call the platform @@ -183,9 +225,13 @@ int pstore_register(struct pstore_info *psi) pstore_get_records(0); kmsg_dump_register(&pstore_dumper); + pstore_register_console(); - pstore_timer.expires = jiffies + PSTORE_INTERVAL; - add_timer(&pstore_timer); + if (pstore_update_ms >= 0) { + pstore_timer.expires = jiffies + + msecs_to_jiffies(pstore_update_ms); + add_timer(&pstore_timer); + } return 0; } @@ -244,7 +290,7 @@ static void pstore_timefunc(unsigned long dummy) schedule_work(&pstore_work); } - mod_timer(&pstore_timer, jiffies + PSTORE_INTERVAL); + mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms)); } module_param(backend, charp, 0444); diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 453030f9c5bc..58b93fbd117e 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 count; - unsigned int max_count; - unsigned int read_count; + unsigned int max_dump_cnt; + unsigned int dump_write_cnt; + unsigned int dump_read_cnt; + unsigned int console_read_cnt; struct pstore_info pstore; }; @@ -81,10 +88,38 @@ static int ramoops_pstore_open(struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; - cxt->read_count = 0; + cxt->dump_read_cnt = 0; + cxt->console_read_cnt = 0; 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 +129,19 @@ 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) - return -EINVAL; + 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; - *id = cxt->read_count++; - prz = cxt->przs[*id]; - - /* Only supports dmesg output so far. */ - *type = PSTORE_TYPE_DMESG; /* TODO(kees): Bogus time for the moment. */ time->tv_sec = 0; time->tv_nsec = 0; - /* Update old/shadowed buffer. */ - persistent_ram_save_old(prz); size = persistent_ram_old_size(prz); *buf = kmalloc(size, GFP_KERNEL); if (*buf == NULL) @@ -141,10 +175,16 @@ 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. */ + 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; @@ -172,7 +212,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; } @@ -181,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_count) + 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; } @@ -202,73 +253,142 @@ static struct ramoops_context oops_cxt = { }, }; -static int __init ramoops_probe(struct platform_device *pdev) +static void ramoops_free_przs(struct ramoops_context *cxt) +{ + int i; + + if (!cxt->przs) + return; + + for (i = 0; !IS_ERR_OR_NULL(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 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 __devinit 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. */ - if (cxt->max_count) + 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); - /* Check for the minimum memory size */ - if (pdata->mem_size < MIN_MEM_SIZE && - pdata->record_size < MIN_MEM_SIZE) { - pr_err("memory size too small, minimum is %lu\n", - MIN_MEM_SIZE); - goto fail_out; - } - - if (pdata->mem_size < pdata->record_size) { - pr_err("The memory size must be larger than the " - "records size\n"); - goto fail_out; - } - - cxt->max_count = pdata->mem_size / pdata->record_size; - cxt->count = 0; + cxt->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; - cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_count, GFP_KERNEL); - if (!cxt->przs) { - err = -ENOMEM; - dev_err(dev, "failed to initialize a prz array\n"); + paddr = cxt->phys_addr; + + dump_mem_sz = cxt->size - cxt->console_size; + err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); + if (err) goto fail_out; - } - for (i = 0; i < cxt->max_count; i++) { - size_t sz = cxt->record_size; - phys_addr_t start = cxt->phys_addr + sz * i; + err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr, cxt->console_size); + if (err) + goto fail_init_cprz; - 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; - } + if (!cxt->przs && !cxt->cprz) { + pr_err("memory size too small, minimum is %lu\n", + 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) { @@ -291,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_count, cxt->record_size, ramoops_ecc ? "on" : "off"); return 0; @@ -302,11 +421,11 @@ fail_buf: kfree(cxt->pstore.buf); fail_clear: cxt->pstore.bufsize = 0; - cxt->max_count = 0; -fail_przs: - for (i = 0; cxt->przs[i]; i++) - persistent_ram_free(cxt->przs[i]); - kfree(cxt->przs); + cxt->max_dump_cnt = 0; +fail_cnt: + kfree(cxt->cprz); +fail_init_cprz: + ramoops_free_przs(cxt); fail_out: return err; } @@ -321,7 +440,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); @@ -333,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", @@ -340,45 +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->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"); diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index c5fbdbbf81ac..a5a7b13d358c 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -35,8 +35,6 @@ struct persistent_ram_buffer { #define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ -static __initdata LIST_HEAD(persistent_ram_list); - static inline size_t buffer_size(struct persistent_ram_zone *prz) { return atomic_read(&prz->buffer->size); @@ -173,12 +171,12 @@ static void persistent_ram_ecc_old(struct persistent_ram_zone *prz) } } -static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, - size_t buffer_size) +static int persistent_ram_init_ecc(struct persistent_ram_zone *prz) { int numerr; struct persistent_ram_buffer *buffer = prz->buffer; int ecc_blocks; + size_t ecc_total; if (!prz->ecc) return 0; @@ -189,14 +187,14 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, prz->ecc_poly = 0x11d; ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size); - prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size; - - if (prz->buffer_size > buffer_size) { - pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n", - buffer_size, prz->buffer_size); + ecc_total = (ecc_blocks + 1) * prz->ecc_size; + if (ecc_total >= prz->buffer_size) { + pr_err("%s: invalid ecc_size %u (total %zu, buffer size %zu)\n", + __func__, prz->ecc_size, ecc_total, prz->buffer_size); return -EINVAL; } + prz->buffer_size -= ecc_total; prz->par_buffer = buffer->data + prz->buffer_size; prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size; @@ -392,13 +390,14 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, return 0; } -static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool ecc) +static int __devinit persistent_ram_post_init(struct persistent_ram_zone *prz, + bool ecc) { int ret; prz->ecc = ecc; - ret = persistent_ram_init_ecc(prz, prz->buffer_size); + ret = persistent_ram_init_ecc(prz); if (ret) return ret; @@ -409,14 +408,14 @@ static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool " size %zu, start %zu\n", buffer_size(prz), buffer_start(prz)); else { - pr_info("persistent_ram: found existing buffer," + pr_debug("persistent_ram: found existing buffer," " size %zu, start %zu\n", buffer_size(prz), buffer_start(prz)); persistent_ram_save_old(prz); return 0; } } else { - pr_info("persistent_ram: no valid data in buffer" + pr_debug("persistent_ram: no valid data in buffer" " (sig = 0x%08x)\n", prz->buffer->sig); } @@ -428,19 +427,25 @@ static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool void persistent_ram_free(struct persistent_ram_zone *prz) { - if (pfn_valid(prz->paddr >> PAGE_SHIFT)) { - vunmap(prz->vaddr); - } else { - iounmap(prz->vaddr); - release_mem_region(prz->paddr, prz->size); + if (!prz) + return; + + if (prz->vaddr) { + if (pfn_valid(prz->paddr >> PAGE_SHIFT)) { + vunmap(prz->vaddr); + } else { + iounmap(prz->vaddr); + release_mem_region(prz->paddr, prz->size); + } + prz->vaddr = NULL; } persistent_ram_free_old(prz); kfree(prz); } -struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start, - size_t size, - bool ecc) +struct persistent_ram_zone * __devinit persistent_ram_new(phys_addr_t start, + size_t size, + bool ecc) { struct persistent_ram_zone *prz; int ret = -ENOMEM; @@ -455,85 +460,12 @@ struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start, if (ret) goto err; - persistent_ram_post_init(prz, ecc); - - return prz; -err: - kfree(prz); - return ERR_PTR(ret); -} - -#ifndef MODULE -static int __init persistent_ram_buffer_init(const char *name, - struct persistent_ram_zone *prz) -{ - int i; - struct persistent_ram *ram; - struct persistent_ram_descriptor *desc; - phys_addr_t start; - - list_for_each_entry(ram, &persistent_ram_list, node) { - start = ram->start; - for (i = 0; i < ram->num_descs; i++) { - desc = &ram->descs[i]; - if (!strcmp(desc->name, name)) - return persistent_ram_buffer_map(start, - desc->size, prz); - start += desc->size; - } - } - - return -EINVAL; -} - -static __init -struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) -{ - struct persistent_ram_zone *prz; - int ret = -ENOMEM; - - prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL); - if (!prz) { - pr_err("persistent_ram: failed to allocate persistent ram zone\n"); - goto err; - } - - ret = persistent_ram_buffer_init(dev_name(dev), prz); - if (ret) { - pr_err("persistent_ram: failed to initialize buffer\n"); + ret = persistent_ram_post_init(prz, ecc); + if (ret) goto err; - } - - persistent_ram_post_init(prz, ecc); return prz; err: - kfree(prz); + persistent_ram_free(prz); return ERR_PTR(ret); } - -struct persistent_ram_zone * __init -persistent_ram_init_ringbuffer(struct device *dev, bool ecc) -{ - return __persistent_ram_init(dev, ecc); -} - -int __init persistent_ram_early_init(struct persistent_ram *ram) -{ - int ret; - - ret = memblock_reserve(ram->start, ram->size); - if (ret) { - pr_err("Failed to reserve persistent memory from %08lx-%08lx\n", - (long)ram->start, (long)(ram->start + ram->size - 1)); - return ret; - } - - list_add_tail(&ram->node, &persistent_ram_list); - - pr_info("Initialized persistent memory from %08lx-%08lx\n", - (long)ram->start, (long)(ram->start + ram->size - 1)); - - return 0; -} -#endif |