Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[safe/jmp/linux-2.6] / kernel / trace / trace_ksym.c
index c538b15..faf37fa 100644 (file)
@@ -42,9 +42,7 @@
 
 struct trace_ksym {
        struct perf_event       **ksym_hbp;
-       unsigned long           ksym_addr;
-       int                     type;
-       int                     len;
+       struct perf_event_attr  attr;
 #ifdef CONFIG_PROFILE_KSYM_TRACER
        unsigned long           counter;
 #endif
@@ -71,7 +69,7 @@ void ksym_collect_stats(unsigned long hbp_hit_addr)
 
        rcu_read_lock();
        hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) {
-               if ((entry->ksym_addr == hbp_hit_addr) &&
+               if ((entry->attr.bp_addr == hbp_hit_addr) &&
                    (entry->counter <= MAX_UL_INT)) {
                        entry->counter++;
                        break;
@@ -81,11 +79,12 @@ void ksym_collect_stats(unsigned long hbp_hit_addr)
 }
 #endif /* CONFIG_PROFILE_KSYM_TRACER */
 
-void ksym_hbp_handler(struct perf_event *hbp, void *data)
+void ksym_hbp_handler(struct perf_event *hbp, int nmi,
+                     struct perf_sample_data *data,
+                     struct pt_regs *regs)
 {
        struct ring_buffer_event *event;
        struct ksym_trace_entry *entry;
-       struct pt_regs *regs = data;
        struct ring_buffer *buffer;
        int pc;
 
@@ -192,14 +191,15 @@ int process_new_ksym_entry(char *ksymname, int op, unsigned long addr)
        if (!entry)
                return -ENOMEM;
 
-       entry->type = op;
-       entry->ksym_addr = addr;
-       entry->len = HW_BREAKPOINT_LEN_4;
+       hw_breakpoint_init(&entry->attr);
+
+       entry->attr.bp_type = op;
+       entry->attr.bp_addr = addr;
+       entry->attr.bp_len = HW_BREAKPOINT_LEN_4;
 
        ret = -EAGAIN;
-       entry->ksym_hbp = register_wide_hw_breakpoint(entry->ksym_addr,
-                                       entry->len, entry->type,
-                                       ksym_hbp_handler, true);
+       entry->ksym_hbp = register_wide_hw_breakpoint(&entry->attr,
+                                       ksym_hbp_handler);
 
        if (IS_ERR(entry->ksym_hbp)) {
                ret = PTR_ERR(entry->ksym_hbp);
@@ -236,12 +236,13 @@ static ssize_t ksym_trace_filter_read(struct file *filp, char __user *ubuf,
        mutex_lock(&ksym_tracer_mutex);
 
        hlist_for_each_entry(entry, node, &ksym_filter_head, ksym_hlist) {
-               ret = trace_seq_printf(s, "%pS:", (void *)entry->ksym_addr);
-               if (entry->type == HW_BREAKPOINT_R)
+               ret = trace_seq_printf(s, "%pS:",
+                               (void *)(unsigned long)entry->attr.bp_addr);
+               if (entry->attr.bp_type == HW_BREAKPOINT_R)
                        ret = trace_seq_puts(s, "r--\n");
-               else if (entry->type == HW_BREAKPOINT_W)
+               else if (entry->attr.bp_type == HW_BREAKPOINT_W)
                        ret = trace_seq_puts(s, "-w-\n");
-               else if (entry->type == (HW_BREAKPOINT_W | HW_BREAKPOINT_R))
+               else if (entry->attr.bp_type == (HW_BREAKPOINT_W | HW_BREAKPOINT_R))
                        ret = trace_seq_puts(s, "rw-\n");
                WARN_ON_ONCE(!ret);
        }
@@ -278,21 +279,20 @@ static ssize_t ksym_trace_filter_write(struct file *file,
 {
        struct trace_ksym *entry;
        struct hlist_node *node;
-       char *input_string, *ksymname = NULL;
+       char *buf, *input_string, *ksymname = NULL;
        unsigned long ksym_addr = 0;
        int ret, op, changed = 0;
 
-       input_string = kzalloc(count + 1, GFP_KERNEL);
-       if (!input_string)
+       buf = kzalloc(count + 1, GFP_KERNEL);
+       if (!buf)
                return -ENOMEM;
 
-       if (copy_from_user(input_string, buffer, count)) {
-               kfree(input_string);
-               return -EFAULT;
-       }
-       input_string[count] = '\0';
+       ret = -EFAULT;
+       if (copy_from_user(buf, buffer, count))
+               goto out;
 
-       strstrip(input_string);
+       buf[count] = '\0';
+       input_string = strstrip(buf);
 
        /*
         * Clear all breakpoints if:
@@ -300,66 +300,59 @@ static ssize_t ksym_trace_filter_write(struct file *file,
         * 2: echo 0 > ksym_trace_filter
         * 3: echo "*:---" > ksym_trace_filter
         */
-       if (!input_string[0] || !strcmp(input_string, "0") ||
-           !strcmp(input_string, "*:---")) {
+       if (!buf[0] || !strcmp(buf, "0") ||
+           !strcmp(buf, "*:---")) {
                __ksym_trace_reset();
-               kfree(input_string);
-               return count;
+               ret = 0;
+               goto out;
        }
 
        ret = op = parse_ksym_trace_str(input_string, &ksymname, &ksym_addr);
-       if (ret < 0) {
-               kfree(input_string);
-               return ret;
-       }
+       if (ret < 0)
+               goto out;
 
        mutex_lock(&ksym_tracer_mutex);
 
        ret = -EINVAL;
        hlist_for_each_entry(entry, node, &ksym_filter_head, ksym_hlist) {
-               if (entry->ksym_addr == ksym_addr) {
+               if (entry->attr.bp_addr == ksym_addr) {
                        /* Check for malformed request: (6) */
-                       if (entry->type != op)
+                       if (entry->attr.bp_type != op)
                                changed = 1;
                        else
-                               goto out;
+                               goto out_unlock;
                        break;
                }
        }
        if (changed) {
                unregister_wide_hw_breakpoint(entry->ksym_hbp);
-               entry->type = op;
+               entry->attr.bp_type = op;
                ret = 0;
                if (op > 0) {
                        entry->ksym_hbp =
-                               register_wide_hw_breakpoint(entry->ksym_addr,
-                                       entry->len, entry->type,
-                                       ksym_hbp_handler, true);
+                               register_wide_hw_breakpoint(&entry->attr,
+                                       ksym_hbp_handler);
                        if (IS_ERR(entry->ksym_hbp))
                                ret = PTR_ERR(entry->ksym_hbp);
                        else
-                               goto out;
+                               goto out_unlock;
                }
                /* Error or "symbol:---" case: drop it */
                ksym_filter_entry_count--;
                hlist_del_rcu(&(entry->ksym_hlist));
                synchronize_rcu();
                kfree(entry);
-               goto out;
+               goto out_unlock;
        } else {
                /* Check for malformed request: (4) */
-               if (op == 0)
-                       goto out;
-               ret = process_new_ksym_entry(ksymname, op, ksym_addr);
+               if (op)
+                       ret = process_new_ksym_entry(ksymname, op, ksym_addr);
        }
-out:
+out_unlock:
        mutex_unlock(&ksym_tracer_mutex);
-
-       kfree(input_string);
-
-       if (!ret)
-               ret = count;
-       return ret;
+out:
+       kfree(buf);
+       return !ret ? count : ret;
 }
 
 static const struct file_operations ksym_tracing_fops = {
@@ -489,7 +482,7 @@ static int ksym_tracer_stat_show(struct seq_file *m, void *v)
 
        entry = hlist_entry(stat, struct trace_ksym, ksym_hlist);
 
-       access_type = entry->type;
+       access_type = entry->attr.bp_type;
 
        switch (access_type) {
        case HW_BREAKPOINT_R:
@@ -505,7 +498,7 @@ static int ksym_tracer_stat_show(struct seq_file *m, void *v)
                seq_puts(m, "  NA          ");
        }
 
-       if (lookup_symbol_name(entry->ksym_addr, fn_name) >= 0)
+       if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0)
                seq_printf(m, "  %-36s", fn_name);
        else
                seq_printf(m, "  %-36s", "<NA>");