Merge tag 'v3.11-rc5' into sched/core
Merge Linux 3.11-rc5, to pick up the latest fixes. Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
+2
-1
@@ -2,7 +2,7 @@
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
obj-y = fork.o exec_domain.o panic.o printk.o \
|
||||
obj-y = fork.o exec_domain.o panic.o \
|
||||
cpu.o exit.o itimer.o time.o softirq.o resource.o \
|
||||
sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
|
||||
signal.o sys.o kmod.o workqueue.o pid.o task_work.o \
|
||||
@@ -24,6 +24,7 @@ endif
|
||||
|
||||
obj-y += sched/
|
||||
obj-y += power/
|
||||
obj-y += printk/
|
||||
obj-y += cpu/
|
||||
|
||||
obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o
|
||||
|
||||
+22
-13
@@ -1845,36 +1845,43 @@ out:
|
||||
EXPORT_SYMBOL_GPL(cgroup_path);
|
||||
|
||||
/**
|
||||
* task_cgroup_path_from_hierarchy - cgroup path of a task on a hierarchy
|
||||
* task_cgroup_path - cgroup path of a task in the first cgroup hierarchy
|
||||
* @task: target task
|
||||
* @hierarchy_id: the hierarchy to look up @task's cgroup from
|
||||
* @buf: the buffer to write the path into
|
||||
* @buflen: the length of the buffer
|
||||
*
|
||||
* Determine @task's cgroup on the hierarchy specified by @hierarchy_id and
|
||||
* copy its path into @buf. This function grabs cgroup_mutex and shouldn't
|
||||
* be used inside locks used by cgroup controller callbacks.
|
||||
* Determine @task's cgroup on the first (the one with the lowest non-zero
|
||||
* hierarchy_id) cgroup hierarchy and copy its path into @buf. This
|
||||
* function grabs cgroup_mutex and shouldn't be used inside locks used by
|
||||
* cgroup controller callbacks.
|
||||
*
|
||||
* Returns 0 on success, fails with -%ENAMETOOLONG if @buflen is too short.
|
||||
*/
|
||||
int task_cgroup_path_from_hierarchy(struct task_struct *task, int hierarchy_id,
|
||||
char *buf, size_t buflen)
|
||||
int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
|
||||
{
|
||||
struct cgroupfs_root *root;
|
||||
struct cgroup *cgrp = NULL;
|
||||
int ret = -ENOENT;
|
||||
struct cgroup *cgrp;
|
||||
int hierarchy_id = 1, ret = 0;
|
||||
|
||||
if (buflen < 2)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
mutex_lock(&cgroup_mutex);
|
||||
|
||||
root = idr_find(&cgroup_hierarchy_idr, hierarchy_id);
|
||||
root = idr_get_next(&cgroup_hierarchy_idr, &hierarchy_id);
|
||||
|
||||
if (root) {
|
||||
cgrp = task_cgroup_from_root(task, root);
|
||||
ret = cgroup_path(cgrp, buf, buflen);
|
||||
} else {
|
||||
/* if no hierarchy exists, everyone is in "/" */
|
||||
memcpy(buf, "/", 2);
|
||||
}
|
||||
|
||||
mutex_unlock(&cgroup_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(task_cgroup_path_from_hierarchy);
|
||||
EXPORT_SYMBOL_GPL(task_cgroup_path);
|
||||
|
||||
/*
|
||||
* Control Group taskset
|
||||
@@ -4328,8 +4335,10 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
|
||||
}
|
||||
|
||||
err = percpu_ref_init(&css->refcnt, css_release);
|
||||
if (err)
|
||||
if (err) {
|
||||
ss->css_free(cgrp);
|
||||
goto err_free_all;
|
||||
}
|
||||
|
||||
init_cgroup_css(css, ss, cgrp);
|
||||
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ static DEFINE_SPINLOCK(freezer_lock);
|
||||
*/
|
||||
bool freezing_slow_path(struct task_struct *p)
|
||||
{
|
||||
if (p->flags & PF_NOFREEZE)
|
||||
if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK))
|
||||
return false;
|
||||
|
||||
if (pm_nosig_freezing || cgroup_freezing(p))
|
||||
|
||||
@@ -109,6 +109,8 @@ static int try_to_freeze_tasks(bool user_only)
|
||||
|
||||
/**
|
||||
* freeze_processes - Signal user space processes to enter the refrigerator.
|
||||
* The current thread will not be frozen. The same process that calls
|
||||
* freeze_processes must later call thaw_processes.
|
||||
*
|
||||
* On success, returns 0. On failure, -errno and system is fully thawed.
|
||||
*/
|
||||
@@ -120,6 +122,9 @@ int freeze_processes(void)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Make sure this task doesn't get frozen */
|
||||
current->flags |= PF_SUSPEND_TASK;
|
||||
|
||||
if (!pm_freezing)
|
||||
atomic_inc(&system_freezing_cnt);
|
||||
|
||||
@@ -168,6 +173,7 @@ int freeze_kernel_threads(void)
|
||||
void thaw_processes(void)
|
||||
{
|
||||
struct task_struct *g, *p;
|
||||
struct task_struct *curr = current;
|
||||
|
||||
if (pm_freezing)
|
||||
atomic_dec(&system_freezing_cnt);
|
||||
@@ -182,10 +188,15 @@ void thaw_processes(void)
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
do_each_thread(g, p) {
|
||||
/* No other threads should have PF_SUSPEND_TASK set */
|
||||
WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK));
|
||||
__thaw_task(p);
|
||||
} while_each_thread(g, p);
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
WARN_ON(!(curr->flags & PF_SUSPEND_TASK));
|
||||
curr->flags &= ~PF_SUSPEND_TASK;
|
||||
|
||||
usermodehelper_enable();
|
||||
|
||||
schedule();
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
obj-y = printk.o
|
||||
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
|
||||
@@ -0,0 +1,49 @@
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "console_cmdline.h"
|
||||
#include "braille.h"
|
||||
|
||||
char *_braille_console_setup(char **str, char **brl_options)
|
||||
{
|
||||
if (!memcmp(*str, "brl,", 4)) {
|
||||
*brl_options = "";
|
||||
*str += 4;
|
||||
} else if (!memcmp(str, "brl=", 4)) {
|
||||
*brl_options = *str + 4;
|
||||
*str = strchr(*brl_options, ',');
|
||||
if (!*str)
|
||||
pr_err("need port name after brl=\n");
|
||||
else
|
||||
*((*str)++) = 0;
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
return *str;
|
||||
}
|
||||
|
||||
int
|
||||
_braille_register_console(struct console *console, struct console_cmdline *c)
|
||||
{
|
||||
int rtn = 0;
|
||||
|
||||
if (c->brl_options) {
|
||||
console->flags |= CON_BRL;
|
||||
rtn = braille_register_console(console, c->index, c->options,
|
||||
c->brl_options);
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
int
|
||||
_braille_unregister_console(struct console *console)
|
||||
{
|
||||
if (console->flags & CON_BRL)
|
||||
return braille_unregister_console(console);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef _PRINTK_BRAILLE_H
|
||||
#define _PRINTK_BRAILLE_H
|
||||
|
||||
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
|
||||
|
||||
static inline void
|
||||
braille_set_options(struct console_cmdline *c, char *brl_options)
|
||||
{
|
||||
c->brl_options = brl_options;
|
||||
}
|
||||
|
||||
char *
|
||||
_braille_console_setup(char **str, char **brl_options);
|
||||
|
||||
int
|
||||
_braille_register_console(struct console *console, struct console_cmdline *c);
|
||||
|
||||
int
|
||||
_braille_unregister_console(struct console *console);
|
||||
|
||||
#else
|
||||
|
||||
static inline void
|
||||
braille_set_options(struct console_cmdline *c, char *brl_options)
|
||||
{
|
||||
}
|
||||
|
||||
static inline char *
|
||||
_braille_console_setup(char **str, char **brl_options)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
_braille_register_console(struct console *console, struct console_cmdline *c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
_braille_unregister_console(struct console *console)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _CONSOLE_CMDLINE_H
|
||||
#define _CONSOLE_CMDLINE_H
|
||||
|
||||
struct console_cmdline
|
||||
{
|
||||
char name[8]; /* Name of the driver */
|
||||
int index; /* Minor dev. to use */
|
||||
char *options; /* Options for the driver */
|
||||
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
|
||||
char *brl_options; /* Options for braille driver */
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -51,6 +51,9 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/printk.h>
|
||||
|
||||
#include "console_cmdline.h"
|
||||
#include "braille.h"
|
||||
|
||||
/* printk's without a loglevel use this.. */
|
||||
#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
|
||||
|
||||
@@ -105,19 +108,11 @@ static struct console *exclusive_console;
|
||||
/*
|
||||
* Array of consoles built from command line options (console=)
|
||||
*/
|
||||
struct console_cmdline
|
||||
{
|
||||
char name[8]; /* Name of the driver */
|
||||
int index; /* Minor dev. to use */
|
||||
char *options; /* Options for the driver */
|
||||
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
|
||||
char *brl_options; /* Options for braille driver */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MAX_CMDLINECONSOLES 8
|
||||
|
||||
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
|
||||
|
||||
static int selected_console = -1;
|
||||
static int preferred_console = -1;
|
||||
int console_set_on_cmdline;
|
||||
@@ -178,7 +173,7 @@ static int console_may_schedule;
|
||||
* 67 "g"
|
||||
* 0032 00 00 00 padding to next message header
|
||||
*
|
||||
* The 'struct log' buffer header must never be directly exported to
|
||||
* The 'struct printk_log' buffer header must never be directly exported to
|
||||
* userspace, it is a kernel-private implementation detail that might
|
||||
* need to be changed in the future, when the requirements change.
|
||||
*
|
||||
@@ -200,7 +195,7 @@ enum log_flags {
|
||||
LOG_CONT = 8, /* text is a fragment of a continuation line */
|
||||
};
|
||||
|
||||
struct log {
|
||||
struct printk_log {
|
||||
u64 ts_nsec; /* timestamp in nanoseconds */
|
||||
u16 len; /* length of entire record */
|
||||
u16 text_len; /* length of text buffer */
|
||||
@@ -248,7 +243,7 @@ static u32 clear_idx;
|
||||
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||||
#define LOG_ALIGN 4
|
||||
#else
|
||||
#define LOG_ALIGN __alignof__(struct log)
|
||||
#define LOG_ALIGN __alignof__(struct printk_log)
|
||||
#endif
|
||||
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
|
||||
static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
|
||||
@@ -259,35 +254,35 @@ static u32 log_buf_len = __LOG_BUF_LEN;
|
||||
static volatile unsigned int logbuf_cpu = UINT_MAX;
|
||||
|
||||
/* human readable text of the record */
|
||||
static char *log_text(const struct log *msg)
|
||||
static char *log_text(const struct printk_log *msg)
|
||||
{
|
||||
return (char *)msg + sizeof(struct log);
|
||||
return (char *)msg + sizeof(struct printk_log);
|
||||
}
|
||||
|
||||
/* optional key/value pair dictionary attached to the record */
|
||||
static char *log_dict(const struct log *msg)
|
||||
static char *log_dict(const struct printk_log *msg)
|
||||
{
|
||||
return (char *)msg + sizeof(struct log) + msg->text_len;
|
||||
return (char *)msg + sizeof(struct printk_log) + msg->text_len;
|
||||
}
|
||||
|
||||
/* get record by index; idx must point to valid msg */
|
||||
static struct log *log_from_idx(u32 idx)
|
||||
static struct printk_log *log_from_idx(u32 idx)
|
||||
{
|
||||
struct log *msg = (struct log *)(log_buf + idx);
|
||||
struct printk_log *msg = (struct printk_log *)(log_buf + idx);
|
||||
|
||||
/*
|
||||
* A length == 0 record is the end of buffer marker. Wrap around and
|
||||
* read the message at the start of the buffer.
|
||||
*/
|
||||
if (!msg->len)
|
||||
return (struct log *)log_buf;
|
||||
return (struct printk_log *)log_buf;
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* get next record; idx must point to valid msg */
|
||||
static u32 log_next(u32 idx)
|
||||
{
|
||||
struct log *msg = (struct log *)(log_buf + idx);
|
||||
struct printk_log *msg = (struct printk_log *)(log_buf + idx);
|
||||
|
||||
/* length == 0 indicates the end of the buffer; wrap */
|
||||
/*
|
||||
@@ -296,7 +291,7 @@ static u32 log_next(u32 idx)
|
||||
* return the one after that.
|
||||
*/
|
||||
if (!msg->len) {
|
||||
msg = (struct log *)log_buf;
|
||||
msg = (struct printk_log *)log_buf;
|
||||
return msg->len;
|
||||
}
|
||||
return idx + msg->len;
|
||||
@@ -308,11 +303,11 @@ static void log_store(int facility, int level,
|
||||
const char *dict, u16 dict_len,
|
||||
const char *text, u16 text_len)
|
||||
{
|
||||
struct log *msg;
|
||||
struct printk_log *msg;
|
||||
u32 size, pad_len;
|
||||
|
||||
/* number of '\0' padding bytes to next message */
|
||||
size = sizeof(struct log) + text_len + dict_len;
|
||||
size = sizeof(struct printk_log) + text_len + dict_len;
|
||||
pad_len = (-size) & (LOG_ALIGN - 1);
|
||||
size += pad_len;
|
||||
|
||||
@@ -324,7 +319,7 @@ static void log_store(int facility, int level,
|
||||
else
|
||||
free = log_first_idx - log_next_idx;
|
||||
|
||||
if (free > size + sizeof(struct log))
|
||||
if (free > size + sizeof(struct printk_log))
|
||||
break;
|
||||
|
||||
/* drop old messages until we have enough contiuous space */
|
||||
@@ -332,18 +327,18 @@ static void log_store(int facility, int level,
|
||||
log_first_seq++;
|
||||
}
|
||||
|
||||
if (log_next_idx + size + sizeof(struct log) >= log_buf_len) {
|
||||
if (log_next_idx + size + sizeof(struct printk_log) >= log_buf_len) {
|
||||
/*
|
||||
* This message + an additional empty header does not fit
|
||||
* at the end of the buffer. Add an empty header with len == 0
|
||||
* to signify a wrap around.
|
||||
*/
|
||||
memset(log_buf + log_next_idx, 0, sizeof(struct log));
|
||||
memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));
|
||||
log_next_idx = 0;
|
||||
}
|
||||
|
||||
/* fill message */
|
||||
msg = (struct log *)(log_buf + log_next_idx);
|
||||
msg = (struct printk_log *)(log_buf + log_next_idx);
|
||||
memcpy(log_text(msg), text, text_len);
|
||||
msg->text_len = text_len;
|
||||
memcpy(log_dict(msg), dict, dict_len);
|
||||
@@ -356,7 +351,7 @@ static void log_store(int facility, int level,
|
||||
else
|
||||
msg->ts_nsec = local_clock();
|
||||
memset(log_dict(msg) + dict_len, 0, pad_len);
|
||||
msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
|
||||
msg->len = sizeof(struct printk_log) + text_len + dict_len + pad_len;
|
||||
|
||||
/* insert message */
|
||||
log_next_idx += msg->len;
|
||||
@@ -479,7 +474,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct devkmsg_user *user = file->private_data;
|
||||
struct log *msg;
|
||||
struct printk_log *msg;
|
||||
u64 ts_usec;
|
||||
size_t i;
|
||||
char cont = '-';
|
||||
@@ -724,14 +719,14 @@ void log_buf_kexec_setup(void)
|
||||
VMCOREINFO_SYMBOL(log_first_idx);
|
||||
VMCOREINFO_SYMBOL(log_next_idx);
|
||||
/*
|
||||
* Export struct log size and field offsets. User space tools can
|
||||
* Export struct printk_log size and field offsets. User space tools can
|
||||
* parse it and detect any changes to structure down the line.
|
||||
*/
|
||||
VMCOREINFO_STRUCT_SIZE(log);
|
||||
VMCOREINFO_OFFSET(log, ts_nsec);
|
||||
VMCOREINFO_OFFSET(log, len);
|
||||
VMCOREINFO_OFFSET(log, text_len);
|
||||
VMCOREINFO_OFFSET(log, dict_len);
|
||||
VMCOREINFO_STRUCT_SIZE(printk_log);
|
||||
VMCOREINFO_OFFSET(printk_log, ts_nsec);
|
||||
VMCOREINFO_OFFSET(printk_log, len);
|
||||
VMCOREINFO_OFFSET(printk_log, text_len);
|
||||
VMCOREINFO_OFFSET(printk_log, dict_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -884,7 +879,7 @@ static size_t print_time(u64 ts, char *buf)
|
||||
(unsigned long)ts, rem_nsec / 1000);
|
||||
}
|
||||
|
||||
static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
|
||||
static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf)
|
||||
{
|
||||
size_t len = 0;
|
||||
unsigned int prefix = (msg->facility << 3) | msg->level;
|
||||
@@ -907,7 +902,7 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t msg_print_text(const struct log *msg, enum log_flags prev,
|
||||
static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
|
||||
bool syslog, char *buf, size_t size)
|
||||
{
|
||||
const char *text = log_text(msg);
|
||||
@@ -969,7 +964,7 @@ static size_t msg_print_text(const struct log *msg, enum log_flags prev,
|
||||
static int syslog_print(char __user *buf, int size)
|
||||
{
|
||||
char *text;
|
||||
struct log *msg;
|
||||
struct printk_log *msg;
|
||||
int len = 0;
|
||||
|
||||
text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
|
||||
@@ -1060,7 +1055,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
||||
idx = clear_idx;
|
||||
prev = 0;
|
||||
while (seq < log_next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
struct printk_log *msg = log_from_idx(idx);
|
||||
|
||||
len += msg_print_text(msg, prev, true, NULL, 0);
|
||||
prev = msg->flags;
|
||||
@@ -1073,7 +1068,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
||||
idx = clear_idx;
|
||||
prev = 0;
|
||||
while (len > size && seq < log_next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
struct printk_log *msg = log_from_idx(idx);
|
||||
|
||||
len -= msg_print_text(msg, prev, true, NULL, 0);
|
||||
prev = msg->flags;
|
||||
@@ -1087,7 +1082,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
||||
len = 0;
|
||||
prev = 0;
|
||||
while (len >= 0 && seq < next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
struct printk_log *msg = log_from_idx(idx);
|
||||
int textlen;
|
||||
|
||||
textlen = msg_print_text(msg, prev, true, text,
|
||||
@@ -1233,7 +1228,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
|
||||
|
||||
error = 0;
|
||||
while (seq < log_next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
struct printk_log *msg = log_from_idx(idx);
|
||||
|
||||
error += msg_print_text(msg, prev, true, NULL, 0);
|
||||
idx = log_next(idx);
|
||||
@@ -1719,10 +1714,10 @@ static struct cont {
|
||||
u8 level;
|
||||
bool flushed:1;
|
||||
} cont;
|
||||
static struct log *log_from_idx(u32 idx) { return NULL; }
|
||||
static struct printk_log *log_from_idx(u32 idx) { return NULL; }
|
||||
static u32 log_next(u32 idx) { return 0; }
|
||||
static void call_console_drivers(int level, const char *text, size_t len) {}
|
||||
static size_t msg_print_text(const struct log *msg, enum log_flags prev,
|
||||
static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
|
||||
bool syslog, char *buf, size_t size) { return 0; }
|
||||
static size_t cont_print_text(char *text, size_t size) { return 0; }
|
||||
|
||||
@@ -1761,23 +1756,23 @@ static int __add_preferred_console(char *name, int idx, char *options,
|
||||
* See if this tty is not yet registered, and
|
||||
* if we have a slot free.
|
||||
*/
|
||||
for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
|
||||
if (strcmp(console_cmdline[i].name, name) == 0 &&
|
||||
console_cmdline[i].index == idx) {
|
||||
if (!brl_options)
|
||||
selected_console = i;
|
||||
return 0;
|
||||
for (i = 0, c = console_cmdline;
|
||||
i < MAX_CMDLINECONSOLES && c->name[0];
|
||||
i++, c++) {
|
||||
if (strcmp(c->name, name) == 0 && c->index == idx) {
|
||||
if (!brl_options)
|
||||
selected_console = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (i == MAX_CMDLINECONSOLES)
|
||||
return -E2BIG;
|
||||
if (!brl_options)
|
||||
selected_console = i;
|
||||
c = &console_cmdline[i];
|
||||
strlcpy(c->name, name, sizeof(c->name));
|
||||
c->options = options;
|
||||
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
|
||||
c->brl_options = brl_options;
|
||||
#endif
|
||||
braille_set_options(c, brl_options);
|
||||
|
||||
c->index = idx;
|
||||
return 0;
|
||||
}
|
||||
@@ -1790,20 +1785,8 @@ static int __init console_setup(char *str)
|
||||
char *s, *options, *brl_options = NULL;
|
||||
int idx;
|
||||
|
||||
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
|
||||
if (!memcmp(str, "brl,", 4)) {
|
||||
brl_options = "";
|
||||
str += 4;
|
||||
} else if (!memcmp(str, "brl=", 4)) {
|
||||
brl_options = str + 4;
|
||||
str = strchr(brl_options, ',');
|
||||
if (!str) {
|
||||
printk(KERN_ERR "need port name after brl=\n");
|
||||
return 1;
|
||||
}
|
||||
*(str++) = 0;
|
||||
}
|
||||
#endif
|
||||
if (_braille_console_setup(&str, &brl_options))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Decode str into name, index, options.
|
||||
@@ -1858,15 +1841,15 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha
|
||||
struct console_cmdline *c;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
|
||||
if (strcmp(console_cmdline[i].name, name) == 0 &&
|
||||
console_cmdline[i].index == idx) {
|
||||
c = &console_cmdline[i];
|
||||
strlcpy(c->name, name_new, sizeof(c->name));
|
||||
c->name[sizeof(c->name) - 1] = 0;
|
||||
c->options = options;
|
||||
c->index = idx_new;
|
||||
return i;
|
||||
for (i = 0, c = console_cmdline;
|
||||
i < MAX_CMDLINECONSOLES && c->name[0];
|
||||
i++, c++)
|
||||
if (strcmp(c->name, name) == 0 && c->index == idx) {
|
||||
strlcpy(c->name, name_new, sizeof(c->name));
|
||||
c->name[sizeof(c->name) - 1] = 0;
|
||||
c->options = options;
|
||||
c->index = idx_new;
|
||||
return i;
|
||||
}
|
||||
/* not found */
|
||||
return -1;
|
||||
@@ -2046,7 +2029,7 @@ void console_unlock(void)
|
||||
console_cont_flush(text, sizeof(text));
|
||||
again:
|
||||
for (;;) {
|
||||
struct log *msg;
|
||||
struct printk_log *msg;
|
||||
size_t len;
|
||||
int level;
|
||||
|
||||
@@ -2241,6 +2224,7 @@ void register_console(struct console *newcon)
|
||||
int i;
|
||||
unsigned long flags;
|
||||
struct console *bcon = NULL;
|
||||
struct console_cmdline *c;
|
||||
|
||||
/*
|
||||
* before we register a new CON_BOOT console, make sure we don't
|
||||
@@ -2288,30 +2272,25 @@ void register_console(struct console *newcon)
|
||||
* See if this console matches one we selected on
|
||||
* the command line.
|
||||
*/
|
||||
for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
|
||||
i++) {
|
||||
if (strcmp(console_cmdline[i].name, newcon->name) != 0)
|
||||
for (i = 0, c = console_cmdline;
|
||||
i < MAX_CMDLINECONSOLES && c->name[0];
|
||||
i++, c++) {
|
||||
if (strcmp(c->name, newcon->name) != 0)
|
||||
continue;
|
||||
if (newcon->index >= 0 &&
|
||||
newcon->index != console_cmdline[i].index)
|
||||
newcon->index != c->index)
|
||||
continue;
|
||||
if (newcon->index < 0)
|
||||
newcon->index = console_cmdline[i].index;
|
||||
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
|
||||
if (console_cmdline[i].brl_options) {
|
||||
newcon->flags |= CON_BRL;
|
||||
braille_register_console(newcon,
|
||||
console_cmdline[i].index,
|
||||
console_cmdline[i].options,
|
||||
console_cmdline[i].brl_options);
|
||||
newcon->index = c->index;
|
||||
|
||||
if (_braille_register_console(newcon, c))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (newcon->setup &&
|
||||
newcon->setup(newcon, console_cmdline[i].options) != 0)
|
||||
break;
|
||||
newcon->flags |= CON_ENABLED;
|
||||
newcon->index = console_cmdline[i].index;
|
||||
newcon->index = c->index;
|
||||
if (i == selected_console) {
|
||||
newcon->flags |= CON_CONSDEV;
|
||||
preferred_console = selected_console;
|
||||
@@ -2394,13 +2373,13 @@ EXPORT_SYMBOL(register_console);
|
||||
int unregister_console(struct console *console)
|
||||
{
|
||||
struct console *a, *b;
|
||||
int res = 1;
|
||||
int res;
|
||||
|
||||
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
|
||||
if (console->flags & CON_BRL)
|
||||
return braille_unregister_console(console);
|
||||
#endif
|
||||
res = _braille_unregister_console(console);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
res = 1;
|
||||
console_lock();
|
||||
if (console_drivers == console) {
|
||||
console_drivers=console->next;
|
||||
@@ -2666,7 +2645,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
|
||||
bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
|
||||
char *line, size_t size, size_t *len)
|
||||
{
|
||||
struct log *msg;
|
||||
struct printk_log *msg;
|
||||
size_t l = 0;
|
||||
bool ret = false;
|
||||
|
||||
@@ -2778,7 +2757,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
||||
idx = dumper->cur_idx;
|
||||
prev = 0;
|
||||
while (seq < dumper->next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
struct printk_log *msg = log_from_idx(idx);
|
||||
|
||||
l += msg_print_text(msg, prev, true, NULL, 0);
|
||||
idx = log_next(idx);
|
||||
@@ -2791,7 +2770,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
||||
idx = dumper->cur_idx;
|
||||
prev = 0;
|
||||
while (l > size && seq < dumper->next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
struct printk_log *msg = log_from_idx(idx);
|
||||
|
||||
l -= msg_print_text(msg, prev, true, NULL, 0);
|
||||
idx = log_next(idx);
|
||||
@@ -2806,7 +2785,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
||||
l = 0;
|
||||
prev = 0;
|
||||
while (seq < dumper->next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
struct printk_log *msg = log_from_idx(idx);
|
||||
|
||||
l += msg_print_text(msg, prev, syslog, buf + l, size - l);
|
||||
idx = log_next(idx);
|
||||
@@ -469,7 +469,6 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
|
||||
/* Architecture-specific hardware disable .. */
|
||||
ptrace_disable(child);
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
flush_ptrace_hw_breakpoint(child);
|
||||
|
||||
write_lock_irq(&tasklist_lock);
|
||||
/*
|
||||
|
||||
+2
-2
@@ -851,7 +851,7 @@ void task_numa_fault(int node, int pages, bool migrated)
|
||||
{
|
||||
struct task_struct *p = current;
|
||||
|
||||
if (!sched_feat_numa(NUMA))
|
||||
if (!numabalancing_enabled)
|
||||
return;
|
||||
|
||||
/* FIXME: Allocate task-specific structure for placement policy here */
|
||||
@@ -5786,7 +5786,7 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
|
||||
entity_tick(cfs_rq, se, queued);
|
||||
}
|
||||
|
||||
if (sched_feat_numa(NUMA))
|
||||
if (numabalancing_enabled)
|
||||
task_tick_numa(rq, curr);
|
||||
|
||||
update_rq_runnable_avg(rq, 1);
|
||||
|
||||
+5
-1
@@ -2346,7 +2346,11 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
|
||||
int write, void *data)
|
||||
{
|
||||
if (write) {
|
||||
*valp = msecs_to_jiffies(*negp ? -*lvalp : *lvalp);
|
||||
unsigned long jif = msecs_to_jiffies(*negp ? -*lvalp : *lvalp);
|
||||
|
||||
if (jif > INT_MAX)
|
||||
return 1;
|
||||
*valp = (int)jif;
|
||||
} else {
|
||||
int val = *valp;
|
||||
unsigned long lval;
|
||||
|
||||
@@ -827,13 +827,10 @@ void tick_nohz_irq_exit(void)
|
||||
{
|
||||
struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
|
||||
|
||||
if (ts->inidle) {
|
||||
/* Cancel the timer because CPU already waken up from the C-states*/
|
||||
menu_hrtimer_cancel();
|
||||
if (ts->inidle)
|
||||
__tick_nohz_idle_enter(ts);
|
||||
} else {
|
||||
else
|
||||
tick_nohz_full_stop_tick(ts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -931,8 +928,6 @@ void tick_nohz_idle_exit(void)
|
||||
|
||||
ts->inidle = 0;
|
||||
|
||||
/* Cancel the timer because CPU already waken up from the C-states*/
|
||||
menu_hrtimer_cancel();
|
||||
if (ts->idle_active || ts->tick_stopped)
|
||||
now = ktime_get();
|
||||
|
||||
|
||||
+86
-19
@@ -1441,12 +1441,22 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
|
||||
* the hashes are freed with call_rcu_sched().
|
||||
*/
|
||||
static int
|
||||
ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
|
||||
ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
|
||||
{
|
||||
struct ftrace_hash *filter_hash;
|
||||
struct ftrace_hash *notrace_hash;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
|
||||
/*
|
||||
* There's a small race when adding ops that the ftrace handler
|
||||
* that wants regs, may be called without them. We can not
|
||||
* allow that handler to be called if regs is NULL.
|
||||
*/
|
||||
if (regs == NULL && (ops->flags & FTRACE_OPS_FL_SAVE_REGS))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
filter_hash = rcu_dereference_raw_notrace(ops->filter_hash);
|
||||
notrace_hash = rcu_dereference_raw_notrace(ops->notrace_hash);
|
||||
|
||||
@@ -2159,12 +2169,57 @@ static cycle_t ftrace_update_time;
|
||||
static unsigned long ftrace_update_cnt;
|
||||
unsigned long ftrace_update_tot_cnt;
|
||||
|
||||
static int ops_traces_mod(struct ftrace_ops *ops)
|
||||
static inline int ops_traces_mod(struct ftrace_ops *ops)
|
||||
{
|
||||
struct ftrace_hash *hash;
|
||||
/*
|
||||
* Filter_hash being empty will default to trace module.
|
||||
* But notrace hash requires a test of individual module functions.
|
||||
*/
|
||||
return ftrace_hash_empty(ops->filter_hash) &&
|
||||
ftrace_hash_empty(ops->notrace_hash);
|
||||
}
|
||||
|
||||
hash = ops->filter_hash;
|
||||
return ftrace_hash_empty(hash);
|
||||
/*
|
||||
* Check if the current ops references the record.
|
||||
*
|
||||
* If the ops traces all functions, then it was already accounted for.
|
||||
* If the ops does not trace the current record function, skip it.
|
||||
* If the ops ignores the function via notrace filter, skip it.
|
||||
*/
|
||||
static inline bool
|
||||
ops_references_rec(struct ftrace_ops *ops, struct dyn_ftrace *rec)
|
||||
{
|
||||
/* If ops isn't enabled, ignore it */
|
||||
if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
|
||||
return 0;
|
||||
|
||||
/* If ops traces all mods, we already accounted for it */
|
||||
if (ops_traces_mod(ops))
|
||||
return 0;
|
||||
|
||||
/* The function must be in the filter */
|
||||
if (!ftrace_hash_empty(ops->filter_hash) &&
|
||||
!ftrace_lookup_ip(ops->filter_hash, rec->ip))
|
||||
return 0;
|
||||
|
||||
/* If in notrace hash, we ignore it too */
|
||||
if (ftrace_lookup_ip(ops->notrace_hash, rec->ip))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int referenced_filters(struct dyn_ftrace *rec)
|
||||
{
|
||||
struct ftrace_ops *ops;
|
||||
int cnt = 0;
|
||||
|
||||
for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) {
|
||||
if (ops_references_rec(ops, rec))
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int ftrace_update_code(struct module *mod)
|
||||
@@ -2173,6 +2228,7 @@ static int ftrace_update_code(struct module *mod)
|
||||
struct dyn_ftrace *p;
|
||||
cycle_t start, stop;
|
||||
unsigned long ref = 0;
|
||||
bool test = false;
|
||||
int i;
|
||||
|
||||
/*
|
||||
@@ -2186,9 +2242,12 @@ static int ftrace_update_code(struct module *mod)
|
||||
|
||||
for (ops = ftrace_ops_list;
|
||||
ops != &ftrace_list_end; ops = ops->next) {
|
||||
if (ops->flags & FTRACE_OPS_FL_ENABLED &&
|
||||
ops_traces_mod(ops))
|
||||
ref++;
|
||||
if (ops->flags & FTRACE_OPS_FL_ENABLED) {
|
||||
if (ops_traces_mod(ops))
|
||||
ref++;
|
||||
else
|
||||
test = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2198,12 +2257,16 @@ static int ftrace_update_code(struct module *mod)
|
||||
for (pg = ftrace_new_pgs; pg; pg = pg->next) {
|
||||
|
||||
for (i = 0; i < pg->index; i++) {
|
||||
int cnt = ref;
|
||||
|
||||
/* If something went wrong, bail without enabling anything */
|
||||
if (unlikely(ftrace_disabled))
|
||||
return -1;
|
||||
|
||||
p = &pg->records[i];
|
||||
p->flags = ref;
|
||||
if (test)
|
||||
cnt += referenced_filters(p);
|
||||
p->flags = cnt;
|
||||
|
||||
/*
|
||||
* Do the initial record conversion from mcount jump
|
||||
@@ -2223,7 +2286,7 @@ static int ftrace_update_code(struct module *mod)
|
||||
* conversion puts the module to the correct state, thus
|
||||
* passing the ftrace_make_call check.
|
||||
*/
|
||||
if (ftrace_start_up && ref) {
|
||||
if (ftrace_start_up && cnt) {
|
||||
int failed = __ftrace_replace_code(p, 1);
|
||||
if (failed)
|
||||
ftrace_bug(failed, p->ip);
|
||||
@@ -3374,6 +3437,12 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
|
||||
return add_hash_entry(hash, ip);
|
||||
}
|
||||
|
||||
static void ftrace_ops_update_code(struct ftrace_ops *ops)
|
||||
{
|
||||
if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
|
||||
ftrace_run_update_code(FTRACE_UPDATE_CALLS);
|
||||
}
|
||||
|
||||
static int
|
||||
ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
|
||||
unsigned long ip, int remove, int reset, int enable)
|
||||
@@ -3416,9 +3485,8 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
|
||||
|
||||
mutex_lock(&ftrace_lock);
|
||||
ret = ftrace_hash_move(ops, enable, orig_hash, hash);
|
||||
if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED
|
||||
&& ftrace_enabled)
|
||||
ftrace_run_update_code(FTRACE_UPDATE_CALLS);
|
||||
if (!ret)
|
||||
ftrace_ops_update_code(ops);
|
||||
|
||||
mutex_unlock(&ftrace_lock);
|
||||
|
||||
@@ -3645,9 +3713,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
|
||||
mutex_lock(&ftrace_lock);
|
||||
ret = ftrace_hash_move(iter->ops, filter_hash,
|
||||
orig_hash, iter->hash);
|
||||
if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED)
|
||||
&& ftrace_enabled)
|
||||
ftrace_run_update_code(FTRACE_UPDATE_CALLS);
|
||||
if (!ret)
|
||||
ftrace_ops_update_code(iter->ops);
|
||||
|
||||
mutex_unlock(&ftrace_lock);
|
||||
}
|
||||
@@ -4218,7 +4285,7 @@ static inline void ftrace_startup_enable(int command) { }
|
||||
# define ftrace_shutdown_sysctl() do { } while (0)
|
||||
|
||||
static inline int
|
||||
ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
|
||||
ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -4241,7 +4308,7 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip,
|
||||
do_for_each_ftrace_op(op, ftrace_control_list) {
|
||||
if (!(op->flags & FTRACE_OPS_FL_STUB) &&
|
||||
!ftrace_function_local_disabled(op) &&
|
||||
ftrace_ops_test(op, ip))
|
||||
ftrace_ops_test(op, ip, regs))
|
||||
op->func(ip, parent_ip, op, regs);
|
||||
} while_for_each_ftrace_op(op);
|
||||
trace_recursion_clear(TRACE_CONTROL_BIT);
|
||||
@@ -4274,7 +4341,7 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
|
||||
*/
|
||||
preempt_disable_notrace();
|
||||
do_for_each_ftrace_op(op, ftrace_ops_list) {
|
||||
if (ftrace_ops_test(op, ip))
|
||||
if (ftrace_ops_test(op, ip, regs))
|
||||
op->func(ip, parent_ip, op, regs);
|
||||
} while_for_each_ftrace_op(op);
|
||||
preempt_enable_notrace();
|
||||
|
||||
+14
-12
@@ -36,11 +36,11 @@ int ring_buffer_print_entry_header(struct trace_seq *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = trace_seq_printf(s, "# compressed entry header\n");
|
||||
ret = trace_seq_printf(s, "\ttype_len : 5 bits\n");
|
||||
ret = trace_seq_printf(s, "\ttime_delta : 27 bits\n");
|
||||
ret = trace_seq_printf(s, "\tarray : 32 bits\n");
|
||||
ret = trace_seq_printf(s, "\n");
|
||||
ret = trace_seq_puts(s, "# compressed entry header\n");
|
||||
ret = trace_seq_puts(s, "\ttype_len : 5 bits\n");
|
||||
ret = trace_seq_puts(s, "\ttime_delta : 27 bits\n");
|
||||
ret = trace_seq_puts(s, "\tarray : 32 bits\n");
|
||||
ret = trace_seq_putc(s, '\n');
|
||||
ret = trace_seq_printf(s, "\tpadding : type == %d\n",
|
||||
RINGBUF_TYPE_PADDING);
|
||||
ret = trace_seq_printf(s, "\ttime_extend : type == %d\n",
|
||||
@@ -1066,7 +1066,7 @@ static int rb_check_list(struct ring_buffer_per_cpu *cpu_buffer,
|
||||
}
|
||||
|
||||
/**
|
||||
* check_pages - integrity check of buffer pages
|
||||
* rb_check_pages - integrity check of buffer pages
|
||||
* @cpu_buffer: CPU buffer with pages to test
|
||||
*
|
||||
* As a safety measure we check to make sure the data pages have not
|
||||
@@ -1258,7 +1258,7 @@ static int rb_cpu_notify(struct notifier_block *self,
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ring_buffer_alloc - allocate a new ring_buffer
|
||||
* __ring_buffer_alloc - allocate a new ring_buffer
|
||||
* @size: the size in bytes per cpu that is needed.
|
||||
* @flags: attributes to set for the ring buffer.
|
||||
*
|
||||
@@ -1607,6 +1607,7 @@ static void update_pages_handler(struct work_struct *work)
|
||||
* ring_buffer_resize - resize the ring buffer
|
||||
* @buffer: the buffer to resize.
|
||||
* @size: the new size.
|
||||
* @cpu_id: the cpu buffer to resize
|
||||
*
|
||||
* Minimum size is 2 * BUF_PAGE_SIZE.
|
||||
*
|
||||
@@ -3956,11 +3957,11 @@ EXPORT_SYMBOL_GPL(ring_buffer_consume);
|
||||
* expected.
|
||||
*
|
||||
* After a sequence of ring_buffer_read_prepare calls, the user is
|
||||
* expected to make at least one call to ring_buffer_prepare_sync.
|
||||
* expected to make at least one call to ring_buffer_read_prepare_sync.
|
||||
* Afterwards, ring_buffer_read_start is invoked to get things going
|
||||
* for real.
|
||||
*
|
||||
* This overall must be paired with ring_buffer_finish.
|
||||
* This overall must be paired with ring_buffer_read_finish.
|
||||
*/
|
||||
struct ring_buffer_iter *
|
||||
ring_buffer_read_prepare(struct ring_buffer *buffer, int cpu)
|
||||
@@ -4009,7 +4010,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_read_prepare_sync);
|
||||
* an intervening ring_buffer_read_prepare_sync must have been
|
||||
* performed.
|
||||
*
|
||||
* Must be paired with ring_buffer_finish.
|
||||
* Must be paired with ring_buffer_read_finish.
|
||||
*/
|
||||
void
|
||||
ring_buffer_read_start(struct ring_buffer_iter *iter)
|
||||
@@ -4031,7 +4032,7 @@ ring_buffer_read_start(struct ring_buffer_iter *iter)
|
||||
EXPORT_SYMBOL_GPL(ring_buffer_read_start);
|
||||
|
||||
/**
|
||||
* ring_buffer_finish - finish reading the iterator of the buffer
|
||||
* ring_buffer_read_finish - finish reading the iterator of the buffer
|
||||
* @iter: The iterator retrieved by ring_buffer_start
|
||||
*
|
||||
* This re-enables the recording to the buffer, and frees the
|
||||
@@ -4346,6 +4347,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu);
|
||||
/**
|
||||
* ring_buffer_alloc_read_page - allocate a page to read from buffer
|
||||
* @buffer: the buffer to allocate for.
|
||||
* @cpu: the cpu buffer to allocate.
|
||||
*
|
||||
* This function is used in conjunction with ring_buffer_read_page.
|
||||
* When reading a full page from the ring buffer, these functions
|
||||
@@ -4403,7 +4405,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
|
||||
* to swap with a page in the ring buffer.
|
||||
*
|
||||
* for example:
|
||||
* rpage = ring_buffer_alloc_read_page(buffer);
|
||||
* rpage = ring_buffer_alloc_read_page(buffer, cpu);
|
||||
* if (!rpage)
|
||||
* return error;
|
||||
* ret = ring_buffer_read_page(buffer, &rpage, len, cpu, 0);
|
||||
|
||||
+116
-138
@@ -243,20 +243,25 @@ int filter_current_check_discard(struct ring_buffer *buffer,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(filter_current_check_discard);
|
||||
|
||||
cycle_t ftrace_now(int cpu)
|
||||
cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu)
|
||||
{
|
||||
u64 ts;
|
||||
|
||||
/* Early boot up does not have a buffer yet */
|
||||
if (!global_trace.trace_buffer.buffer)
|
||||
if (!buf->buffer)
|
||||
return trace_clock_local();
|
||||
|
||||
ts = ring_buffer_time_stamp(global_trace.trace_buffer.buffer, cpu);
|
||||
ring_buffer_normalize_time_stamp(global_trace.trace_buffer.buffer, cpu, &ts);
|
||||
ts = ring_buffer_time_stamp(buf->buffer, cpu);
|
||||
ring_buffer_normalize_time_stamp(buf->buffer, cpu, &ts);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
cycle_t ftrace_now(int cpu)
|
||||
{
|
||||
return buffer_ftrace_now(&global_trace.trace_buffer, cpu);
|
||||
}
|
||||
|
||||
/**
|
||||
* tracing_is_enabled - Show if global_trace has been disabled
|
||||
*
|
||||
@@ -1211,7 +1216,7 @@ void tracing_reset_online_cpus(struct trace_buffer *buf)
|
||||
/* Make sure all commits have finished */
|
||||
synchronize_sched();
|
||||
|
||||
buf->time_start = ftrace_now(buf->cpu);
|
||||
buf->time_start = buffer_ftrace_now(buf, buf->cpu);
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
ring_buffer_reset_cpu(buffer, cpu);
|
||||
@@ -1219,23 +1224,17 @@ void tracing_reset_online_cpus(struct trace_buffer *buf)
|
||||
ring_buffer_record_enable(buffer);
|
||||
}
|
||||
|
||||
void tracing_reset_current(int cpu)
|
||||
{
|
||||
tracing_reset(&global_trace.trace_buffer, cpu);
|
||||
}
|
||||
|
||||
/* Must have trace_types_lock held */
|
||||
void tracing_reset_all_online_cpus(void)
|
||||
{
|
||||
struct trace_array *tr;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
list_for_each_entry(tr, &ftrace_trace_arrays, list) {
|
||||
tracing_reset_online_cpus(&tr->trace_buffer);
|
||||
#ifdef CONFIG_TRACER_MAX_TRACE
|
||||
tracing_reset_online_cpus(&tr->max_buffer);
|
||||
#endif
|
||||
}
|
||||
mutex_unlock(&trace_types_lock);
|
||||
}
|
||||
|
||||
#define SAVED_CMDLINES 128
|
||||
@@ -2843,6 +2842,17 @@ static int s_show(struct seq_file *m, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should be used after trace_array_get(), trace_types_lock
|
||||
* ensures that i_cdev was already initialized.
|
||||
*/
|
||||
static inline int tracing_get_cpu(struct inode *inode)
|
||||
{
|
||||
if (inode->i_cdev) /* See trace_create_cpu_file() */
|
||||
return (long)inode->i_cdev - 1;
|
||||
return RING_BUFFER_ALL_CPUS;
|
||||
}
|
||||
|
||||
static const struct seq_operations tracer_seq_ops = {
|
||||
.start = s_start,
|
||||
.next = s_next,
|
||||
@@ -2851,9 +2861,9 @@ static const struct seq_operations tracer_seq_ops = {
|
||||
};
|
||||
|
||||
static struct trace_iterator *
|
||||
__tracing_open(struct trace_array *tr, struct trace_cpu *tc,
|
||||
struct inode *inode, struct file *file, bool snapshot)
|
||||
__tracing_open(struct inode *inode, struct file *file, bool snapshot)
|
||||
{
|
||||
struct trace_array *tr = inode->i_private;
|
||||
struct trace_iterator *iter;
|
||||
int cpu;
|
||||
|
||||
@@ -2894,8 +2904,8 @@ __tracing_open(struct trace_array *tr, struct trace_cpu *tc,
|
||||
iter->trace_buffer = &tr->trace_buffer;
|
||||
iter->snapshot = snapshot;
|
||||
iter->pos = -1;
|
||||
iter->cpu_file = tracing_get_cpu(inode);
|
||||
mutex_init(&iter->mutex);
|
||||
iter->cpu_file = tc->cpu;
|
||||
|
||||
/* Notify the tracer early; before we stop tracing. */
|
||||
if (iter->trace && iter->trace->open)
|
||||
@@ -2971,45 +2981,22 @@ static int tracing_open_generic_tr(struct inode *inode, struct file *filp)
|
||||
filp->private_data = inode->i_private;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int tracing_open_generic_tc(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct trace_cpu *tc = inode->i_private;
|
||||
struct trace_array *tr = tc->tr;
|
||||
|
||||
if (tracing_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
if (trace_array_get(tr) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
filp->private_data = inode->i_private;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int tracing_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct trace_array *tr = inode->i_private;
|
||||
struct seq_file *m = file->private_data;
|
||||
struct trace_iterator *iter;
|
||||
struct trace_array *tr;
|
||||
int cpu;
|
||||
|
||||
/* Writes do not use seq_file, need to grab tr from inode */
|
||||
if (!(file->f_mode & FMODE_READ)) {
|
||||
struct trace_cpu *tc = inode->i_private;
|
||||
|
||||
trace_array_put(tc->tr);
|
||||
trace_array_put(tr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Writes do not use seq_file */
|
||||
iter = m->private;
|
||||
tr = iter->tr;
|
||||
trace_array_put(tr);
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
|
||||
for_each_tracing_cpu(cpu) {
|
||||
@@ -3023,6 +3010,9 @@ static int tracing_release(struct inode *inode, struct file *file)
|
||||
if (!iter->snapshot)
|
||||
/* reenable tracing if it was previously enabled */
|
||||
tracing_start_tr(tr);
|
||||
|
||||
__trace_array_put(tr);
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
mutex_destroy(&iter->mutex);
|
||||
@@ -3042,15 +3032,6 @@ static int tracing_release_generic_tr(struct inode *inode, struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tracing_release_generic_tc(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct trace_cpu *tc = inode->i_private;
|
||||
struct trace_array *tr = tc->tr;
|
||||
|
||||
trace_array_put(tr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tracing_single_release_tr(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct trace_array *tr = inode->i_private;
|
||||
@@ -3062,8 +3043,7 @@ static int tracing_single_release_tr(struct inode *inode, struct file *file)
|
||||
|
||||
static int tracing_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct trace_cpu *tc = inode->i_private;
|
||||
struct trace_array *tr = tc->tr;
|
||||
struct trace_array *tr = inode->i_private;
|
||||
struct trace_iterator *iter;
|
||||
int ret = 0;
|
||||
|
||||
@@ -3071,16 +3051,17 @@ static int tracing_open(struct inode *inode, struct file *file)
|
||||
return -ENODEV;
|
||||
|
||||
/* If this file was open for write, then erase contents */
|
||||
if ((file->f_mode & FMODE_WRITE) &&
|
||||
(file->f_flags & O_TRUNC)) {
|
||||
if (tc->cpu == RING_BUFFER_ALL_CPUS)
|
||||
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
|
||||
int cpu = tracing_get_cpu(inode);
|
||||
|
||||
if (cpu == RING_BUFFER_ALL_CPUS)
|
||||
tracing_reset_online_cpus(&tr->trace_buffer);
|
||||
else
|
||||
tracing_reset(&tr->trace_buffer, tc->cpu);
|
||||
tracing_reset(&tr->trace_buffer, cpu);
|
||||
}
|
||||
|
||||
if (file->f_mode & FMODE_READ) {
|
||||
iter = __tracing_open(tr, tc, inode, file, false);
|
||||
iter = __tracing_open(inode, file, false);
|
||||
if (IS_ERR(iter))
|
||||
ret = PTR_ERR(iter);
|
||||
else if (trace_flags & TRACE_ITER_LATENCY_FMT)
|
||||
@@ -3447,6 +3428,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
|
||||
static int tracing_trace_options_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct trace_array *tr = inode->i_private;
|
||||
int ret;
|
||||
|
||||
if (tracing_disabled)
|
||||
return -ENODEV;
|
||||
@@ -3454,7 +3436,11 @@ static int tracing_trace_options_open(struct inode *inode, struct file *file)
|
||||
if (trace_array_get(tr) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
return single_open(file, tracing_trace_options_show, inode->i_private);
|
||||
ret = single_open(file, tracing_trace_options_show, inode->i_private);
|
||||
if (ret < 0)
|
||||
trace_array_put(tr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations tracing_iter_fops = {
|
||||
@@ -3537,14 +3523,14 @@ static const char readme_msg[] =
|
||||
"\n snapshot\t\t- Like 'trace' but shows the content of the static snapshot buffer\n"
|
||||
"\t\t\t Read the contents for more information\n"
|
||||
#endif
|
||||
#ifdef CONFIG_STACKTRACE
|
||||
#ifdef CONFIG_STACK_TRACER
|
||||
" stack_trace\t\t- Shows the max stack trace when active\n"
|
||||
" stack_max_size\t- Shows current max stack size that was traced\n"
|
||||
"\t\t\t Write into this file to reset the max size (trigger a new trace)\n"
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
" stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace traces\n"
|
||||
#endif
|
||||
#endif /* CONFIG_STACKTRACE */
|
||||
#endif /* CONFIG_STACK_TRACER */
|
||||
;
|
||||
|
||||
static ssize_t
|
||||
@@ -3941,8 +3927,7 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf,
|
||||
|
||||
static int tracing_open_pipe(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct trace_cpu *tc = inode->i_private;
|
||||
struct trace_array *tr = tc->tr;
|
||||
struct trace_array *tr = inode->i_private;
|
||||
struct trace_iterator *iter;
|
||||
int ret = 0;
|
||||
|
||||
@@ -3958,6 +3943,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
|
||||
iter = kzalloc(sizeof(*iter), GFP_KERNEL);
|
||||
if (!iter) {
|
||||
ret = -ENOMEM;
|
||||
__trace_array_put(tr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -3987,9 +3973,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
|
||||
if (trace_clocks[tr->clock_id].in_ns)
|
||||
iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
|
||||
|
||||
iter->cpu_file = tc->cpu;
|
||||
iter->tr = tc->tr;
|
||||
iter->trace_buffer = &tc->tr->trace_buffer;
|
||||
iter->tr = tr;
|
||||
iter->trace_buffer = &tr->trace_buffer;
|
||||
iter->cpu_file = tracing_get_cpu(inode);
|
||||
mutex_init(&iter->mutex);
|
||||
filp->private_data = iter;
|
||||
|
||||
@@ -4012,8 +3998,7 @@ fail:
|
||||
static int tracing_release_pipe(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct trace_iterator *iter = file->private_data;
|
||||
struct trace_cpu *tc = inode->i_private;
|
||||
struct trace_array *tr = tc->tr;
|
||||
struct trace_array *tr = inode->i_private;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
|
||||
@@ -4166,6 +4151,7 @@ waitagain:
|
||||
memset(&iter->seq, 0,
|
||||
sizeof(struct trace_iterator) -
|
||||
offsetof(struct trace_iterator, seq));
|
||||
cpumask_clear(iter->started);
|
||||
iter->pos = -1;
|
||||
|
||||
trace_event_read_lock();
|
||||
@@ -4366,15 +4352,16 @@ static ssize_t
|
||||
tracing_entries_read(struct file *filp, char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
struct trace_cpu *tc = filp->private_data;
|
||||
struct trace_array *tr = tc->tr;
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct trace_array *tr = inode->i_private;
|
||||
int cpu = tracing_get_cpu(inode);
|
||||
char buf[64];
|
||||
int r = 0;
|
||||
ssize_t ret;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
|
||||
if (tc->cpu == RING_BUFFER_ALL_CPUS) {
|
||||
if (cpu == RING_BUFFER_ALL_CPUS) {
|
||||
int cpu, buf_size_same;
|
||||
unsigned long size;
|
||||
|
||||
@@ -4401,7 +4388,7 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
|
||||
} else
|
||||
r = sprintf(buf, "X\n");
|
||||
} else
|
||||
r = sprintf(buf, "%lu\n", per_cpu_ptr(tr->trace_buffer.data, tc->cpu)->entries >> 10);
|
||||
r = sprintf(buf, "%lu\n", per_cpu_ptr(tr->trace_buffer.data, cpu)->entries >> 10);
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
@@ -4413,7 +4400,8 @@ static ssize_t
|
||||
tracing_entries_write(struct file *filp, const char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
struct trace_cpu *tc = filp->private_data;
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct trace_array *tr = inode->i_private;
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
@@ -4427,8 +4415,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
|
||||
|
||||
/* value is in KB */
|
||||
val <<= 10;
|
||||
|
||||
ret = tracing_resize_ring_buffer(tc->tr, val, tc->cpu);
|
||||
ret = tracing_resize_ring_buffer(tr, val, tracing_get_cpu(inode));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -4482,7 +4469,7 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
|
||||
|
||||
/* disable tracing ? */
|
||||
if (trace_flags & TRACE_ITER_STOP_ON_FREE)
|
||||
tracing_off();
|
||||
tracer_tracing_off(tr);
|
||||
/* resize the ring buffer to 0 */
|
||||
tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
|
||||
|
||||
@@ -4647,12 +4634,12 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
|
||||
* New clock may not be consistent with the previous clock.
|
||||
* Reset the buffer so that it doesn't have incomparable timestamps.
|
||||
*/
|
||||
tracing_reset_online_cpus(&global_trace.trace_buffer);
|
||||
tracing_reset_online_cpus(&tr->trace_buffer);
|
||||
|
||||
#ifdef CONFIG_TRACER_MAX_TRACE
|
||||
if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer)
|
||||
ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func);
|
||||
tracing_reset_online_cpus(&global_trace.max_buffer);
|
||||
tracing_reset_online_cpus(&tr->max_buffer);
|
||||
#endif
|
||||
|
||||
mutex_unlock(&trace_types_lock);
|
||||
@@ -4689,8 +4676,7 @@ struct ftrace_buffer_info {
|
||||
#ifdef CONFIG_TRACER_SNAPSHOT
|
||||
static int tracing_snapshot_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct trace_cpu *tc = inode->i_private;
|
||||
struct trace_array *tr = tc->tr;
|
||||
struct trace_array *tr = inode->i_private;
|
||||
struct trace_iterator *iter;
|
||||
struct seq_file *m;
|
||||
int ret = 0;
|
||||
@@ -4699,26 +4685,29 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
|
||||
return -ENODEV;
|
||||
|
||||
if (file->f_mode & FMODE_READ) {
|
||||
iter = __tracing_open(tr, tc, inode, file, true);
|
||||
iter = __tracing_open(inode, file, true);
|
||||
if (IS_ERR(iter))
|
||||
ret = PTR_ERR(iter);
|
||||
} else {
|
||||
/* Writes still need the seq_file to hold the private data */
|
||||
ret = -ENOMEM;
|
||||
m = kzalloc(sizeof(*m), GFP_KERNEL);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
goto out;
|
||||
iter = kzalloc(sizeof(*iter), GFP_KERNEL);
|
||||
if (!iter) {
|
||||
kfree(m);
|
||||
return -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
iter->tr = tr;
|
||||
iter->trace_buffer = &tc->tr->max_buffer;
|
||||
iter->cpu_file = tc->cpu;
|
||||
iter->trace_buffer = &tr->max_buffer;
|
||||
iter->cpu_file = tracing_get_cpu(inode);
|
||||
m->private = iter;
|
||||
file->private_data = m;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret < 0)
|
||||
trace_array_put(tr);
|
||||
|
||||
@@ -4873,11 +4862,11 @@ static const struct file_operations tracing_pipe_fops = {
|
||||
};
|
||||
|
||||
static const struct file_operations tracing_entries_fops = {
|
||||
.open = tracing_open_generic_tc,
|
||||
.open = tracing_open_generic_tr,
|
||||
.read = tracing_entries_read,
|
||||
.write = tracing_entries_write,
|
||||
.llseek = generic_file_llseek,
|
||||
.release = tracing_release_generic_tc,
|
||||
.release = tracing_release_generic_tr,
|
||||
};
|
||||
|
||||
static const struct file_operations tracing_total_entries_fops = {
|
||||
@@ -4929,8 +4918,7 @@ static const struct file_operations snapshot_raw_fops = {
|
||||
|
||||
static int tracing_buffers_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct trace_cpu *tc = inode->i_private;
|
||||
struct trace_array *tr = tc->tr;
|
||||
struct trace_array *tr = inode->i_private;
|
||||
struct ftrace_buffer_info *info;
|
||||
int ret;
|
||||
|
||||
@@ -4948,10 +4936,8 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
|
||||
tr->ref++;
|
||||
|
||||
info->iter.tr = tr;
|
||||
info->iter.cpu_file = tc->cpu;
|
||||
info->iter.cpu_file = tracing_get_cpu(inode);
|
||||
info->iter.trace = tr->current_trace;
|
||||
info->iter.trace_buffer = &tr->trace_buffer;
|
||||
info->spare = NULL;
|
||||
@@ -5268,14 +5254,14 @@ static ssize_t
|
||||
tracing_stats_read(struct file *filp, char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct trace_cpu *tc = filp->private_data;
|
||||
struct trace_array *tr = tc->tr;
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct trace_array *tr = inode->i_private;
|
||||
struct trace_buffer *trace_buf = &tr->trace_buffer;
|
||||
int cpu = tracing_get_cpu(inode);
|
||||
struct trace_seq *s;
|
||||
unsigned long cnt;
|
||||
unsigned long long t;
|
||||
unsigned long usec_rem;
|
||||
int cpu = tc->cpu;
|
||||
|
||||
s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (!s)
|
||||
@@ -5328,9 +5314,10 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
|
||||
}
|
||||
|
||||
static const struct file_operations tracing_stats_fops = {
|
||||
.open = tracing_open_generic,
|
||||
.open = tracing_open_generic_tr,
|
||||
.read = tracing_stats_read,
|
||||
.llseek = generic_file_llseek,
|
||||
.release = tracing_release_generic_tr,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
@@ -5519,10 +5506,20 @@ static struct dentry *tracing_dentry_percpu(struct trace_array *tr, int cpu)
|
||||
return tr->percpu_dir;
|
||||
}
|
||||
|
||||
static struct dentry *
|
||||
trace_create_cpu_file(const char *name, umode_t mode, struct dentry *parent,
|
||||
void *data, long cpu, const struct file_operations *fops)
|
||||
{
|
||||
struct dentry *ret = trace_create_file(name, mode, parent, data, fops);
|
||||
|
||||
if (ret) /* See tracing_get_cpu() */
|
||||
ret->d_inode->i_cdev = (void *)(cpu + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
|
||||
{
|
||||
struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
|
||||
struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
|
||||
struct dentry *d_cpu;
|
||||
char cpu_dir[30]; /* 30 characters should be more than enough */
|
||||
@@ -5538,28 +5535,28 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
|
||||
}
|
||||
|
||||
/* per cpu trace_pipe */
|
||||
trace_create_file("trace_pipe", 0444, d_cpu,
|
||||
(void *)&data->trace_cpu, &tracing_pipe_fops);
|
||||
trace_create_cpu_file("trace_pipe", 0444, d_cpu,
|
||||
tr, cpu, &tracing_pipe_fops);
|
||||
|
||||
/* per cpu trace */
|
||||
trace_create_file("trace", 0644, d_cpu,
|
||||
(void *)&data->trace_cpu, &tracing_fops);
|
||||
trace_create_cpu_file("trace", 0644, d_cpu,
|
||||
tr, cpu, &tracing_fops);
|
||||
|
||||
trace_create_file("trace_pipe_raw", 0444, d_cpu,
|
||||
(void *)&data->trace_cpu, &tracing_buffers_fops);
|
||||
trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu,
|
||||
tr, cpu, &tracing_buffers_fops);
|
||||
|
||||
trace_create_file("stats", 0444, d_cpu,
|
||||
(void *)&data->trace_cpu, &tracing_stats_fops);
|
||||
trace_create_cpu_file("stats", 0444, d_cpu,
|
||||
tr, cpu, &tracing_stats_fops);
|
||||
|
||||
trace_create_file("buffer_size_kb", 0444, d_cpu,
|
||||
(void *)&data->trace_cpu, &tracing_entries_fops);
|
||||
trace_create_cpu_file("buffer_size_kb", 0444, d_cpu,
|
||||
tr, cpu, &tracing_entries_fops);
|
||||
|
||||
#ifdef CONFIG_TRACER_SNAPSHOT
|
||||
trace_create_file("snapshot", 0644, d_cpu,
|
||||
(void *)&data->trace_cpu, &snapshot_fops);
|
||||
trace_create_cpu_file("snapshot", 0644, d_cpu,
|
||||
tr, cpu, &snapshot_fops);
|
||||
|
||||
trace_create_file("snapshot_raw", 0444, d_cpu,
|
||||
(void *)&data->trace_cpu, &snapshot_raw_fops);
|
||||
trace_create_cpu_file("snapshot_raw", 0444, d_cpu,
|
||||
tr, cpu, &snapshot_raw_fops);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5868,17 +5865,6 @@ struct dentry *trace_instance_dir;
|
||||
static void
|
||||
init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer);
|
||||
|
||||
static void init_trace_buffers(struct trace_array *tr, struct trace_buffer *buf)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_tracing_cpu(cpu) {
|
||||
memset(per_cpu_ptr(buf->data, cpu), 0, sizeof(struct trace_array_cpu));
|
||||
per_cpu_ptr(buf->data, cpu)->trace_cpu.cpu = cpu;
|
||||
per_cpu_ptr(buf->data, cpu)->trace_cpu.tr = tr;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size)
|
||||
{
|
||||
@@ -5896,8 +5882,6 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
init_trace_buffers(tr, buf);
|
||||
|
||||
/* Allocate the first page for all buffers */
|
||||
set_buffer_entries(&tr->trace_buffer,
|
||||
ring_buffer_size(tr->trace_buffer.buffer, 0));
|
||||
@@ -5964,17 +5948,15 @@ static int new_instance_create(const char *name)
|
||||
if (allocate_trace_buffers(tr, trace_buf_size) < 0)
|
||||
goto out_free_tr;
|
||||
|
||||
/* Holder for file callbacks */
|
||||
tr->trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
|
||||
tr->trace_cpu.tr = tr;
|
||||
|
||||
tr->dir = debugfs_create_dir(name, trace_instance_dir);
|
||||
if (!tr->dir)
|
||||
goto out_free_tr;
|
||||
|
||||
ret = event_trace_add_tracer(tr->dir, tr);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
debugfs_remove_recursive(tr->dir);
|
||||
goto out_free_tr;
|
||||
}
|
||||
|
||||
init_tracer_debugfs(tr, tr->dir);
|
||||
|
||||
@@ -6120,13 +6102,13 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
|
||||
tr, &tracing_iter_fops);
|
||||
|
||||
trace_create_file("trace", 0644, d_tracer,
|
||||
(void *)&tr->trace_cpu, &tracing_fops);
|
||||
tr, &tracing_fops);
|
||||
|
||||
trace_create_file("trace_pipe", 0444, d_tracer,
|
||||
(void *)&tr->trace_cpu, &tracing_pipe_fops);
|
||||
tr, &tracing_pipe_fops);
|
||||
|
||||
trace_create_file("buffer_size_kb", 0644, d_tracer,
|
||||
(void *)&tr->trace_cpu, &tracing_entries_fops);
|
||||
tr, &tracing_entries_fops);
|
||||
|
||||
trace_create_file("buffer_total_size_kb", 0444, d_tracer,
|
||||
tr, &tracing_total_entries_fops);
|
||||
@@ -6141,11 +6123,11 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
|
||||
&trace_clock_fops);
|
||||
|
||||
trace_create_file("tracing_on", 0644, d_tracer,
|
||||
tr, &rb_simple_fops);
|
||||
tr, &rb_simple_fops);
|
||||
|
||||
#ifdef CONFIG_TRACER_SNAPSHOT
|
||||
trace_create_file("snapshot", 0644, d_tracer,
|
||||
(void *)&tr->trace_cpu, &snapshot_fops);
|
||||
tr, &snapshot_fops);
|
||||
#endif
|
||||
|
||||
for_each_tracing_cpu(cpu)
|
||||
@@ -6439,10 +6421,6 @@ __init static int tracer_alloc_buffers(void)
|
||||
|
||||
global_trace.flags = TRACE_ARRAY_FL_GLOBAL;
|
||||
|
||||
/* Holder for file callbacks */
|
||||
global_trace.trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
|
||||
global_trace.trace_cpu.tr = &global_trace;
|
||||
|
||||
INIT_LIST_HEAD(&global_trace.systems);
|
||||
INIT_LIST_HEAD(&global_trace.events);
|
||||
list_add(&global_trace.list, &ftrace_trace_arrays);
|
||||
|
||||
@@ -130,19 +130,12 @@ enum trace_flag_type {
|
||||
|
||||
struct trace_array;
|
||||
|
||||
struct trace_cpu {
|
||||
struct trace_array *tr;
|
||||
struct dentry *dir;
|
||||
int cpu;
|
||||
};
|
||||
|
||||
/*
|
||||
* The CPU trace array - it consists of thousands of trace entries
|
||||
* plus some other descriptor data: (for example which task started
|
||||
* the trace, etc.)
|
||||
*/
|
||||
struct trace_array_cpu {
|
||||
struct trace_cpu trace_cpu;
|
||||
atomic_t disabled;
|
||||
void *buffer_page; /* ring buffer spare */
|
||||
|
||||
@@ -196,7 +189,6 @@ struct trace_array {
|
||||
bool allocated_snapshot;
|
||||
#endif
|
||||
int buffer_disabled;
|
||||
struct trace_cpu trace_cpu; /* place holder */
|
||||
#ifdef CONFIG_FTRACE_SYSCALLS
|
||||
int sys_refcount_enter;
|
||||
int sys_refcount_exit;
|
||||
@@ -214,7 +206,6 @@ struct trace_array {
|
||||
struct dentry *event_dir;
|
||||
struct list_head systems;
|
||||
struct list_head events;
|
||||
struct task_struct *waiter;
|
||||
int ref;
|
||||
};
|
||||
|
||||
@@ -680,6 +671,15 @@ extern int trace_selftest_startup_sched_switch(struct tracer *trace,
|
||||
struct trace_array *tr);
|
||||
extern int trace_selftest_startup_branch(struct tracer *trace,
|
||||
struct trace_array *tr);
|
||||
/*
|
||||
* Tracer data references selftest functions that only occur
|
||||
* on boot up. These can be __init functions. Thus, when selftests
|
||||
* are enabled, then the tracers need to reference __init functions.
|
||||
*/
|
||||
#define __tracer_data __refdata
|
||||
#else
|
||||
/* Tracers are seldom changed. Optimize when selftests are disabled. */
|
||||
#define __tracer_data __read_mostly
|
||||
#endif /* CONFIG_FTRACE_STARTUP_TEST */
|
||||
|
||||
extern void *head_page(struct trace_array_cpu *data);
|
||||
|
||||
@@ -236,6 +236,10 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
|
||||
|
||||
BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long));
|
||||
|
||||
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
|
||||
"perf buffer not large enough"))
|
||||
return NULL;
|
||||
|
||||
pc = preempt_count();
|
||||
|
||||
*rctxp = perf_swevent_get_recursion_context();
|
||||
@@ -266,6 +270,10 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip,
|
||||
struct pt_regs regs;
|
||||
int rctx;
|
||||
|
||||
head = this_cpu_ptr(event_function.perf_events);
|
||||
if (hlist_empty(head))
|
||||
return;
|
||||
|
||||
#define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \
|
||||
sizeof(u64)) - sizeof(u32))
|
||||
|
||||
@@ -279,8 +287,6 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip,
|
||||
|
||||
entry->ip = ip;
|
||||
entry->parent_ip = parent_ip;
|
||||
|
||||
head = this_cpu_ptr(event_function.perf_events);
|
||||
perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0,
|
||||
1, ®s, head, NULL);
|
||||
|
||||
|
||||
+171
-125
@@ -409,33 +409,42 @@ static void put_system(struct ftrace_subsystem_dir *dir)
|
||||
mutex_unlock(&event_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open and update trace_array ref count.
|
||||
* Must have the current trace_array passed to it.
|
||||
*/
|
||||
static int tracing_open_generic_file(struct inode *inode, struct file *filp)
|
||||
static void remove_subsystem(struct ftrace_subsystem_dir *dir)
|
||||
{
|
||||
struct ftrace_event_file *file = inode->i_private;
|
||||
struct trace_array *tr = file->tr;
|
||||
int ret;
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
if (trace_array_get(tr) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
ret = tracing_open_generic(inode, filp);
|
||||
if (ret < 0)
|
||||
trace_array_put(tr);
|
||||
return ret;
|
||||
if (!--dir->nr_events) {
|
||||
debugfs_remove_recursive(dir->entry);
|
||||
list_del(&dir->list);
|
||||
__put_system_dir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
static int tracing_release_generic_file(struct inode *inode, struct file *filp)
|
||||
static void *event_file_data(struct file *filp)
|
||||
{
|
||||
struct ftrace_event_file *file = inode->i_private;
|
||||
struct trace_array *tr = file->tr;
|
||||
return ACCESS_ONCE(file_inode(filp)->i_private);
|
||||
}
|
||||
|
||||
trace_array_put(tr);
|
||||
static void remove_event_file_dir(struct ftrace_event_file *file)
|
||||
{
|
||||
struct dentry *dir = file->dir;
|
||||
struct dentry *child;
|
||||
|
||||
return 0;
|
||||
if (dir) {
|
||||
spin_lock(&dir->d_lock); /* probably unneeded */
|
||||
list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
|
||||
if (child->d_inode) /* probably unneeded */
|
||||
child->d_inode->i_private = NULL;
|
||||
}
|
||||
spin_unlock(&dir->d_lock);
|
||||
|
||||
debugfs_remove_recursive(dir);
|
||||
}
|
||||
|
||||
list_del(&file->list);
|
||||
remove_subsystem(file->system);
|
||||
kmem_cache_free(file_cachep, file);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -679,15 +688,25 @@ static ssize_t
|
||||
event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct ftrace_event_file *file = filp->private_data;
|
||||
struct ftrace_event_file *file;
|
||||
unsigned long flags;
|
||||
char buf[4] = "0";
|
||||
|
||||
if (file->flags & FTRACE_EVENT_FL_ENABLED &&
|
||||
!(file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
|
||||
mutex_lock(&event_mutex);
|
||||
file = event_file_data(filp);
|
||||
if (likely(file))
|
||||
flags = file->flags;
|
||||
mutex_unlock(&event_mutex);
|
||||
|
||||
if (!file)
|
||||
return -ENODEV;
|
||||
|
||||
if (flags & FTRACE_EVENT_FL_ENABLED &&
|
||||
!(flags & FTRACE_EVENT_FL_SOFT_DISABLED))
|
||||
strcpy(buf, "1");
|
||||
|
||||
if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED ||
|
||||
file->flags & FTRACE_EVENT_FL_SOFT_MODE)
|
||||
if (flags & FTRACE_EVENT_FL_SOFT_DISABLED ||
|
||||
flags & FTRACE_EVENT_FL_SOFT_MODE)
|
||||
strcat(buf, "*");
|
||||
|
||||
strcat(buf, "\n");
|
||||
@@ -699,13 +718,10 @@ static ssize_t
|
||||
event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct ftrace_event_file *file = filp->private_data;
|
||||
struct ftrace_event_file *file;
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
if (!file)
|
||||
return -EINVAL;
|
||||
|
||||
ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -717,8 +733,11 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
|
||||
switch (val) {
|
||||
case 0:
|
||||
case 1:
|
||||
ret = -ENODEV;
|
||||
mutex_lock(&event_mutex);
|
||||
ret = ftrace_event_enable_disable(file, val);
|
||||
file = event_file_data(filp);
|
||||
if (likely(file))
|
||||
ret = ftrace_event_enable_disable(file, val);
|
||||
mutex_unlock(&event_mutex);
|
||||
break;
|
||||
|
||||
@@ -825,65 +844,39 @@ enum {
|
||||
|
||||
static void *f_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
struct ftrace_event_call *call = m->private;
|
||||
struct ftrace_event_field *field;
|
||||
struct ftrace_event_call *call = event_file_data(m->private);
|
||||
struct list_head *common_head = &ftrace_common_fields;
|
||||
struct list_head *head = trace_get_fields(call);
|
||||
struct list_head *node = v;
|
||||
|
||||
(*pos)++;
|
||||
|
||||
switch ((unsigned long)v) {
|
||||
case FORMAT_HEADER:
|
||||
if (unlikely(list_empty(common_head)))
|
||||
return NULL;
|
||||
|
||||
field = list_entry(common_head->prev,
|
||||
struct ftrace_event_field, link);
|
||||
return field;
|
||||
node = common_head;
|
||||
break;
|
||||
|
||||
case FORMAT_FIELD_SEPERATOR:
|
||||
if (unlikely(list_empty(head)))
|
||||
return NULL;
|
||||
|
||||
field = list_entry(head->prev, struct ftrace_event_field, link);
|
||||
return field;
|
||||
node = head;
|
||||
break;
|
||||
|
||||
case FORMAT_PRINTFMT:
|
||||
/* all done */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
field = v;
|
||||
if (field->link.prev == common_head)
|
||||
node = node->prev;
|
||||
if (node == common_head)
|
||||
return (void *)FORMAT_FIELD_SEPERATOR;
|
||||
else if (field->link.prev == head)
|
||||
else if (node == head)
|
||||
return (void *)FORMAT_PRINTFMT;
|
||||
|
||||
field = list_entry(field->link.prev, struct ftrace_event_field, link);
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
static void *f_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
loff_t l = 0;
|
||||
void *p;
|
||||
|
||||
/* Start by showing the header */
|
||||
if (!*pos)
|
||||
return (void *)FORMAT_HEADER;
|
||||
|
||||
p = (void *)FORMAT_HEADER;
|
||||
do {
|
||||
p = f_next(m, p, &l);
|
||||
} while (p && l < *pos);
|
||||
|
||||
return p;
|
||||
else
|
||||
return node;
|
||||
}
|
||||
|
||||
static int f_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct ftrace_event_call *call = m->private;
|
||||
struct ftrace_event_call *call = event_file_data(m->private);
|
||||
struct ftrace_event_field *field;
|
||||
const char *array_descriptor;
|
||||
|
||||
@@ -904,8 +897,7 @@ static int f_show(struct seq_file *m, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
field = v;
|
||||
|
||||
field = list_entry(v, struct ftrace_event_field, link);
|
||||
/*
|
||||
* Smartly shows the array type(except dynamic array).
|
||||
* Normal:
|
||||
@@ -932,8 +924,25 @@ static int f_show(struct seq_file *m, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *f_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
void *p = (void *)FORMAT_HEADER;
|
||||
loff_t l = 0;
|
||||
|
||||
/* ->stop() is called even if ->start() fails */
|
||||
mutex_lock(&event_mutex);
|
||||
if (!event_file_data(m->private))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
while (l < *pos && p)
|
||||
p = f_next(m, p, &l);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void f_stop(struct seq_file *m, void *p)
|
||||
{
|
||||
mutex_unlock(&event_mutex);
|
||||
}
|
||||
|
||||
static const struct seq_operations trace_format_seq_ops = {
|
||||
@@ -945,7 +954,6 @@ static const struct seq_operations trace_format_seq_ops = {
|
||||
|
||||
static int trace_format_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ftrace_event_call *call = inode->i_private;
|
||||
struct seq_file *m;
|
||||
int ret;
|
||||
|
||||
@@ -954,7 +962,7 @@ static int trace_format_open(struct inode *inode, struct file *file)
|
||||
return ret;
|
||||
|
||||
m = file->private_data;
|
||||
m->private = call;
|
||||
m->private = file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -962,45 +970,47 @@ static int trace_format_open(struct inode *inode, struct file *file)
|
||||
static ssize_t
|
||||
event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
|
||||
{
|
||||
struct ftrace_event_call *call = filp->private_data;
|
||||
struct trace_seq *s;
|
||||
int r;
|
||||
int id = (long)event_file_data(filp);
|
||||
char buf[32];
|
||||
int len;
|
||||
|
||||
if (*ppos)
|
||||
return 0;
|
||||
|
||||
s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
if (unlikely(!id))
|
||||
return -ENODEV;
|
||||
|
||||
trace_seq_init(s);
|
||||
trace_seq_printf(s, "%d\n", call->event.type);
|
||||
len = sprintf(buf, "%d\n", id);
|
||||
|
||||
r = simple_read_from_buffer(ubuf, cnt, ppos,
|
||||
s->buffer, s->len);
|
||||
kfree(s);
|
||||
return r;
|
||||
return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct ftrace_event_call *call = filp->private_data;
|
||||
struct ftrace_event_call *call;
|
||||
struct trace_seq *s;
|
||||
int r;
|
||||
int r = -ENODEV;
|
||||
|
||||
if (*ppos)
|
||||
return 0;
|
||||
|
||||
s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
trace_seq_init(s);
|
||||
|
||||
print_event_filter(call, s);
|
||||
r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
|
||||
mutex_lock(&event_mutex);
|
||||
call = event_file_data(filp);
|
||||
if (call)
|
||||
print_event_filter(call, s);
|
||||
mutex_unlock(&event_mutex);
|
||||
|
||||
if (call)
|
||||
r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
|
||||
|
||||
kfree(s);
|
||||
|
||||
@@ -1011,9 +1021,9 @@ static ssize_t
|
||||
event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct ftrace_event_call *call = filp->private_data;
|
||||
struct ftrace_event_call *call;
|
||||
char *buf;
|
||||
int err;
|
||||
int err = -ENODEV;
|
||||
|
||||
if (cnt >= PAGE_SIZE)
|
||||
return -EINVAL;
|
||||
@@ -1028,7 +1038,12 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
|
||||
}
|
||||
buf[cnt] = '\0';
|
||||
|
||||
err = apply_event_filter(call, buf);
|
||||
mutex_lock(&event_mutex);
|
||||
call = event_file_data(filp);
|
||||
if (call)
|
||||
err = apply_event_filter(call, buf);
|
||||
mutex_unlock(&event_mutex);
|
||||
|
||||
free_page((unsigned long) buf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -1218,6 +1233,7 @@ show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
|
||||
|
||||
static int ftrace_event_avail_open(struct inode *inode, struct file *file);
|
||||
static int ftrace_event_set_open(struct inode *inode, struct file *file);
|
||||
static int ftrace_event_release(struct inode *inode, struct file *file);
|
||||
|
||||
static const struct seq_operations show_event_seq_ops = {
|
||||
.start = t_start,
|
||||
@@ -1245,14 +1261,13 @@ static const struct file_operations ftrace_set_event_fops = {
|
||||
.read = seq_read,
|
||||
.write = ftrace_event_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
.release = ftrace_event_release,
|
||||
};
|
||||
|
||||
static const struct file_operations ftrace_enable_fops = {
|
||||
.open = tracing_open_generic_file,
|
||||
.open = tracing_open_generic,
|
||||
.read = event_enable_read,
|
||||
.write = event_enable_write,
|
||||
.release = tracing_release_generic_file,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
@@ -1264,7 +1279,6 @@ static const struct file_operations ftrace_event_format_fops = {
|
||||
};
|
||||
|
||||
static const struct file_operations ftrace_event_id_fops = {
|
||||
.open = tracing_open_generic,
|
||||
.read = event_id_read,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
@@ -1323,6 +1337,15 @@ ftrace_event_open(struct inode *inode, struct file *file,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ftrace_event_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct trace_array *tr = inode->i_private;
|
||||
|
||||
trace_array_put(tr);
|
||||
|
||||
return seq_release(inode, file);
|
||||
}
|
||||
|
||||
static int
|
||||
ftrace_event_avail_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
@@ -1336,12 +1359,19 @@ ftrace_event_set_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
const struct seq_operations *seq_ops = &show_set_event_seq_ops;
|
||||
struct trace_array *tr = inode->i_private;
|
||||
int ret;
|
||||
|
||||
if (trace_array_get(tr) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
if ((file->f_mode & FMODE_WRITE) &&
|
||||
(file->f_flags & O_TRUNC))
|
||||
ftrace_clear_events(tr);
|
||||
|
||||
return ftrace_event_open(inode, file, seq_ops);
|
||||
ret = ftrace_event_open(inode, file, seq_ops);
|
||||
if (ret < 0)
|
||||
trace_array_put(tr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct event_subsystem *
|
||||
@@ -1496,8 +1526,8 @@ event_create_dir(struct dentry *parent,
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
if (call->event.type && call->class->reg)
|
||||
trace_create_file("id", 0444, file->dir, call,
|
||||
id);
|
||||
trace_create_file("id", 0444, file->dir,
|
||||
(void *)(long)call->event.type, id);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1522,33 +1552,16 @@ event_create_dir(struct dentry *parent,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void remove_subsystem(struct ftrace_subsystem_dir *dir)
|
||||
{
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
if (!--dir->nr_events) {
|
||||
debugfs_remove_recursive(dir->entry);
|
||||
list_del(&dir->list);
|
||||
__put_system_dir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_event_from_tracers(struct ftrace_event_call *call)
|
||||
{
|
||||
struct ftrace_event_file *file;
|
||||
struct trace_array *tr;
|
||||
|
||||
do_for_each_event_file_safe(tr, file) {
|
||||
|
||||
if (file->event_call != call)
|
||||
continue;
|
||||
|
||||
list_del(&file->list);
|
||||
debugfs_remove_recursive(file->dir);
|
||||
remove_subsystem(file->system);
|
||||
kmem_cache_free(file_cachep, file);
|
||||
|
||||
remove_event_file_dir(file);
|
||||
/*
|
||||
* The do_for_each_event_file_safe() is
|
||||
* a double loop. After finding the call for this
|
||||
@@ -1700,16 +1713,53 @@ static void __trace_remove_event_call(struct ftrace_event_call *call)
|
||||
destroy_preds(call);
|
||||
}
|
||||
|
||||
/* Remove an event_call */
|
||||
void trace_remove_event_call(struct ftrace_event_call *call)
|
||||
static int probe_remove_event_call(struct ftrace_event_call *call)
|
||||
{
|
||||
struct trace_array *tr;
|
||||
struct ftrace_event_file *file;
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
if (call->perf_refcount)
|
||||
return -EBUSY;
|
||||
#endif
|
||||
do_for_each_event_file(tr, file) {
|
||||
if (file->event_call != call)
|
||||
continue;
|
||||
/*
|
||||
* We can't rely on ftrace_event_enable_disable(enable => 0)
|
||||
* we are going to do, FTRACE_EVENT_FL_SOFT_MODE can suppress
|
||||
* TRACE_REG_UNREGISTER.
|
||||
*/
|
||||
if (file->flags & FTRACE_EVENT_FL_ENABLED)
|
||||
return -EBUSY;
|
||||
/*
|
||||
* The do_for_each_event_file_safe() is
|
||||
* a double loop. After finding the call for this
|
||||
* trace_array, we use break to jump to the next
|
||||
* trace_array.
|
||||
*/
|
||||
break;
|
||||
} while_for_each_event_file();
|
||||
|
||||
__trace_remove_event_call(call);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove an event_call */
|
||||
int trace_remove_event_call(struct ftrace_event_call *call)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
mutex_lock(&event_mutex);
|
||||
down_write(&trace_event_sem);
|
||||
__trace_remove_event_call(call);
|
||||
ret = probe_remove_event_call(call);
|
||||
up_write(&trace_event_sem);
|
||||
mutex_unlock(&event_mutex);
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define for_each_event(event, start, end) \
|
||||
@@ -2278,12 +2328,8 @@ __trace_remove_event_dirs(struct trace_array *tr)
|
||||
{
|
||||
struct ftrace_event_file *file, *next;
|
||||
|
||||
list_for_each_entry_safe(file, next, &tr->events, list) {
|
||||
list_del(&file->list);
|
||||
debugfs_remove_recursive(file->dir);
|
||||
remove_subsystem(file->system);
|
||||
kmem_cache_free(file_cachep, file);
|
||||
}
|
||||
list_for_each_entry_safe(file, next, &tr->events, list)
|
||||
remove_event_file_dir(file);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -637,17 +637,15 @@ static void append_filter_err(struct filter_parse_state *ps,
|
||||
free_page((unsigned long) buf);
|
||||
}
|
||||
|
||||
/* caller must hold event_mutex */
|
||||
void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
|
||||
{
|
||||
struct event_filter *filter;
|
||||
struct event_filter *filter = call->filter;
|
||||
|
||||
mutex_lock(&event_mutex);
|
||||
filter = call->filter;
|
||||
if (filter && filter->filter_string)
|
||||
trace_seq_printf(s, "%s\n", filter->filter_string);
|
||||
else
|
||||
trace_seq_printf(s, "none\n");
|
||||
mutex_unlock(&event_mutex);
|
||||
trace_seq_puts(s, "none\n");
|
||||
}
|
||||
|
||||
void print_subsystem_event_filter(struct event_subsystem *system,
|
||||
@@ -660,7 +658,7 @@ void print_subsystem_event_filter(struct event_subsystem *system,
|
||||
if (filter && filter->filter_string)
|
||||
trace_seq_printf(s, "%s\n", filter->filter_string);
|
||||
else
|
||||
trace_seq_printf(s, DEFAULT_SYS_FILTER_MESSAGE "\n");
|
||||
trace_seq_puts(s, DEFAULT_SYS_FILTER_MESSAGE "\n");
|
||||
mutex_unlock(&event_mutex);
|
||||
}
|
||||
|
||||
@@ -1841,23 +1839,22 @@ static int create_system_filter(struct event_subsystem *system,
|
||||
return err;
|
||||
}
|
||||
|
||||
/* caller must hold event_mutex */
|
||||
int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
|
||||
{
|
||||
struct event_filter *filter;
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&event_mutex);
|
||||
int err;
|
||||
|
||||
if (!strcmp(strstrip(filter_string), "0")) {
|
||||
filter_disable(call);
|
||||
filter = call->filter;
|
||||
if (!filter)
|
||||
goto out_unlock;
|
||||
return 0;
|
||||
RCU_INIT_POINTER(call->filter, NULL);
|
||||
/* Make sure the filter is not being used */
|
||||
synchronize_sched();
|
||||
__free_filter(filter);
|
||||
goto out_unlock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = create_filter(call, filter_string, true, &filter);
|
||||
@@ -1884,8 +1881,6 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
|
||||
__free_filter(tmp);
|
||||
}
|
||||
}
|
||||
out_unlock:
|
||||
mutex_unlock(&event_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ static int func_set_flag(u32 old_flags, u32 bit, int set)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tracer function_trace __read_mostly =
|
||||
static struct tracer function_trace __tracer_data =
|
||||
{
|
||||
.name = "function",
|
||||
.init = function_trace_init,
|
||||
|
||||
@@ -446,7 +446,7 @@ print_graph_proc(struct trace_seq *s, pid_t pid)
|
||||
|
||||
/* First spaces to align center */
|
||||
for (i = 0; i < spaces / 2; i++) {
|
||||
ret = trace_seq_printf(s, " ");
|
||||
ret = trace_seq_putc(s, ' ');
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
@@ -457,7 +457,7 @@ print_graph_proc(struct trace_seq *s, pid_t pid)
|
||||
|
||||
/* Last spaces to align center */
|
||||
for (i = 0; i < spaces - (spaces / 2); i++) {
|
||||
ret = trace_seq_printf(s, " ");
|
||||
ret = trace_seq_putc(s, ' ');
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
@@ -503,7 +503,7 @@ verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
|
||||
------------------------------------------
|
||||
|
||||
*/
|
||||
ret = trace_seq_printf(s,
|
||||
ret = trace_seq_puts(s,
|
||||
" ------------------------------------------\n");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
@@ -516,7 +516,7 @@ verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
|
||||
if (ret == TRACE_TYPE_PARTIAL_LINE)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
ret = trace_seq_printf(s, " => ");
|
||||
ret = trace_seq_puts(s, " => ");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
@@ -524,7 +524,7 @@ verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
|
||||
if (ret == TRACE_TYPE_PARTIAL_LINE)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
ret = trace_seq_printf(s,
|
||||
ret = trace_seq_puts(s,
|
||||
"\n ------------------------------------------\n\n");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
@@ -645,7 +645,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
|
||||
ret = print_graph_proc(s, pid);
|
||||
if (ret == TRACE_TYPE_PARTIAL_LINE)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
ret = trace_seq_printf(s, " | ");
|
||||
ret = trace_seq_puts(s, " | ");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
@@ -657,9 +657,9 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
|
||||
return ret;
|
||||
|
||||
if (type == TRACE_GRAPH_ENT)
|
||||
ret = trace_seq_printf(s, "==========>");
|
||||
ret = trace_seq_puts(s, "==========>");
|
||||
else
|
||||
ret = trace_seq_printf(s, "<==========");
|
||||
ret = trace_seq_puts(s, "<==========");
|
||||
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
@@ -668,7 +668,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
|
||||
if (ret != TRACE_TYPE_HANDLED)
|
||||
return ret;
|
||||
|
||||
ret = trace_seq_printf(s, "\n");
|
||||
ret = trace_seq_putc(s, '\n');
|
||||
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
@@ -705,13 +705,13 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
|
||||
len += strlen(nsecs_str);
|
||||
}
|
||||
|
||||
ret = trace_seq_printf(s, " us ");
|
||||
ret = trace_seq_puts(s, " us ");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
/* Print remaining spaces to fit the row's width */
|
||||
for (i = len; i < 7; i++) {
|
||||
ret = trace_seq_printf(s, " ");
|
||||
ret = trace_seq_putc(s, ' ');
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
@@ -731,13 +731,13 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s,
|
||||
/* No real adata, just filling the column with spaces */
|
||||
switch (duration) {
|
||||
case DURATION_FILL_FULL:
|
||||
ret = trace_seq_printf(s, " | ");
|
||||
ret = trace_seq_puts(s, " | ");
|
||||
return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
|
||||
case DURATION_FILL_START:
|
||||
ret = trace_seq_printf(s, " ");
|
||||
ret = trace_seq_puts(s, " ");
|
||||
return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
|
||||
case DURATION_FILL_END:
|
||||
ret = trace_seq_printf(s, " |");
|
||||
ret = trace_seq_puts(s, " |");
|
||||
return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
|
||||
@@ -745,10 +745,10 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s,
|
||||
if (flags & TRACE_GRAPH_PRINT_OVERHEAD) {
|
||||
/* Duration exceeded 100 msecs */
|
||||
if (duration > 100000ULL)
|
||||
ret = trace_seq_printf(s, "! ");
|
||||
ret = trace_seq_puts(s, "! ");
|
||||
/* Duration exceeded 10 msecs */
|
||||
else if (duration > 10000ULL)
|
||||
ret = trace_seq_printf(s, "+ ");
|
||||
ret = trace_seq_puts(s, "+ ");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -757,7 +757,7 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s,
|
||||
* to fill out the space.
|
||||
*/
|
||||
if (ret == -1)
|
||||
ret = trace_seq_printf(s, " ");
|
||||
ret = trace_seq_puts(s, " ");
|
||||
|
||||
/* Catching here any failure happenned above */
|
||||
if (!ret)
|
||||
@@ -767,7 +767,7 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s,
|
||||
if (ret != TRACE_TYPE_HANDLED)
|
||||
return ret;
|
||||
|
||||
ret = trace_seq_printf(s, "| ");
|
||||
ret = trace_seq_puts(s, "| ");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
@@ -817,7 +817,7 @@ print_graph_entry_leaf(struct trace_iterator *iter,
|
||||
|
||||
/* Function */
|
||||
for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
|
||||
ret = trace_seq_printf(s, " ");
|
||||
ret = trace_seq_putc(s, ' ');
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
@@ -858,7 +858,7 @@ print_graph_entry_nested(struct trace_iterator *iter,
|
||||
|
||||
/* Function */
|
||||
for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
|
||||
ret = trace_seq_printf(s, " ");
|
||||
ret = trace_seq_putc(s, ' ');
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
@@ -917,7 +917,7 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
|
||||
if (ret == TRACE_TYPE_PARTIAL_LINE)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
ret = trace_seq_printf(s, " | ");
|
||||
ret = trace_seq_puts(s, " | ");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
@@ -1117,7 +1117,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
|
||||
|
||||
/* Closing brace */
|
||||
for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
|
||||
ret = trace_seq_printf(s, " ");
|
||||
ret = trace_seq_putc(s, ' ');
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
@@ -1129,7 +1129,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
|
||||
* belongs to, write out the function name.
|
||||
*/
|
||||
if (func_match) {
|
||||
ret = trace_seq_printf(s, "}\n");
|
||||
ret = trace_seq_puts(s, "}\n");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
} else {
|
||||
@@ -1179,13 +1179,13 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
|
||||
/* Indentation */
|
||||
if (depth > 0)
|
||||
for (i = 0; i < (depth + 1) * TRACE_GRAPH_INDENT; i++) {
|
||||
ret = trace_seq_printf(s, " ");
|
||||
ret = trace_seq_putc(s, ' ');
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
|
||||
/* The comment */
|
||||
ret = trace_seq_printf(s, "/* ");
|
||||
ret = trace_seq_puts(s, "/* ");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
@@ -1216,7 +1216,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
|
||||
s->len--;
|
||||
}
|
||||
|
||||
ret = trace_seq_printf(s, " */\n");
|
||||
ret = trace_seq_puts(s, " */\n");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
@@ -1448,7 +1448,7 @@ static struct trace_event graph_trace_ret_event = {
|
||||
.funcs = &graph_functions
|
||||
};
|
||||
|
||||
static struct tracer graph_trace __read_mostly = {
|
||||
static struct tracer graph_trace __tracer_data = {
|
||||
.name = "function_graph",
|
||||
.open = graph_trace_open,
|
||||
.pipe_open = graph_trace_open,
|
||||
|
||||
+32
-18
@@ -95,7 +95,7 @@ static __kprobes bool trace_probe_is_on_module(struct trace_probe *tp)
|
||||
}
|
||||
|
||||
static int register_probe_event(struct trace_probe *tp);
|
||||
static void unregister_probe_event(struct trace_probe *tp);
|
||||
static int unregister_probe_event(struct trace_probe *tp);
|
||||
|
||||
static DEFINE_MUTEX(probe_lock);
|
||||
static LIST_HEAD(probe_list);
|
||||
@@ -243,11 +243,11 @@ find_event_file_link(struct trace_probe *tp, struct ftrace_event_file *file)
|
||||
static int
|
||||
disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
|
||||
{
|
||||
struct event_file_link *link = NULL;
|
||||
int wait = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (file) {
|
||||
struct event_file_link *link;
|
||||
|
||||
link = find_event_file_link(tp, file);
|
||||
if (!link) {
|
||||
ret = -EINVAL;
|
||||
@@ -255,10 +255,7 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
|
||||
}
|
||||
|
||||
list_del_rcu(&link->list);
|
||||
/* synchronize with kprobe_trace_func/kretprobe_trace_func */
|
||||
synchronize_sched();
|
||||
kfree(link);
|
||||
|
||||
wait = 1;
|
||||
if (!list_empty(&tp->files))
|
||||
goto out;
|
||||
|
||||
@@ -271,8 +268,22 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file)
|
||||
disable_kretprobe(&tp->rp);
|
||||
else
|
||||
disable_kprobe(&tp->rp.kp);
|
||||
wait = 1;
|
||||
}
|
||||
out:
|
||||
if (wait) {
|
||||
/*
|
||||
* Synchronize with kprobe_trace_func/kretprobe_trace_func
|
||||
* to ensure disabled (all running handlers are finished).
|
||||
* This is not only for kfree(), but also the caller,
|
||||
* trace_remove_event_call() supposes it for releasing
|
||||
* event_call related objects, which will be accessed in
|
||||
* the kprobe_trace_func/kretprobe_trace_func.
|
||||
*/
|
||||
synchronize_sched();
|
||||
kfree(link); /* Ignored if link == NULL */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -340,9 +351,12 @@ static int unregister_trace_probe(struct trace_probe *tp)
|
||||
if (trace_probe_is_enabled(tp))
|
||||
return -EBUSY;
|
||||
|
||||
/* Will fail if probe is being used by ftrace or perf */
|
||||
if (unregister_probe_event(tp))
|
||||
return -EBUSY;
|
||||
|
||||
__unregister_trace_probe(tp);
|
||||
list_del(&tp->list);
|
||||
unregister_probe_event(tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -621,7 +635,9 @@ static int release_all_trace_probes(void)
|
||||
/* TODO: Use batch unregistration */
|
||||
while (!list_empty(&probe_list)) {
|
||||
tp = list_entry(probe_list.next, struct trace_probe, list);
|
||||
unregister_trace_probe(tp);
|
||||
ret = unregister_trace_probe(tp);
|
||||
if (ret)
|
||||
goto end;
|
||||
free_trace_probe(tp);
|
||||
}
|
||||
|
||||
@@ -1087,9 +1103,6 @@ kprobe_perf_func(struct trace_probe *tp, struct pt_regs *regs)
|
||||
__size = sizeof(*entry) + tp->size + dsize;
|
||||
size = ALIGN(__size + sizeof(u32), sizeof(u64));
|
||||
size -= sizeof(u32);
|
||||
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
|
||||
"profile buffer not large enough"))
|
||||
return;
|
||||
|
||||
entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
|
||||
if (!entry)
|
||||
@@ -1120,9 +1133,6 @@ kretprobe_perf_func(struct trace_probe *tp, struct kretprobe_instance *ri,
|
||||
__size = sizeof(*entry) + tp->size + dsize;
|
||||
size = ALIGN(__size + sizeof(u32), sizeof(u64));
|
||||
size -= sizeof(u32);
|
||||
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
|
||||
"profile buffer not large enough"))
|
||||
return;
|
||||
|
||||
entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
|
||||
if (!entry)
|
||||
@@ -1242,11 +1252,15 @@ static int register_probe_event(struct trace_probe *tp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void unregister_probe_event(struct trace_probe *tp)
|
||||
static int unregister_probe_event(struct trace_probe *tp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* tp->event is unregistered in trace_remove_event_call() */
|
||||
trace_remove_event_call(&tp->call);
|
||||
kfree(tp->call.print_fmt);
|
||||
ret = trace_remove_event_call(&tp->call);
|
||||
if (!ret)
|
||||
kfree(tp->call.print_fmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Make a debugfs interface for controlling probe points */
|
||||
|
||||
@@ -90,7 +90,7 @@ static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
|
||||
if (drv)
|
||||
ret += trace_seq_printf(s, " %s\n", drv->name);
|
||||
else
|
||||
ret += trace_seq_printf(s, " \n");
|
||||
ret += trace_seq_puts(s, " \n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ static void mmio_pipe_open(struct trace_iterator *iter)
|
||||
struct header_iter *hiter;
|
||||
struct trace_seq *s = &iter->seq;
|
||||
|
||||
trace_seq_printf(s, "VERSION 20070824\n");
|
||||
trace_seq_puts(s, "VERSION 20070824\n");
|
||||
|
||||
hiter = kzalloc(sizeof(*hiter), GFP_KERNEL);
|
||||
if (!hiter)
|
||||
@@ -209,7 +209,7 @@ static enum print_line_t mmio_print_rw(struct trace_iterator *iter)
|
||||
(rw->value >> 0) & 0xff, rw->pc, 0);
|
||||
break;
|
||||
default:
|
||||
ret = trace_seq_printf(s, "rw what?\n");
|
||||
ret = trace_seq_puts(s, "rw what?\n");
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
@@ -245,7 +245,7 @@ static enum print_line_t mmio_print_map(struct trace_iterator *iter)
|
||||
secs, usec_rem, m->map_id, 0UL, 0);
|
||||
break;
|
||||
default:
|
||||
ret = trace_seq_printf(s, "map what?\n");
|
||||
ret = trace_seq_puts(s, "map what?\n");
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
|
||||
@@ -78,7 +78,7 @@ enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)
|
||||
|
||||
trace_assign_type(field, entry);
|
||||
|
||||
ret = trace_seq_printf(s, "%s", field->buf);
|
||||
ret = trace_seq_puts(s, field->buf);
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
@@ -558,14 +558,14 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
|
||||
if (ret)
|
||||
ret = trace_seq_puts(s, "??");
|
||||
if (ret)
|
||||
ret = trace_seq_puts(s, "\n");
|
||||
ret = trace_seq_putc(s, '\n');
|
||||
continue;
|
||||
}
|
||||
if (!ret)
|
||||
break;
|
||||
if (ret)
|
||||
ret = seq_print_user_ip(s, mm, ip, sym_flags);
|
||||
ret = trace_seq_puts(s, "\n");
|
||||
ret = trace_seq_putc(s, '\n');
|
||||
}
|
||||
|
||||
if (mm)
|
||||
@@ -579,7 +579,7 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
|
||||
int ret;
|
||||
|
||||
if (!ip)
|
||||
return trace_seq_printf(s, "0");
|
||||
return trace_seq_putc(s, '0');
|
||||
|
||||
if (sym_flags & TRACE_ITER_SYM_OFFSET)
|
||||
ret = seq_print_sym_offset(s, "%s", ip);
|
||||
@@ -964,14 +964,14 @@ static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags,
|
||||
goto partial;
|
||||
|
||||
if ((flags & TRACE_ITER_PRINT_PARENT) && field->parent_ip) {
|
||||
if (!trace_seq_printf(s, " <-"))
|
||||
if (!trace_seq_puts(s, " <-"))
|
||||
goto partial;
|
||||
if (!seq_print_ip_sym(s,
|
||||
field->parent_ip,
|
||||
flags))
|
||||
goto partial;
|
||||
}
|
||||
if (!trace_seq_printf(s, "\n"))
|
||||
if (!trace_seq_putc(s, '\n'))
|
||||
goto partial;
|
||||
|
||||
return TRACE_TYPE_HANDLED;
|
||||
@@ -1210,7 +1210,7 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,
|
||||
|
||||
if (!seq_print_ip_sym(s, *p, flags))
|
||||
goto partial;
|
||||
if (!trace_seq_puts(s, "\n"))
|
||||
if (!trace_seq_putc(s, '\n'))
|
||||
goto partial;
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags,
|
||||
entry = syscall_nr_to_meta(syscall);
|
||||
|
||||
if (!entry) {
|
||||
trace_seq_printf(s, "\n");
|
||||
trace_seq_putc(s, '\n');
|
||||
return TRACE_TYPE_HANDLED;
|
||||
}
|
||||
|
||||
@@ -566,15 +566,15 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
|
||||
if (!sys_data)
|
||||
return;
|
||||
|
||||
head = this_cpu_ptr(sys_data->enter_event->perf_events);
|
||||
if (hlist_empty(head))
|
||||
return;
|
||||
|
||||
/* get the size after alignment with the u32 buffer size field */
|
||||
size = sizeof(unsigned long) * sys_data->nb_args + sizeof(*rec);
|
||||
size = ALIGN(size + sizeof(u32), sizeof(u64));
|
||||
size -= sizeof(u32);
|
||||
|
||||
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
|
||||
"perf buffer not large enough"))
|
||||
return;
|
||||
|
||||
rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size,
|
||||
sys_data->enter_event->event.type, regs, &rctx);
|
||||
if (!rec)
|
||||
@@ -583,8 +583,6 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
|
||||
rec->nr = syscall_nr;
|
||||
syscall_get_arguments(current, regs, 0, sys_data->nb_args,
|
||||
(unsigned long *)&rec->args);
|
||||
|
||||
head = this_cpu_ptr(sys_data->enter_event->perf_events);
|
||||
perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
|
||||
}
|
||||
|
||||
@@ -642,18 +640,14 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
|
||||
if (!sys_data)
|
||||
return;
|
||||
|
||||
head = this_cpu_ptr(sys_data->exit_event->perf_events);
|
||||
if (hlist_empty(head))
|
||||
return;
|
||||
|
||||
/* We can probably do that at build time */
|
||||
size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64));
|
||||
size -= sizeof(u32);
|
||||
|
||||
/*
|
||||
* Impossible, but be paranoid with the future
|
||||
* How to put this check outside runtime?
|
||||
*/
|
||||
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
|
||||
"exit event has grown above perf buffer size"))
|
||||
return;
|
||||
|
||||
rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size,
|
||||
sys_data->exit_event->event.type, regs, &rctx);
|
||||
if (!rec)
|
||||
@@ -661,8 +655,6 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
|
||||
|
||||
rec->nr = syscall_nr;
|
||||
rec->ret = syscall_get_return_value(current, regs);
|
||||
|
||||
head = this_cpu_ptr(sys_data->exit_event->perf_events);
|
||||
perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
|
||||
}
|
||||
|
||||
|
||||
+38
-15
@@ -70,7 +70,7 @@ struct trace_uprobe {
|
||||
(sizeof(struct probe_arg) * (n)))
|
||||
|
||||
static int register_uprobe_event(struct trace_uprobe *tu);
|
||||
static void unregister_uprobe_event(struct trace_uprobe *tu);
|
||||
static int unregister_uprobe_event(struct trace_uprobe *tu);
|
||||
|
||||
static DEFINE_MUTEX(uprobe_lock);
|
||||
static LIST_HEAD(uprobe_list);
|
||||
@@ -164,11 +164,17 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou
|
||||
}
|
||||
|
||||
/* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */
|
||||
static void unregister_trace_uprobe(struct trace_uprobe *tu)
|
||||
static int unregister_trace_uprobe(struct trace_uprobe *tu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = unregister_uprobe_event(tu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_del(&tu->list);
|
||||
unregister_uprobe_event(tu);
|
||||
free_trace_uprobe(tu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register a trace_uprobe and probe_event */
|
||||
@@ -181,9 +187,12 @@ static int register_trace_uprobe(struct trace_uprobe *tu)
|
||||
|
||||
/* register as an event */
|
||||
old_tp = find_probe_event(tu->call.name, tu->call.class->system);
|
||||
if (old_tp)
|
||||
if (old_tp) {
|
||||
/* delete old event */
|
||||
unregister_trace_uprobe(old_tp);
|
||||
ret = unregister_trace_uprobe(old_tp);
|
||||
if (ret)
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = register_uprobe_event(tu);
|
||||
if (ret) {
|
||||
@@ -256,6 +265,8 @@ static int create_trace_uprobe(int argc, char **argv)
|
||||
group = UPROBE_EVENT_SYSTEM;
|
||||
|
||||
if (is_delete) {
|
||||
int ret;
|
||||
|
||||
if (!event) {
|
||||
pr_info("Delete command needs an event name.\n");
|
||||
return -EINVAL;
|
||||
@@ -269,9 +280,9 @@ static int create_trace_uprobe(int argc, char **argv)
|
||||
return -ENOENT;
|
||||
}
|
||||
/* delete an event */
|
||||
unregister_trace_uprobe(tu);
|
||||
ret = unregister_trace_uprobe(tu);
|
||||
mutex_unlock(&uprobe_lock);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
@@ -408,16 +419,20 @@ fail_address_parse:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cleanup_all_probes(void)
|
||||
static int cleanup_all_probes(void)
|
||||
{
|
||||
struct trace_uprobe *tu;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&uprobe_lock);
|
||||
while (!list_empty(&uprobe_list)) {
|
||||
tu = list_entry(uprobe_list.next, struct trace_uprobe, list);
|
||||
unregister_trace_uprobe(tu);
|
||||
ret = unregister_trace_uprobe(tu);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&uprobe_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Probes listing interfaces */
|
||||
@@ -462,8 +477,13 @@ static const struct seq_operations probes_seq_op = {
|
||||
|
||||
static int probes_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC))
|
||||
cleanup_all_probes();
|
||||
int ret;
|
||||
|
||||
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
|
||||
ret = cleanup_all_probes();
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return seq_open(file, &probes_seq_op);
|
||||
}
|
||||
@@ -818,8 +838,6 @@ static void uprobe_perf_print(struct trace_uprobe *tu,
|
||||
|
||||
size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
|
||||
size = ALIGN(size + tu->size + sizeof(u32), sizeof(u64)) - sizeof(u32);
|
||||
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
|
||||
return;
|
||||
|
||||
preempt_disable();
|
||||
head = this_cpu_ptr(call->perf_events);
|
||||
@@ -970,12 +988,17 @@ static int register_uprobe_event(struct trace_uprobe *tu)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void unregister_uprobe_event(struct trace_uprobe *tu)
|
||||
static int unregister_uprobe_event(struct trace_uprobe *tu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* tu->event is unregistered in trace_remove_event_call() */
|
||||
trace_remove_event_call(&tu->call);
|
||||
ret = trace_remove_event_call(&tu->call);
|
||||
if (ret)
|
||||
return ret;
|
||||
kfree(tu->call.print_fmt);
|
||||
tu->call.print_fmt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make a trace interface for controling probe points */
|
||||
|
||||
+13
-4
@@ -62,6 +62,9 @@ int create_user_ns(struct cred *new)
|
||||
kgid_t group = new->egid;
|
||||
int ret;
|
||||
|
||||
if (parent_ns->level > 32)
|
||||
return -EUSERS;
|
||||
|
||||
/*
|
||||
* Verify that we can not violate the policy of which files
|
||||
* may be accessed that is specified by the root directory,
|
||||
@@ -92,6 +95,7 @@ int create_user_ns(struct cred *new)
|
||||
atomic_set(&ns->count, 1);
|
||||
/* Leave the new->user_ns reference with the new user namespace. */
|
||||
ns->parent = parent_ns;
|
||||
ns->level = parent_ns->level + 1;
|
||||
ns->owner = owner;
|
||||
ns->group = group;
|
||||
|
||||
@@ -105,16 +109,21 @@ int create_user_ns(struct cred *new)
|
||||
int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
|
||||
{
|
||||
struct cred *cred;
|
||||
int err = -ENOMEM;
|
||||
|
||||
if (!(unshare_flags & CLONE_NEWUSER))
|
||||
return 0;
|
||||
|
||||
cred = prepare_creds();
|
||||
if (!cred)
|
||||
return -ENOMEM;
|
||||
if (cred) {
|
||||
err = create_user_ns(cred);
|
||||
if (err)
|
||||
put_cred(cred);
|
||||
else
|
||||
*new_cred = cred;
|
||||
}
|
||||
|
||||
*new_cred = cred;
|
||||
return create_user_ns(cred);
|
||||
return err;
|
||||
}
|
||||
|
||||
void free_user_ns(struct user_namespace *ns)
|
||||
|
||||
+2
-1
@@ -333,7 +333,8 @@ int __wait_on_atomic_t(wait_queue_head_t *wq, struct wait_bit_queue *q,
|
||||
prepare_to_wait(wq, &q->wait, mode);
|
||||
val = q->key.flags;
|
||||
if (atomic_read(val) == 0)
|
||||
ret = (*action)(val);
|
||||
break;
|
||||
ret = (*action)(val);
|
||||
} while (!ret && atomic_read(val) != 0);
|
||||
finish_wait(wq, &q->wait);
|
||||
return ret;
|
||||
|
||||
+34
-10
@@ -2817,6 +2817,19 @@ already_gone:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool __flush_work(struct work_struct *work)
|
||||
{
|
||||
struct wq_barrier barr;
|
||||
|
||||
if (start_flush_work(work, &barr)) {
|
||||
wait_for_completion(&barr.done);
|
||||
destroy_work_on_stack(&barr.work);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* flush_work - wait for a work to finish executing the last queueing instance
|
||||
* @work: the work to flush
|
||||
@@ -2830,18 +2843,10 @@ already_gone:
|
||||
*/
|
||||
bool flush_work(struct work_struct *work)
|
||||
{
|
||||
struct wq_barrier barr;
|
||||
|
||||
lock_map_acquire(&work->lockdep_map);
|
||||
lock_map_release(&work->lockdep_map);
|
||||
|
||||
if (start_flush_work(work, &barr)) {
|
||||
wait_for_completion(&barr.done);
|
||||
destroy_work_on_stack(&barr.work);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return __flush_work(work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(flush_work);
|
||||
|
||||
@@ -3411,6 +3416,12 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to,
|
||||
{
|
||||
to->nice = from->nice;
|
||||
cpumask_copy(to->cpumask, from->cpumask);
|
||||
/*
|
||||
* Unlike hash and equality test, this function doesn't ignore
|
||||
* ->no_numa as it is used for both pool and wq attrs. Instead,
|
||||
* get_unbound_pool() explicitly clears ->no_numa after copying.
|
||||
*/
|
||||
to->no_numa = from->no_numa;
|
||||
}
|
||||
|
||||
/* hash value of the content of @attr */
|
||||
@@ -3578,6 +3589,12 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs)
|
||||
lockdep_set_subclass(&pool->lock, 1); /* see put_pwq() */
|
||||
copy_workqueue_attrs(pool->attrs, attrs);
|
||||
|
||||
/*
|
||||
* no_numa isn't a worker_pool attribute, always clear it. See
|
||||
* 'struct workqueue_attrs' comments for detail.
|
||||
*/
|
||||
pool->attrs->no_numa = false;
|
||||
|
||||
/* if cpumask is contained inside a NUMA node, we belong to that node */
|
||||
if (wq_numa_enabled) {
|
||||
for_each_node(node) {
|
||||
@@ -4756,7 +4773,14 @@ long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
|
||||
|
||||
INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
|
||||
schedule_work_on(cpu, &wfc.work);
|
||||
flush_work(&wfc.work);
|
||||
|
||||
/*
|
||||
* The work item is on-stack and can't lead to deadlock through
|
||||
* flushing. Use __flush_work() to avoid spurious lockdep warnings
|
||||
* when work_on_cpu()s are nested.
|
||||
*/
|
||||
__flush_work(&wfc.work);
|
||||
|
||||
return wfc.ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(work_on_cpu);
|
||||
|
||||
Reference in New Issue
Block a user