With this support kernel can save function call chain log into a persistent ram buffer that can be decoded and dumped after reboot through pstore filesystem. It can be used to determine what function was last called before a reset or panic. We store the log in a binary format and then decode it at read time. p.s. Mostly the code comes from trace_persistent.c driver found in the Android git tree, written by Colin Cross <ccross@android.com> (according to sign-off history). I reworked the driver a little bit, and ported it to pstore. Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>tirimbino
parent
897dba0274
commit
060287b8c4
@ -0,0 +1,35 @@ |
||||
/*
|
||||
* Copyright 2012 Google, Inc. |
||||
* |
||||
* This software is licensed under the terms of the GNU General Public |
||||
* License version 2, as published by the Free Software Foundation, and |
||||
* may be copied, distributed, and modified under those terms. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
*/ |
||||
|
||||
#include <linux/kernel.h> |
||||
#include <linux/compiler.h> |
||||
#include <linux/irqflags.h> |
||||
#include <linux/percpu.h> |
||||
#include <linux/smp.h> |
||||
#include <linux/atomic.h> |
||||
#include <asm/barrier.h> |
||||
#include "internal.h" |
||||
|
||||
void notrace pstore_ftrace_call(unsigned long ip, unsigned long parent_ip) |
||||
{ |
||||
struct pstore_ftrace_record rec = {}; |
||||
|
||||
if (unlikely(oops_in_progress)) |
||||
return; |
||||
|
||||
rec.ip = ip; |
||||
rec.parent_ip = parent_ip; |
||||
pstore_ftrace_encode_cpu(&rec, raw_smp_processor_id()); |
||||
psinfo->write_buf(PSTORE_TYPE_FTRACE, 0, NULL, 0, (void *)&rec, |
||||
sizeof(rec), psinfo); |
||||
} |
@ -1,6 +1,49 @@ |
||||
#ifndef __PSTORE_INTERNAL_H__ |
||||
#define __PSTORE_INTERNAL_H__ |
||||
|
||||
#include <linux/pstore.h> |
||||
|
||||
#if NR_CPUS <= 2 && defined(CONFIG_ARM_THUMB) |
||||
#define PSTORE_CPU_IN_IP 0x1 |
||||
#elif NR_CPUS <= 4 && defined(CONFIG_ARM) |
||||
#define PSTORE_CPU_IN_IP 0x3 |
||||
#endif |
||||
|
||||
struct pstore_ftrace_record { |
||||
unsigned long ip; |
||||
unsigned long parent_ip; |
||||
#ifndef PSTORE_CPU_IN_IP |
||||
unsigned int cpu; |
||||
#endif |
||||
}; |
||||
|
||||
static inline void |
||||
pstore_ftrace_encode_cpu(struct pstore_ftrace_record *rec, unsigned int cpu) |
||||
{ |
||||
#ifndef PSTORE_CPU_IN_IP |
||||
rec->cpu = cpu; |
||||
#else |
||||
rec->ip |= cpu; |
||||
#endif |
||||
} |
||||
|
||||
static inline unsigned int |
||||
pstore_ftrace_decode_cpu(struct pstore_ftrace_record *rec) |
||||
{ |
||||
#ifndef PSTORE_CPU_IN_IP |
||||
return rec->cpu; |
||||
#else |
||||
return rec->ip & PSTORE_CPU_IN_IP; |
||||
#endif |
||||
} |
||||
|
||||
extern struct pstore_info *psinfo; |
||||
|
||||
extern void pstore_set_kmsg_bytes(int); |
||||
extern void pstore_get_records(int); |
||||
extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, |
||||
char *data, size_t size, |
||||
struct timespec time, struct pstore_info *psi); |
||||
extern int pstore_is_mounted(void); |
||||
|
||||
#endif |
||||
|
Loading…
Reference in new issue