You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'pstore-v4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull pstore updates from Kees Cook: "Improvements and fixes to pstore subsystem: - add additional checks for bad platform data - remove bounce buffer in console writer - protect read/unlink race with a mutex - correctly give up during dump locking failures - increase ftrace bandwidth by splitting ftrace buffers per CPU" * tag 'pstore-v4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: ramoops: add pdata NULL check to ramoops_probe pstore: Convert console write to use ->write_buf pstore: Protect unlink with read_mutex pstore: Use global ftrace filters for function trace filtering ftrace: Provide API to use global filtering for ftrace ops pstore: Clarify context field przs as dprzs pstore: improve error report for failed setup pstore: Merge per-CPU ftrace records into one pstore: Add ftrace timestamp counter ramoops: Split ftrace buffer space into per-CPU zones pstore: Make ramoops_init_przs generic for other prz arrays pstore: Allow prz to control need for locking pstore: Warn on PSTORE_TYPE_PMSG using deprecated function pstore: Make spinlock per zone instead of global pstore: Actually give up during locking failure
This commit is contained in:
@@ -46,3 +46,6 @@ Optional properties:
|
||||
(defaults to buffered mappings)
|
||||
|
||||
- no-dump-oops: if present, only dump panics (defaults to panics and oops)
|
||||
|
||||
- flags: if present, pass ramoops behavioral flags (defaults to 0,
|
||||
see include/linux/pstore_ram.h RAMOOPS_FLAG_* for flag values).
|
||||
|
||||
+9
-2
@@ -27,6 +27,9 @@
|
||||
#include <asm/barrier.h>
|
||||
#include "internal.h"
|
||||
|
||||
/* This doesn't need to be atomic: speed is chosen over correctness here. */
|
||||
static u64 pstore_ftrace_stamp;
|
||||
|
||||
static void notrace pstore_ftrace_call(unsigned long ip,
|
||||
unsigned long parent_ip,
|
||||
struct ftrace_ops *op,
|
||||
@@ -42,6 +45,7 @@ static void notrace pstore_ftrace_call(unsigned long ip,
|
||||
|
||||
rec.ip = ip;
|
||||
rec.parent_ip = parent_ip;
|
||||
pstore_ftrace_write_timestamp(&rec, pstore_ftrace_stamp++);
|
||||
pstore_ftrace_encode_cpu(&rec, raw_smp_processor_id());
|
||||
psinfo->write_buf(PSTORE_TYPE_FTRACE, 0, NULL, 0, (void *)&rec,
|
||||
0, sizeof(rec), psinfo);
|
||||
@@ -71,10 +75,13 @@ static ssize_t pstore_ftrace_knob_write(struct file *f, const char __user *buf,
|
||||
if (!on ^ pstore_ftrace_enabled)
|
||||
goto out;
|
||||
|
||||
if (on)
|
||||
if (on) {
|
||||
ftrace_ops_set_global_filter(&pstore_ftrace_ops);
|
||||
ret = register_ftrace_function(&pstore_ftrace_ops);
|
||||
else
|
||||
} else {
|
||||
ret = unregister_ftrace_function(&pstore_ftrace_ops);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
pr_err("%s: unable to %sregister ftrace ops: %zd\n",
|
||||
__func__, on ? "" : "un", ret);
|
||||
|
||||
+10
-5
@@ -107,9 +107,11 @@ static int pstore_ftrace_seq_show(struct seq_file *s, void *v)
|
||||
struct pstore_ftrace_seq_data *data = v;
|
||||
struct pstore_ftrace_record *rec = (void *)(ps->data + data->off);
|
||||
|
||||
seq_printf(s, "%d %08lx %08lx %pf <- %pF\n",
|
||||
pstore_ftrace_decode_cpu(rec), rec->ip, rec->parent_ip,
|
||||
(void *)rec->ip, (void *)rec->parent_ip);
|
||||
seq_printf(s, "CPU:%d ts:%llu %08lx %08lx %pf <- %pF\n",
|
||||
pstore_ftrace_decode_cpu(rec),
|
||||
pstore_ftrace_read_timestamp(rec),
|
||||
rec->ip, rec->parent_ip, (void *)rec->ip,
|
||||
(void *)rec->parent_ip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -197,11 +199,14 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (p->psi->erase)
|
||||
if (p->psi->erase) {
|
||||
mutex_lock(&p->psi->read_mutex);
|
||||
p->psi->erase(p->type, p->id, p->count,
|
||||
d_inode(dentry)->i_ctime, p->psi);
|
||||
else
|
||||
mutex_unlock(&p->psi->read_mutex);
|
||||
} else {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return simple_unlink(dir, dentry);
|
||||
}
|
||||
|
||||
@@ -5,40 +5,6 @@
|
||||
#include <linux/time.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
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PSTORE_FTRACE
|
||||
extern void pstore_register_ftrace(void);
|
||||
extern void pstore_unregister_ftrace(void);
|
||||
|
||||
@@ -493,6 +493,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
|
||||
if (!is_locked) {
|
||||
pr_err("pstore dump routine blocked in %s path, may corrupt error record\n"
|
||||
, in_nmi() ? "NMI" : why);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
spin_lock_irqsave(&psinfo->buf_lock, flags);
|
||||
@@ -584,8 +585,8 @@ static void pstore_console_write(struct console *con, const char *s, unsigned c)
|
||||
} else {
|
||||
spin_lock_irqsave(&psinfo->buf_lock, flags);
|
||||
}
|
||||
memcpy(psinfo->buf, s, c);
|
||||
psinfo->write(PSTORE_TYPE_CONSOLE, 0, &id, 0, 0, 0, c, psinfo);
|
||||
psinfo->write_buf(PSTORE_TYPE_CONSOLE, 0, &id, 0,
|
||||
s, 0, c, psinfo);
|
||||
spin_unlock_irqrestore(&psinfo->buf_lock, flags);
|
||||
s += c;
|
||||
c = e - s;
|
||||
|
||||
+256
-73
File diff suppressed because it is too large
Load Diff
+16
-11
@@ -48,16 +48,15 @@ static inline size_t buffer_start(struct persistent_ram_zone *prz)
|
||||
return atomic_read(&prz->buffer->start);
|
||||
}
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(buffer_lock);
|
||||
|
||||
/* increase and wrap the start pointer, returning the old value */
|
||||
static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
|
||||
{
|
||||
int old;
|
||||
int new;
|
||||
unsigned long flags;
|
||||
unsigned long flags = 0;
|
||||
|
||||
raw_spin_lock_irqsave(&buffer_lock, flags);
|
||||
if (!(prz->flags & PRZ_FLAG_NO_LOCK))
|
||||
raw_spin_lock_irqsave(&prz->buffer_lock, flags);
|
||||
|
||||
old = atomic_read(&prz->buffer->start);
|
||||
new = old + a;
|
||||
@@ -65,7 +64,8 @@ static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
|
||||
new -= prz->buffer_size;
|
||||
atomic_set(&prz->buffer->start, new);
|
||||
|
||||
raw_spin_unlock_irqrestore(&buffer_lock, flags);
|
||||
if (!(prz->flags & PRZ_FLAG_NO_LOCK))
|
||||
raw_spin_unlock_irqrestore(&prz->buffer_lock, flags);
|
||||
|
||||
return old;
|
||||
}
|
||||
@@ -75,9 +75,10 @@ static void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
|
||||
{
|
||||
size_t old;
|
||||
size_t new;
|
||||
unsigned long flags;
|
||||
unsigned long flags = 0;
|
||||
|
||||
raw_spin_lock_irqsave(&buffer_lock, flags);
|
||||
if (!(prz->flags & PRZ_FLAG_NO_LOCK))
|
||||
raw_spin_lock_irqsave(&prz->buffer_lock, flags);
|
||||
|
||||
old = atomic_read(&prz->buffer->size);
|
||||
if (old == prz->buffer_size)
|
||||
@@ -89,7 +90,8 @@ static void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
|
||||
atomic_set(&prz->buffer->size, new);
|
||||
|
||||
exit:
|
||||
raw_spin_unlock_irqrestore(&buffer_lock, flags);
|
||||
if (!(prz->flags & PRZ_FLAG_NO_LOCK))
|
||||
raw_spin_unlock_irqrestore(&prz->buffer_lock, flags);
|
||||
}
|
||||
|
||||
static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
|
||||
@@ -465,7 +467,8 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
|
||||
}
|
||||
|
||||
static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
|
||||
struct persistent_ram_ecc_info *ecc_info)
|
||||
struct persistent_ram_ecc_info *ecc_info,
|
||||
unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -493,6 +496,8 @@ static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
|
||||
|
||||
prz->buffer->sig = sig;
|
||||
persistent_ram_zap(prz);
|
||||
prz->buffer_lock = __RAW_SPIN_LOCK_UNLOCKED(buffer_lock);
|
||||
prz->flags = flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -517,7 +522,7 @@ void persistent_ram_free(struct persistent_ram_zone *prz)
|
||||
|
||||
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
|
||||
u32 sig, struct persistent_ram_ecc_info *ecc_info,
|
||||
unsigned int memtype)
|
||||
unsigned int memtype, u32 flags)
|
||||
{
|
||||
struct persistent_ram_zone *prz;
|
||||
int ret = -ENOMEM;
|
||||
@@ -532,7 +537,7 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = persistent_ram_post_init(prz, sig, ecc_info);
|
||||
ret = persistent_ram_post_init(prz, sig, ecc_info, flags);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
||||
@@ -398,6 +398,7 @@ int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
|
||||
void ftrace_set_global_filter(unsigned char *buf, int len, int reset);
|
||||
void ftrace_set_global_notrace(unsigned char *buf, int len, int reset);
|
||||
void ftrace_free_filter(struct ftrace_ops *ops);
|
||||
void ftrace_ops_set_global_filter(struct ftrace_ops *ops);
|
||||
|
||||
int register_ftrace_command(struct ftrace_func_command *cmd);
|
||||
int unregister_ftrace_command(struct ftrace_func_command *cmd);
|
||||
@@ -645,6 +646,7 @@ static inline unsigned long ftrace_location(unsigned long ip)
|
||||
#define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; })
|
||||
#define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; })
|
||||
#define ftrace_free_filter(ops) do { } while (0)
|
||||
#define ftrace_ops_set_global_filter(ops) do { } while (0)
|
||||
|
||||
static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos) { return -ENODEV; }
|
||||
|
||||
@@ -89,4 +89,80 @@ extern int pstore_register(struct pstore_info *);
|
||||
extern void pstore_unregister(struct pstore_info *);
|
||||
extern bool pstore_cannot_block_path(enum kmsg_dump_reason reason);
|
||||
|
||||
struct pstore_ftrace_record {
|
||||
unsigned long ip;
|
||||
unsigned long parent_ip;
|
||||
u64 ts;
|
||||
};
|
||||
|
||||
/*
|
||||
* ftrace related stuff: Both backends and frontends need these so expose
|
||||
* them here.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
#define TS_CPU_SHIFT 8
|
||||
#define TS_CPU_MASK (BIT(TS_CPU_SHIFT) - 1)
|
||||
|
||||
/*
|
||||
* If CPU number can be stored in IP, store it there, otherwise store it in
|
||||
* the time stamp. This means more timestamp resolution is available when
|
||||
* the CPU can be stored in the IP.
|
||||
*/
|
||||
#ifdef PSTORE_CPU_IN_IP
|
||||
static inline void
|
||||
pstore_ftrace_encode_cpu(struct pstore_ftrace_record *rec, unsigned int cpu)
|
||||
{
|
||||
rec->ip |= cpu;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
pstore_ftrace_decode_cpu(struct pstore_ftrace_record *rec)
|
||||
{
|
||||
return rec->ip & PSTORE_CPU_IN_IP;
|
||||
}
|
||||
|
||||
static inline u64
|
||||
pstore_ftrace_read_timestamp(struct pstore_ftrace_record *rec)
|
||||
{
|
||||
return rec->ts;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pstore_ftrace_write_timestamp(struct pstore_ftrace_record *rec, u64 val)
|
||||
{
|
||||
rec->ts = val;
|
||||
}
|
||||
#else
|
||||
static inline void
|
||||
pstore_ftrace_encode_cpu(struct pstore_ftrace_record *rec, unsigned int cpu)
|
||||
{
|
||||
rec->ts &= ~(TS_CPU_MASK);
|
||||
rec->ts |= cpu;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
pstore_ftrace_decode_cpu(struct pstore_ftrace_record *rec)
|
||||
{
|
||||
return rec->ts & TS_CPU_MASK;
|
||||
}
|
||||
|
||||
static inline u64
|
||||
pstore_ftrace_read_timestamp(struct pstore_ftrace_record *rec)
|
||||
{
|
||||
return rec->ts >> TS_CPU_SHIFT;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pstore_ftrace_write_timestamp(struct pstore_ftrace_record *rec, u64 val)
|
||||
{
|
||||
rec->ts = (rec->ts & TS_CPU_MASK) | (val << TS_CPU_SHIFT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_LINUX_PSTORE_H*/
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* Choose whether access to the RAM zone requires locking or not. If a zone
|
||||
* can be written to from different CPUs like with ftrace for example, then
|
||||
* PRZ_FLAG_NO_LOCK is used. For all other cases, locking is required.
|
||||
*/
|
||||
#define PRZ_FLAG_NO_LOCK BIT(0)
|
||||
|
||||
struct persistent_ram_buffer;
|
||||
struct rs_control;
|
||||
|
||||
@@ -40,6 +47,8 @@ struct persistent_ram_zone {
|
||||
void *vaddr;
|
||||
struct persistent_ram_buffer *buffer;
|
||||
size_t buffer_size;
|
||||
u32 flags;
|
||||
raw_spinlock_t buffer_lock;
|
||||
|
||||
/* ECC correction */
|
||||
char *par_buffer;
|
||||
@@ -55,7 +64,7 @@ struct persistent_ram_zone {
|
||||
|
||||
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
|
||||
u32 sig, struct persistent_ram_ecc_info *ecc_info,
|
||||
unsigned int memtype);
|
||||
unsigned int memtype, u32 flags);
|
||||
void persistent_ram_free(struct persistent_ram_zone *prz);
|
||||
void persistent_ram_zap(struct persistent_ram_zone *prz);
|
||||
|
||||
@@ -77,6 +86,8 @@ ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
|
||||
* @mem_address physical memory address to contain ramoops
|
||||
*/
|
||||
|
||||
#define RAMOOPS_FLAG_FTRACE_PER_CPU BIT(0)
|
||||
|
||||
struct ramoops_platform_data {
|
||||
unsigned long mem_size;
|
||||
phys_addr_t mem_address;
|
||||
@@ -86,6 +97,7 @@ struct ramoops_platform_data {
|
||||
unsigned long ftrace_size;
|
||||
unsigned long pmsg_size;
|
||||
int dump_oops;
|
||||
u32 flags;
|
||||
struct persistent_ram_ecc_info ecc_info;
|
||||
};
|
||||
|
||||
|
||||
@@ -4258,6 +4258,23 @@ int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ftrace_set_filter_ip);
|
||||
|
||||
/**
|
||||
* ftrace_ops_set_global_filter - setup ops to use global filters
|
||||
* @ops - the ops which will use the global filters
|
||||
*
|
||||
* ftrace users who need global function trace filtering should call this.
|
||||
* It can set the global filter only if ops were not initialized before.
|
||||
*/
|
||||
void ftrace_ops_set_global_filter(struct ftrace_ops *ops)
|
||||
{
|
||||
if (ops->flags & FTRACE_OPS_FL_INITIALIZED)
|
||||
return;
|
||||
|
||||
ftrace_ops_init(ops);
|
||||
ops->func_hash = &global_ops.local_hash;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ftrace_ops_set_global_filter);
|
||||
|
||||
static int
|
||||
ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
|
||||
int reset, int enable)
|
||||
|
||||
Reference in New Issue
Block a user