Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 2 Dec 2013 18:13:09 +0000 (10:13 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 2 Dec 2013 18:13:09 +0000 (10:13 -0800)
Pull perf fixes from Ingo Molnar:
 "Misc kernel and tooling fixes"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  tools lib traceevent: Fix conversion of pointer to integer of different size
  perf/trace: Properly use u64 to hold event_id
  perf: Remove fragile swevent hlist optimization
  ftrace, perf: Avoid infinite event generation loop
  tools lib traceevent: Fix use of multiple options in processing field
  perf header: Fix possible memory leaks in process_group_desc()
  perf header: Fix bogus group name
  perf tools: Tag thread comm as overriden

arch/x86/include/asm/trace/irq_vectors.h
include/linux/ftrace_event.h
include/linux/tracepoint.h
include/trace/ftrace.h
kernel/events/core.c
kernel/trace/trace_event_perf.c
tools/lib/traceevent/event-parse.c
tools/perf/util/header.c
tools/perf/util/thread.c

index 2874df24e7a448cd56631d87f5ac9e0fdd00cbc7..4cab890007a7267ecc7ce148eaa1fdfbee4a49df 100644 (file)
@@ -71,6 +71,17 @@ DEFINE_IRQ_VECTOR_EVENT(x86_platform_ipi);
  */
 DEFINE_IRQ_VECTOR_EVENT(irq_work);
 
+/*
+ * We must dis-allow sampling irq_work_exit() because perf event sampling
+ * itself can cause irq_work, which would lead to an infinite loop;
+ *
+ *  1) irq_work_exit happens
+ *  2) generates perf sample
+ *  3) generates irq_work
+ *  4) goto 1
+ */
+TRACE_EVENT_PERF_PERM(irq_work_exit, is_sampling_event(p_event) ? -EPERM : 0);
+
 /*
  * call_function - called when entering/exiting a call function interrupt
  * vector handler
index 9abbe630c456775b19cc999f36887efa94bbdd41..8c9b7a1c4138b87a79833bc400370a13e94cf270 100644 (file)
@@ -248,6 +248,9 @@ struct ftrace_event_call {
 #ifdef CONFIG_PERF_EVENTS
        int                             perf_refcount;
        struct hlist_head __percpu      *perf_events;
+
+       int     (*perf_perm)(struct ftrace_event_call *,
+                            struct perf_event *);
 #endif
 };
 
@@ -317,6 +320,19 @@ struct ftrace_event_file {
        }                                                               \
        early_initcall(trace_init_flags_##name);
 
+#define __TRACE_EVENT_PERF_PERM(name, expr...)                         \
+       static int perf_perm_##name(struct ftrace_event_call *tp_event, \
+                                   struct perf_event *p_event)         \
+       {                                                               \
+               return ({ expr; });                                     \
+       }                                                               \
+       static int __init trace_init_perf_perm_##name(void)             \
+       {                                                               \
+               event_##name.perf_perm = &perf_perm_##name;             \
+               return 0;                                               \
+       }                                                               \
+       early_initcall(trace_init_perf_perm_##name);
+
 #define PERF_MAX_TRACE_SIZE    2048
 
 #define MAX_FILTER_STR_VAL     256     /* Should handle KSYM_SYMBOL_LEN */
index ebeab360d851c1ece4952b3f5f4f294aa9673db0..f16dc0a4004976376c9036a244e1121ed52ed020 100644 (file)
@@ -267,6 +267,8 @@ static inline void tracepoint_synchronize_unregister(void)
 
 #define TRACE_EVENT_FLAGS(event, flag)
 
+#define TRACE_EVENT_PERF_PERM(event, expr...)
+
 #endif /* DECLARE_TRACE */
 
 #ifndef TRACE_EVENT
@@ -399,4 +401,6 @@ static inline void tracepoint_synchronize_unregister(void)
 
 #define TRACE_EVENT_FLAGS(event, flag)
 
+#define TRACE_EVENT_PERF_PERM(event, expr...)
+
 #endif /* ifdef TRACE_EVENT (see note above) */
index d17a35c6537e615a384e2cd006f37b4a2828a55a..5c38606613d89a06c361a56054e97031c391c2d3 100644 (file)
 #define TRACE_EVENT_FLAGS(name, value)                                 \
        __TRACE_EVENT_FLAGS(name, value)
 
+#undef TRACE_EVENT_PERF_PERM
+#define TRACE_EVENT_PERF_PERM(name, expr...)                           \
+       __TRACE_EVENT_PERF_PERM(name, expr)
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 
 #undef TRACE_EVENT_FLAGS
 #define TRACE_EVENT_FLAGS(event, flag)
 
+#undef TRACE_EVENT_PERF_PERM
+#define TRACE_EVENT_PERF_PERM(event, expr...)
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 /*
index d724e7757cd1ec2df7a9c2ac9be1b0c23f6e4e71..72348dc192c11e7a85560b67bc792415d969e22f 100644 (file)
@@ -5680,11 +5680,6 @@ static void swevent_hlist_put(struct perf_event *event)
 {
        int cpu;
 
-       if (event->cpu != -1) {
-               swevent_hlist_put_cpu(event, event->cpu);
-               return;
-       }
-
        for_each_possible_cpu(cpu)
                swevent_hlist_put_cpu(event, cpu);
 }
@@ -5718,9 +5713,6 @@ static int swevent_hlist_get(struct perf_event *event)
        int err;
        int cpu, failed_cpu;
 
-       if (event->cpu != -1)
-               return swevent_hlist_get_cpu(event, event->cpu);
-
        get_online_cpus();
        for_each_possible_cpu(cpu) {
                err = swevent_hlist_get_cpu(event, cpu);
index 78e27e3b52ac2ee0b9e86f544b77a45e12865d95..e854f420e033eb65a2bca233bb8df2e42778faf7 100644 (file)
@@ -24,6 +24,12 @@ static int   total_ref_count;
 static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
                                 struct perf_event *p_event)
 {
+       if (tp_event->perf_perm) {
+               int ret = tp_event->perf_perm(tp_event, p_event);
+               if (ret)
+                       return ret;
+       }
+
        /* The ftrace function trace is allowed only for root. */
        if (ftrace_event_is_function(tp_event) &&
            perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
@@ -173,7 +179,7 @@ static int perf_trace_event_init(struct ftrace_event_call *tp_event,
 int perf_trace_init(struct perf_event *p_event)
 {
        struct ftrace_event_call *tp_event;
-       int event_id = p_event->attr.config;
+       u64 event_id = p_event->attr.config;
        int ret = -EINVAL;
 
        mutex_lock(&event_mutex);
index 0362d575de7d185752b2a23a53845236c71510f6..217c82ee3665704282443261c512d1c3920ed699 100644 (file)
@@ -1606,6 +1606,24 @@ process_arg(struct event_format *event, struct print_arg *arg, char **tok)
 static enum event_type
 process_op(struct event_format *event, struct print_arg *arg, char **tok);
 
+/*
+ * For __print_symbolic() and __print_flags, we need to completely
+ * evaluate the first argument, which defines what to print next.
+ */
+static enum event_type
+process_field_arg(struct event_format *event, struct print_arg *arg, char **tok)
+{
+       enum event_type type;
+
+       type = process_arg(event, arg, tok);
+
+       while (type == EVENT_OP) {
+               type = process_op(event, arg, tok);
+       }
+
+       return type;
+}
+
 static enum event_type
 process_cond(struct event_format *event, struct print_arg *top, char **tok)
 {
@@ -2371,7 +2389,7 @@ process_flags(struct event_format *event, struct print_arg *arg, char **tok)
                goto out_free;
        }
 
-       type = process_arg(event, field, &token);
+       type = process_field_arg(event, field, &token);
 
        /* Handle operations in the first argument */
        while (type == EVENT_OP)
@@ -2424,7 +2442,8 @@ process_symbols(struct event_format *event, struct print_arg *arg, char **tok)
                goto out_free;
        }
 
-       type = process_arg(event, field, &token);
+       type = process_field_arg(event, field, &token);
+
        if (test_type_token(type, token, EVENT_DELIM, ","))
                goto out_free_field;
 
@@ -3446,7 +3465,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
                 * is in the bottom half of the 32 bit field.
                 */
                offset &= 0xffff;
-               val = (unsigned long long)(data + offset);
+               val = (unsigned long long)((unsigned long)data + offset);
                break;
        default: /* not sure what to do there */
                return 0;
index 369c03648f8846d3da12bf96a938f6e76485fbed..1cd035708931144dccbfdb68f4c1024903e45631 100644 (file)
@@ -2078,8 +2078,10 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,
                if (evsel->idx == (int) desc[i].leader_idx) {
                        evsel->leader = evsel;
                        /* {anon_group} is a dummy name */
-                       if (strcmp(desc[i].name, "{anon_group}"))
+                       if (strcmp(desc[i].name, "{anon_group}")) {
                                evsel->group_name = desc[i].name;
+                               desc[i].name = NULL;
+                       }
                        evsel->nr_members = desc[i].nr_members;
 
                        if (i >= nr_groups || nr > 0) {
@@ -2105,7 +2107,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,
 
        ret = 0;
 out_free:
-       while ((int) --i >= 0)
+       for (i = 0; i < nr_groups; i++)
                free(desc[i].name);
        free(desc);
 
index cd8e2f59271969f410daf28afdf93523699f475c..49eaf1d7d89d0554a146a272e923cd139e6cbac7 100644 (file)
@@ -70,14 +70,13 @@ int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
        /* Override latest entry if it had no specific time coverage */
        if (!curr->start) {
                comm__override(curr, str, timestamp);
-               return 0;
+       } else {
+               new = comm__new(str, timestamp);
+               if (!new)
+                       return -ENOMEM;
+               list_add(&new->list, &thread->comm_list);
        }
 
-       new = comm__new(str, timestamp);
-       if (!new)
-               return -ENOMEM;
-
-       list_add(&new->list, &thread->comm_list);
        thread->comm_set = true;
 
        return 0;