Blame view

kernel/trace/trace_event_perf.c 4.68 KB
ac199db01   Peter Zijlstra   ftrace: event pro...
1
  /*
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
2
   * trace event based perf event profiling/tracing
ac199db01   Peter Zijlstra   ftrace: event pro...
3
4
   *
   * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra <pzijlstr@redhat.com>
c530665c3   Frederic Weisbecker   perf: Take a hot ...
5
   * Copyright (C) 2009-2010 Frederic Weisbecker <fweisbec@gmail.com>
ac199db01   Peter Zijlstra   ftrace: event pro...
6
   */
558e6547e   Li Zefan   tracing/profile: ...
7
  #include <linux/module.h>
430ad5a60   Xiao Guangrong   perf: Factorize t...
8
  #include <linux/kprobes.h>
ac199db01   Peter Zijlstra   ftrace: event pro...
9
  #include "trace.h"
6016ee13d   Namhyung Kim   perf, tracing: ad...
10
  static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS];
20ab4425a   Frederic Weisbecker   tracing: Allocate...
11

eb1e79611   Frederic Weisbecker   perf: Correctly a...
12
13
14
15
16
17
  /*
   * Force it to be aligned to unsigned long to avoid misaligned accesses
   * suprises
   */
  typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)])
  	perf_trace_t;
ce71b9df8   Frederic Weisbecker   tracing: Use the ...
18

20ab4425a   Frederic Weisbecker   tracing: Allocate...
19
  /* Count the events in use (per event id, not per instance) */
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
20
  static int	total_ref_count;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
21

61c32659b   Frederic Weisbecker   tracing: New flag...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
  				 struct perf_event *p_event)
  {
  	/* No tracing, just counting, so no obvious leak */
  	if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW))
  		return 0;
  
  	/* Some events are ok to be traced by non-root users... */
  	if (p_event->attach_state == PERF_ATTACH_TASK) {
  		if (tp_event->flags & TRACE_EVENT_FL_CAP_ANY)
  			return 0;
  	}
  
  	/*
  	 * ...otherwise raw tracepoint data can be a severe data leak,
  	 * only allow root to have these.
  	 */
  	if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	return 0;
  }
1c024eca5   Peter Zijlstra   perf, trace: Opti...
44
45
  static int perf_trace_event_init(struct ftrace_event_call *tp_event,
  				 struct perf_event *p_event)
e5e25cf47   Frederic Weisbecker   tracing: Factoriz...
46
  {
6016ee13d   Namhyung Kim   perf, tracing: ad...
47
  	struct hlist_head __percpu *list;
61c32659b   Frederic Weisbecker   tracing: New flag...
48
  	int ret;
1c024eca5   Peter Zijlstra   perf, trace: Opti...
49
  	int cpu;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
50

61c32659b   Frederic Weisbecker   tracing: New flag...
51
52
53
  	ret = perf_trace_event_perm(tp_event, p_event);
  	if (ret)
  		return ret;
1c024eca5   Peter Zijlstra   perf, trace: Opti...
54
55
  	p_event->tp_event = tp_event;
  	if (tp_event->perf_refcount++ > 0)
e5e25cf47   Frederic Weisbecker   tracing: Factoriz...
56
  		return 0;
61c32659b   Frederic Weisbecker   tracing: New flag...
57
  	ret = -ENOMEM;
1c024eca5   Peter Zijlstra   perf, trace: Opti...
58
59
60
61
62
63
  	list = alloc_percpu(struct hlist_head);
  	if (!list)
  		goto fail;
  
  	for_each_possible_cpu(cpu)
  		INIT_HLIST_HEAD(per_cpu_ptr(list, cpu));
20ab4425a   Frederic Weisbecker   tracing: Allocate...
64

1c024eca5   Peter Zijlstra   perf, trace: Opti...
65
  	tp_event->perf_events = list;
e5e25cf47   Frederic Weisbecker   tracing: Factoriz...
66

97d5a2200   Frederic Weisbecker   perf: Drop the ob...
67
  	if (!total_ref_count) {
6016ee13d   Namhyung Kim   perf, tracing: ad...
68
  		char __percpu *buf;
b7e2ecef9   Peter Zijlstra   perf, trace: Opti...
69
  		int i;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
70

7ae07ea3a   Frederic Weisbecker   perf: Humanize th...
71
  		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
6016ee13d   Namhyung Kim   perf, tracing: ad...
72
  			buf = (char __percpu *)alloc_percpu(perf_trace_t);
b7e2ecef9   Peter Zijlstra   perf, trace: Opti...
73
  			if (!buf)
1c024eca5   Peter Zijlstra   perf, trace: Opti...
74
  				goto fail;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
75

1c024eca5   Peter Zijlstra   perf, trace: Opti...
76
  			perf_trace_buf[i] = buf;
b7e2ecef9   Peter Zijlstra   perf, trace: Opti...
77
  		}
20ab4425a   Frederic Weisbecker   tracing: Allocate...
78
  	}
a1d0ce821   Steven Rostedt   tracing: Use clas...
79
  	ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER);
