Commit f2955b49 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perf-fixes-for-linus' of...

Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  tracing: t_start: reset FTRACE_ITER_HASH in case of seek/pread
  perf symbols: Fix multiple initialization of symbol system
  perf: Fix CPU hotplug
  perf, trace: Fix module leak
  tracing/kprobe: Fix handling of C-unlike argument names
  tracing/kprobes: Fix handling of argument names
  perf probe: Fix handling of arguments names
  perf probe: Fix return probe support
  tracing/kprobe: Fix a memory leak in error case
  tracing: Do not allow llseek to set_ftrace_filter
parents 3d96406c 9efdda31
...@@ -5761,15 +5761,15 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) ...@@ -5761,15 +5761,15 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
{ {
unsigned int cpu = (long)hcpu; unsigned int cpu = (long)hcpu;
switch (action) { switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE: case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN: case CPU_DOWN_FAILED:
perf_event_init_cpu(cpu); perf_event_init_cpu(cpu);
break; break;
case CPU_UP_CANCELED:
case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
perf_event_exit_cpu(cpu); perf_event_exit_cpu(cpu);
break; break;
......
...@@ -1510,6 +1510,8 @@ static void *t_start(struct seq_file *m, loff_t *pos) ...@@ -1510,6 +1510,8 @@ static void *t_start(struct seq_file *m, loff_t *pos)
if (*pos > 0) if (*pos > 0)
return t_hash_start(m, pos); return t_hash_start(m, pos);
iter->flags |= FTRACE_ITER_PRINTALL; iter->flags |= FTRACE_ITER_PRINTALL;
/* reset in case of seek/pread */
iter->flags &= ~FTRACE_ITER_HASH;
return iter; return iter;
} }
...@@ -2416,7 +2418,7 @@ static const struct file_operations ftrace_filter_fops = { ...@@ -2416,7 +2418,7 @@ static const struct file_operations ftrace_filter_fops = {
.open = ftrace_filter_open, .open = ftrace_filter_open,
.read = seq_read, .read = seq_read,
.write = ftrace_filter_write, .write = ftrace_filter_write,
.llseek = ftrace_regex_lseek, .llseek = no_llseek,
.release = ftrace_filter_release, .release = ftrace_filter_release,
}; };
......
...@@ -91,6 +91,8 @@ int perf_trace_init(struct perf_event *p_event) ...@@ -91,6 +91,8 @@ int perf_trace_init(struct perf_event *p_event)
tp_event->class && tp_event->class->reg && tp_event->class && tp_event->class->reg &&
try_module_get(tp_event->mod)) { try_module_get(tp_event->mod)) {
ret = perf_trace_event_init(tp_event, p_event); ret = perf_trace_event_init(tp_event, p_event);
if (ret)
module_put(tp_event->mod);
break; break;
} }
} }
...@@ -146,6 +148,7 @@ void perf_trace_destroy(struct perf_event *p_event) ...@@ -146,6 +148,7 @@ void perf_trace_destroy(struct perf_event *p_event)
} }
} }
out: out:
module_put(tp_event->mod);
mutex_unlock(&event_mutex); mutex_unlock(&event_mutex);
} }
......
...@@ -514,8 +514,8 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); ...@@ -514,8 +514,8 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
static int kretprobe_dispatcher(struct kretprobe_instance *ri, static int kretprobe_dispatcher(struct kretprobe_instance *ri,
struct pt_regs *regs); struct pt_regs *regs);
/* Check the name is good for event/group */ /* Check the name is good for event/group/fields */
static int check_event_name(const char *name) static int is_good_name(const char *name)
{ {
if (!isalpha(*name) && *name != '_') if (!isalpha(*name) && *name != '_')
return 0; return 0;
...@@ -557,7 +557,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, ...@@ -557,7 +557,7 @@ static struct trace_probe *alloc_trace_probe(const char *group,
else else
tp->rp.kp.pre_handler = kprobe_dispatcher; tp->rp.kp.pre_handler = kprobe_dispatcher;
if (!event || !check_event_name(event)) { if (!event || !is_good_name(event)) {
ret = -EINVAL; ret = -EINVAL;
goto error; goto error;
} }
...@@ -567,7 +567,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, ...@@ -567,7 +567,7 @@ static struct trace_probe *alloc_trace_probe(const char *group,
if (!tp->call.name) if (!tp->call.name)
goto error; goto error;
if (!group || !check_event_name(group)) { if (!group || !is_good_name(group)) {
ret = -EINVAL; ret = -EINVAL;
goto error; goto error;
} }
...@@ -883,7 +883,7 @@ static int create_trace_probe(int argc, char **argv) ...@@ -883,7 +883,7 @@ static int create_trace_probe(int argc, char **argv)
int i, ret = 0; int i, ret = 0;
int is_return = 0, is_delete = 0; int is_return = 0, is_delete = 0;
char *symbol = NULL, *event = NULL, *group = NULL; char *symbol = NULL, *event = NULL, *group = NULL;
char *arg, *tmp; char *arg;
unsigned long offset = 0; unsigned long offset = 0;
void *addr = NULL; void *addr = NULL;
char buf[MAX_EVENT_NAME_LEN]; char buf[MAX_EVENT_NAME_LEN];
...@@ -992,26 +992,36 @@ static int create_trace_probe(int argc, char **argv) ...@@ -992,26 +992,36 @@ static int create_trace_probe(int argc, char **argv)
/* parse arguments */ /* parse arguments */
ret = 0; ret = 0;
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
/* Increment count for freeing args in error case */
tp->nr_args++;
/* Parse argument name */ /* Parse argument name */
arg = strchr(argv[i], '='); arg = strchr(argv[i], '=');
if (arg) if (arg) {
*arg++ = '\0'; *arg++ = '\0';
else tp->args[i].name = kstrdup(argv[i], GFP_KERNEL);
} else {
arg = argv[i]; arg = argv[i];
/* If argument name is omitted, set "argN" */
snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1);
tp->args[i].name = kstrdup(buf, GFP_KERNEL);
}
tp->args[i].name = kstrdup(argv[i], GFP_KERNEL);
if (!tp->args[i].name) { if (!tp->args[i].name) {
pr_info("Failed to allocate argument%d name '%s'.\n", pr_info("Failed to allocate argument[%d] name.\n", i);
i, argv[i]);
ret = -ENOMEM; ret = -ENOMEM;
goto error; goto error;
} }
tmp = strchr(tp->args[i].name, ':');
if (tmp) if (!is_good_name(tp->args[i].name)) {
*tmp = '_'; /* convert : to _ */ pr_info("Invalid argument[%d] name: %s\n",
i, tp->args[i].name);
ret = -EINVAL;
goto error;
}
if (conflict_field_name(tp->args[i].name, tp->args, i)) { if (conflict_field_name(tp->args[i].name, tp->args, i)) {
pr_info("Argument%d name '%s' conflicts with " pr_info("Argument[%d] name '%s' conflicts with "
"another field.\n", i, argv[i]); "another field.\n", i, argv[i]);
ret = -EINVAL; ret = -EINVAL;
goto error; goto error;
...@@ -1020,12 +1030,9 @@ static int create_trace_probe(int argc, char **argv) ...@@ -1020,12 +1030,9 @@ static int create_trace_probe(int argc, char **argv)
/* Parse fetch argument */ /* Parse fetch argument */
ret = parse_probe_arg(arg, tp, &tp->args[i], is_return); ret = parse_probe_arg(arg, tp, &tp->args[i], is_return);
if (ret) { if (ret) {
pr_info("Parse error at argument%d. (%d)\n", i, ret); pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
kfree(tp->args[i].name);
goto error; goto error;
} }
tp->nr_args++;
} }
ret = register_trace_probe(tp); ret = register_trace_probe(tp);
......
...@@ -1539,6 +1539,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, ...@@ -1539,6 +1539,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
goto error; goto error;
} }
tev->point.offset = pev->point.offset; tev->point.offset = pev->point.offset;
tev->point.retprobe = pev->point.retprobe;
tev->nargs = pev->nargs; tev->nargs = pev->nargs;
if (tev->nargs) { if (tev->nargs) {
tev->args = zalloc(sizeof(struct probe_trace_arg) tev->args = zalloc(sizeof(struct probe_trace_arg)
......
...@@ -686,6 +686,25 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) ...@@ -686,6 +686,25 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
char buf[32], *ptr; char buf[32], *ptr;
int ret, nscopes; int ret, nscopes;
if (!is_c_varname(pf->pvar->var)) {
/* Copy raw parameters */
pf->tvar->value = strdup(pf->pvar->var);
if (pf->tvar->value == NULL)
return -ENOMEM;
if (pf->pvar->type) {
pf->tvar->type = strdup(pf->pvar->type);
if (pf->tvar->type == NULL)
return -ENOMEM;
}
if (pf->pvar->name) {
pf->tvar->name = strdup(pf->pvar->name);
if (pf->tvar->name == NULL)
return -ENOMEM;
} else
pf->tvar->name = NULL;
return 0;
}
if (pf->pvar->name) if (pf->pvar->name)
pf->tvar->name = strdup(pf->pvar->name); pf->tvar->name = strdup(pf->pvar->name);
else { else {
...@@ -700,19 +719,6 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) ...@@ -700,19 +719,6 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
if (pf->tvar->name == NULL) if (pf->tvar->name == NULL)
return -ENOMEM; return -ENOMEM;
if (!is_c_varname(pf->pvar->var)) {
/* Copy raw parameters */
pf->tvar->value = strdup(pf->pvar->var);
if (pf->tvar->value == NULL)
return -ENOMEM;
if (pf->pvar->type) {
pf->tvar->type = strdup(pf->pvar->type);
if (pf->tvar->type == NULL)
return -ENOMEM;
}
return 0;
}
pr_debug("Searching '%s' variable in context.\n", pr_debug("Searching '%s' variable in context.\n",
pf->pvar->var); pf->pvar->var);
/* Search child die for local variables and parameters. */ /* Search child die for local variables and parameters. */
...@@ -783,6 +789,16 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) ...@@ -783,6 +789,16 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
/* This function has no name. */ /* This function has no name. */
tev->point.offset = (unsigned long)pf->addr; tev->point.offset = (unsigned long)pf->addr;
/* Return probe must be on the head of a subprogram */
if (pf->pev->point.retprobe) {
if (tev->point.offset != 0) {
pr_warning("Return probe must be on the head of"
" a real function\n");
return -EINVAL;
}
tev->point.retprobe = true;
}
pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
tev->point.offset); tev->point.offset);
......
...@@ -2268,6 +2268,9 @@ static int setup_list(struct strlist **list, const char *list_str, ...@@ -2268,6 +2268,9 @@ static int setup_list(struct strlist **list, const char *list_str,
int symbol__init(void) int symbol__init(void)
{ {
if (symbol_conf.initialized)
return 0;
elf_version(EV_CURRENT); elf_version(EV_CURRENT);
if (symbol_conf.sort_by_name) if (symbol_conf.sort_by_name)
symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
...@@ -2293,6 +2296,7 @@ int symbol__init(void) ...@@ -2293,6 +2296,7 @@ int symbol__init(void)
symbol_conf.sym_list_str, "symbol") < 0) symbol_conf.sym_list_str, "symbol") < 0)
goto out_free_comm_list; goto out_free_comm_list;
symbol_conf.initialized = true;
return 0; return 0;
out_free_dso_list: out_free_dso_list:
...@@ -2304,11 +2308,14 @@ int symbol__init(void) ...@@ -2304,11 +2308,14 @@ int symbol__init(void)
void symbol__exit(void) void symbol__exit(void)
{ {
if (!symbol_conf.initialized)
return;
strlist__delete(symbol_conf.sym_list); strlist__delete(symbol_conf.sym_list);
strlist__delete(symbol_conf.dso_list); strlist__delete(symbol_conf.dso_list);
strlist__delete(symbol_conf.comm_list); strlist__delete(symbol_conf.comm_list);
vmlinux_path__exit(); vmlinux_path__exit();
symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
symbol_conf.initialized = false;
} }
int machines__create_kernel_maps(struct rb_root *self, pid_t pid) int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
......
...@@ -69,7 +69,8 @@ struct symbol_conf { ...@@ -69,7 +69,8 @@ struct symbol_conf {
show_nr_samples, show_nr_samples,
use_callchain, use_callchain,
exclude_other, exclude_other,
show_cpu_utilization; show_cpu_utilization,
initialized;
const char *vmlinux_name, const char *vmlinux_name,
*source_prefix, *source_prefix,
*field_sep; *field_sep;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment