The ftrace log size is configurable via ramoops.ftrace_size
module option, and the log itself is available via
<pstore-mount>/ftrace-ramoops file.

Signed-off-by: Anton Vorontsov <anton.voront...@linaro.org>
---
 Documentation/ramoops.txt  |   25 +++++++++++++++++++++++++
 fs/pstore/ram.c            |   37 +++++++++++++++++++++++++++++++++----
 include/linux/pstore_ram.h |    1 +
 3 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
index 59a74a8..197ad59 100644
--- a/Documentation/ramoops.txt
+++ b/Documentation/ramoops.txt
@@ -94,3 +94,28 @@ timestamp and a new line. The dump then continues with the 
actual data.
 The dump data can be read from the pstore filesystem. The format for these
 files is "dmesg-ramoops-N", where N is the record number in memory. To delete
 a stored record from RAM, simply unlink the respective pstore file.
+
+5. Persistent function tracing
+
+Persistent function tracing might be useful for debugging software or hardware
+related hangs. The functions call chain log is stored in a "ftrace-ramoops"
+file. Here is an example of usage:
+
+ # mount -t debugfs debugfs /sys/kernel/debug/
+ # cd /sys/kernel/debug/tracing
+ # echo function > current_tracer
+ # echo 1 > options/func_pstore
+ # reboot -f
+ [...]
+ # mount -t pstore pstore /mnt/
+ # tail /mnt/ftrace-ramoops
+ 0 ffffffff8101ea64  ffffffff8101bcda  native_apic_mem_read <- 
disconnect_bsp_APIC+0x6a/0xc0
+ 0 ffffffff8101ea44  ffffffff8101bcf6  native_apic_mem_write <- 
disconnect_bsp_APIC+0x86/0xc0
+ 0 ffffffff81020084  ffffffff8101a4b5  hpet_disable <- 
native_machine_shutdown+0x75/0x90
+ 0 ffffffff81005f94  ffffffff8101a4bb  iommu_shutdown_noop <- 
native_machine_shutdown+0x7b/0x90
+ 0 ffffffff8101a6a1  ffffffff8101a437  native_machine_emergency_restart <- 
native_machine_restart+0x37/0x40
+ 0 ffffffff811f9876  ffffffff8101a73a  acpi_reboot <- 
native_machine_emergency_restart+0xaa/0x1e0
+ 0 ffffffff8101a514  ffffffff8101a772  mach_reboot_fixups <- 
native_machine_emergency_restart+0xe2/0x1e0
+ 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
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 74f4111..1dd108e 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;
 };
 
@@ -138,6 +145,9 @@ static ssize_t ramoops_pstore_read(u64 *id, enum 
pstore_type_id *type,
                prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
                                           1, id, type, PSTORE_TYPE_CONSOLE, 0);
        if (!prz)
+               prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
+                                          1, id, type, PSTORE_TYPE_FTRACE, 0);
+       if (!prz)
                return 0;
 
        /* TODO(kees): Bogus time for the moment. */
@@ -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
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index dcf805f..af848e1 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -72,6 +72,7 @@ struct ramoops_platform_data {
        unsigned long   mem_address;
        unsigned long   record_size;
        unsigned long   console_size;
+       unsigned long   ftrace_size;
        int             dump_oops;
        int             ecc_size;
 };
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to