1c024eca5   Peter Zijlstra   perf, trace: Opti...
80
81
  	if (ret)
  		goto fail;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
82

1c024eca5   Peter Zijlstra   perf, trace: Opti...
83
84
85
86
  	total_ref_count++;
  	return 0;
  
  fail:
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
87
  	if (!total_ref_count) {
b7e2ecef9   Peter Zijlstra   perf, trace: Opti...
88
  		int i;
7ae07ea3a   Frederic Weisbecker   perf: Humanize th...
89
  		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
b7e2ecef9   Peter Zijlstra   perf, trace: Opti...
90
91
92
  			free_percpu(perf_trace_buf[i]);
  			perf_trace_buf[i] = NULL;
  		}
fe8e5b5a6   Frederic Weisbecker   tracing: Check to...
93
  	}
1c024eca5   Peter Zijlstra   perf, trace: Opti...
94
95
96
97
  
  	if (!--tp_event->perf_refcount) {
  		free_percpu(tp_event->perf_events);
  		tp_event->perf_events = NULL;
fe8e5b5a6   Frederic Weisbecker   tracing: Check to...
98
  	}
20ab4425a   Frederic Weisbecker   tracing: Allocate...
99
100
  
  	return ret;
e5e25cf47   Frederic Weisbecker   tracing: Factoriz...
101
  }
1c024eca5   Peter Zijlstra   perf, trace: Opti...
102
  int perf_trace_init(struct perf_event *p_event)
ac199db01   Peter Zijlstra   ftrace: event pro...
103
  {
1c024eca5   Peter Zijlstra   perf, trace: Opti...
104
105
  	struct ftrace_event_call *tp_event;
  	int event_id = p_event->attr.config;
20c8928ab   Li Zefan   tracing/events: f...
106
  	int ret = -EINVAL;
ac199db01   Peter Zijlstra   ftrace: event pro...
107

20c8928ab   Li Zefan   tracing/events: f...
108
  	mutex_lock(&event_mutex);
1c024eca5   Peter Zijlstra   perf, trace: Opti...
109
  	list_for_each_entry(tp_event, &ftrace_events, list) {
ff5f149b6   Steven Rostedt   Merge branch 'per...
110
  		if (tp_event->event.type == event_id &&
a1d0ce821   Steven Rostedt   tracing: Use clas...
111
  		    tp_event->class && tp_event->class->reg &&
1c024eca5   Peter Zijlstra   perf, trace: Opti...
112
113
  		    try_module_get(tp_event->mod)) {
  			ret = perf_trace_event_init(tp_event, p_event);
9cb627d5f   Li Zefan   perf, trace: Fix ...
114
115
  			if (ret)
  				module_put(tp_event->mod);
20c8928ab   Li Zefan   tracing/events: f...
116
117
  			break;
  		}
ac199db01   Peter Zijlstra   ftrace: event pro...
118
  	}
20c8928ab   Li Zefan   tracing/events: f...
119
  	mutex_unlock(&event_mutex);
ac199db01   Peter Zijlstra   ftrace: event pro...
120

20c8928ab   Li Zefan   tracing/events: f...
121
  	return ret;
ac199db01   Peter Zijlstra   ftrace: event pro...
122
  }
a4eaf7f14   Peter Zijlstra   perf: Rework the ...
123
  int perf_trace_add(struct perf_event *p_event, int flags)
e5e25cf47   Frederic Weisbecker   tracing: Factoriz...
124
  {
1c024eca5   Peter Zijlstra   perf, trace: Opti...
125
  	struct ftrace_event_call *tp_event = p_event->tp_event;
6016ee13d   Namhyung Kim   perf, tracing: ad...
126
  	struct hlist_head __percpu *pcpu_list;
1c024eca5   Peter Zijlstra   perf, trace: Opti...
127
  	struct hlist_head *list;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
128

6016ee13d   Namhyung Kim   perf, tracing: ad...
129
130
  	pcpu_list = tp_event->perf_events;
  	if (WARN_ON_ONCE(!pcpu_list))
1c024eca5   Peter Zijlstra   perf, trace: Opti...
131
  		return -EINVAL;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
132

a4eaf7f14   Peter Zijlstra   perf: Rework the ...
133
134
  	if (!(flags & PERF_EF_START))
  		p_event->hw.state = PERF_HES_STOPPED;
6016ee13d   Namhyung Kim   perf, tracing: ad...
135
  	list = this_cpu_ptr(pcpu_list);
1c024eca5   Peter Zijlstra   perf, trace: Opti...
136
  	hlist_add_head_rcu(&p_event->hlist_entry, list);
20ab4425a   Frederic Weisbecker   tracing: Allocate...
137

1c024eca5   Peter Zijlstra   perf, trace: Opti...
138
139
  	return 0;
  }
20ab4425a   Frederic Weisbecker   tracing: Allocate...
140

a4eaf7f14   Peter Zijlstra   perf: Rework the ...
141
  void perf_trace_del(struct perf_event *p_event, int flags)
1c024eca5   Peter Zijlstra   perf, trace: Opti...
142
143
  {
  	hlist_del_rcu(&p_event->hlist_entry);
e5e25cf47   Frederic Weisbecker   tracing: Factoriz...
144
  }
1c024eca5   Peter Zijlstra   perf, trace: Opti...
145
  void perf_trace_destroy(struct perf_event *p_event)
ac199db01   Peter Zijlstra   ftrace: event pro...
146
  {
1c024eca5   Peter Zijlstra   perf, trace: Opti...
147
148
  	struct ftrace_event_call *tp_event = p_event->tp_event;
  	int i;
ac199db01   Peter Zijlstra   ftrace: event pro...
149

2e97942fe   Peter Zijlstra   perf_events, trac...
150
  	mutex_lock(&event_mutex);
1c024eca5   Peter Zijlstra   perf, trace: Opti...
151
  	if (--tp_event->perf_refcount > 0)
2e97942fe   Peter Zijlstra   perf_events, trac...
152
  		goto out;
1c024eca5   Peter Zijlstra   perf, trace: Opti...
153

a1d0ce821   Steven Rostedt   tracing: Use clas...
154
  	tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER);
1c024eca5   Peter Zijlstra   perf, trace: Opti...
155

3771f0771   Peter Zijlstra   perf_events, trac...
156
  	/*
669336e4c   Frederic Weisbecker   perf: Use tracepo...
157
158
  	 * Ensure our callback won't be called anymore. The buffers
  	 * will be freed after that.
3771f0771   Peter Zijlstra   perf_events, trac...
159
  	 */
669336e4c   Frederic Weisbecker   perf: Use tracepo...
160
  	tracepoint_synchronize_unregister();
3771f0771   Peter Zijlstra   perf_events, trac...
161

1c024eca5   Peter Zijlstra   perf, trace: Opti...
162
163
164
165
  	free_percpu(tp_event->perf_events);
  	tp_event->perf_events = NULL;
  
  	if (!--total_ref_count) {
7ae07ea3a   Frederic Weisbecker   perf: Humanize th...
166
  		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
1c024eca5   Peter Zijlstra   perf, trace: Opti...
167
168
  			free_percpu(perf_trace_buf[i]);
  			perf_trace_buf[i] = NULL;
20c8928ab   Li Zefan   tracing/events: f...
169
  		}
ac199db01   Peter Zijlstra   ftrace: event pro...
170
  	}
2e97942fe   Peter Zijlstra   perf_events, trac...
171
  out:
9cb627d5f   Li Zefan   perf, trace: Fix ...
172
  	module_put(tp_event->mod);
2e97942fe   Peter Zijlstra   perf_events, trac...
173
  	mutex_unlock(&event_mutex);
ac199db01   Peter Zijlstra   ftrace: event pro...
174
  }
430ad5a60   Xiao Guangrong   perf: Factorize t...
175

97d5a2200   Frederic Weisbecker   perf: Drop the ob...
176
  __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
b7e2ecef9   Peter Zijlstra   perf, trace: Opti...
177
  				       struct pt_regs *regs, int *rctxp)
430ad5a60   Xiao Guangrong   perf: Factorize t...
178
179
  {
  	struct trace_entry *entry;
87f44bbc2   Peter Zijlstra   perf, trace: Fix ...
180
  	unsigned long flags;
1c024eca5   Peter Zijlstra   perf, trace: Opti...
181
  	char *raw_data;
b7e2ecef9   Peter Zijlstra   perf, trace: Opti...
182
  	int pc;
430ad5a60   Xiao Guangrong   perf: Factorize t...
183

eb1e79611   Frederic Weisbecker   perf: Correctly a...
184
  	BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long));
430ad5a60   Xiao Guangrong   perf: Factorize t...
185
  	pc = preempt_count();
430ad5a60   Xiao Guangrong   perf: Factorize t...
186
187
  	*rctxp = perf_swevent_get_recursion_context();
  	if (*rctxp < 0)
1c024eca5   Peter Zijlstra   perf, trace: Opti...
188
  		return NULL;
430ad5a60   Xiao Guangrong   perf: Factorize t...
189

3771f0771   Peter Zijlstra   perf_events, trac...
190
  	raw_data = this_cpu_ptr(perf_trace_buf[*rctxp]);
430ad5a60   Xiao Guangrong   perf: Factorize t...
191
192
  
  	/* zero the dead bytes from align to not leak stack to user */
eb1e79611   Frederic Weisbecker   perf: Correctly a...
193
  	memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64));
430ad5a60   Xiao Guangrong   perf: Factorize t...
194
195
  
  	entry = (struct trace_entry *)raw_data;
87f44bbc2   Peter Zijlstra   perf, trace: Fix ...
196
197
  	local_save_flags(flags);
  	tracing_generic_entry_update(entry, flags, pc);
430ad5a60   Xiao Guangrong   perf: Factorize t...
198
199
200
  	entry->type = type;
  
  	return raw_data;
430ad5a60   Xiao Guangrong   perf: Factorize t...
201
  }
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
202
  EXPORT_SYMBOL_GPL(perf_trace_buf_prepare);