xref: /linux/kernel/trace/trace_event_perf.c (revision a6ca88b241d5e929e6e60b12ad8cd288f0ffa256)
1bcea3f96SSteven Rostedt (VMware) // SPDX-License-Identifier: GPL-2.0
297d5a220SFrederic Weisbecker /*
397d5a220SFrederic Weisbecker  * trace event based perf event profiling/tracing
497d5a220SFrederic Weisbecker  *
590eec103SPeter Zijlstra  * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra
697d5a220SFrederic Weisbecker  * Copyright (C) 2009-2010 Frederic Weisbecker <fweisbec@gmail.com>
797d5a220SFrederic Weisbecker  */
897d5a220SFrederic Weisbecker 
997d5a220SFrederic Weisbecker #include <linux/module.h>
1097d5a220SFrederic Weisbecker #include <linux/kprobes.h>
1197d5a220SFrederic Weisbecker #include "trace.h"
12e12f03d7SSong Liu #include "trace_probe.h"
1397d5a220SFrederic Weisbecker 
146016ee13SNamhyung Kim static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS];
1597d5a220SFrederic Weisbecker 
16eb1e7961SFrederic Weisbecker /*
17eb1e7961SFrederic Weisbecker  * Force it to be aligned to unsigned long to avoid misaligned accesses
18eb1e7961SFrederic Weisbecker  * suprises
19eb1e7961SFrederic Weisbecker  */
20eb1e7961SFrederic Weisbecker typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)])
21eb1e7961SFrederic Weisbecker 	perf_trace_t;
2297d5a220SFrederic Weisbecker 
2397d5a220SFrederic Weisbecker /* Count the events in use (per event id, not per instance) */
2497d5a220SFrederic Weisbecker static int	total_ref_count;
2597d5a220SFrederic Weisbecker 
262425bcb9SSteven Rostedt (Red Hat) static int perf_trace_event_perm(struct trace_event_call *tp_event,
2761c32659SFrederic Weisbecker 				 struct perf_event *p_event)
2861c32659SFrederic Weisbecker {
29d5b5f391SPeter Zijlstra 	if (tp_event->perf_perm) {
30d5b5f391SPeter Zijlstra 		int ret = tp_event->perf_perm(tp_event, p_event);
31d5b5f391SPeter Zijlstra 		if (ret)
32d5b5f391SPeter Zijlstra 			return ret;
33d5b5f391SPeter Zijlstra 	}
34d5b5f391SPeter Zijlstra 
35f4be073dSJiri Olsa 	/*
36f4be073dSJiri Olsa 	 * We checked and allowed to create parent,
37f4be073dSJiri Olsa 	 * allow children without checking.
38f4be073dSJiri Olsa 	 */
39f4be073dSJiri Olsa 	if (p_event->parent)
40f4be073dSJiri Olsa 		return 0;
41f4be073dSJiri Olsa 
42f4be073dSJiri Olsa 	/*
43f4be073dSJiri Olsa 	 * It's ok to check current process (owner) permissions in here,
44f4be073dSJiri Olsa 	 * because code below is called only via perf_event_open syscall.
45f4be073dSJiri Olsa 	 */
46f4be073dSJiri Olsa 
47ced39002SJiri Olsa 	/* The ftrace function trace is allowed only for root. */
48cfa77bc4SJiri Olsa 	if (ftrace_event_is_function(tp_event)) {
49cfa77bc4SJiri Olsa 		if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
50ced39002SJiri Olsa 			return -EPERM;
51ced39002SJiri Olsa 
520a74c5b3SJiri Olsa 		if (!is_sampling_event(p_event))
530a74c5b3SJiri Olsa 			return 0;
540a74c5b3SJiri Olsa 
55cfa77bc4SJiri Olsa 		/*
56cfa77bc4SJiri Olsa 		 * We don't allow user space callchains for  function trace
57cfa77bc4SJiri Olsa 		 * event, due to issues with page faults while tracing page
58cfa77bc4SJiri Olsa 		 * fault handler and its overall trickiness nature.
59cfa77bc4SJiri Olsa 		 */
60cfa77bc4SJiri Olsa 		if (!p_event->attr.exclude_callchain_user)
61cfa77bc4SJiri Olsa 			return -EINVAL;
6263c45f4bSJiri Olsa 
6363c45f4bSJiri Olsa 		/*
6463c45f4bSJiri Olsa 		 * Same reason to disable user stack dump as for user space
6563c45f4bSJiri Olsa 		 * callchains above.
6663c45f4bSJiri Olsa 		 */
6763c45f4bSJiri Olsa 		if (p_event->attr.sample_type & PERF_SAMPLE_STACK_USER)
6863c45f4bSJiri Olsa 			return -EINVAL;
69cfa77bc4SJiri Olsa 	}
70cfa77bc4SJiri Olsa 
7161c32659SFrederic Weisbecker 	/* No tracing, just counting, so no obvious leak */
7261c32659SFrederic Weisbecker 	if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW))
7361c32659SFrederic Weisbecker 		return 0;
7461c32659SFrederic Weisbecker 
7561c32659SFrederic Weisbecker 	/* Some events are ok to be traced by non-root users... */
7661c32659SFrederic Weisbecker 	if (p_event->attach_state == PERF_ATTACH_TASK) {
7761c32659SFrederic Weisbecker 		if (tp_event->flags & TRACE_EVENT_FL_CAP_ANY)
7861c32659SFrederic Weisbecker 			return 0;
7961c32659SFrederic Weisbecker 	}
8061c32659SFrederic Weisbecker 
8161c32659SFrederic Weisbecker 	/*
8261c32659SFrederic Weisbecker 	 * ...otherwise raw tracepoint data can be a severe data leak,
8361c32659SFrederic Weisbecker 	 * only allow root to have these.
8461c32659SFrederic Weisbecker 	 */
8561c32659SFrederic Weisbecker 	if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
8661c32659SFrederic Weisbecker 		return -EPERM;
8761c32659SFrederic Weisbecker 
8861c32659SFrederic Weisbecker 	return 0;
8961c32659SFrederic Weisbecker }
9061c32659SFrederic Weisbecker 
912425bcb9SSteven Rostedt (Red Hat) static int perf_trace_event_reg(struct trace_event_call *tp_event,
921c024ecaSPeter Zijlstra 				struct perf_event *p_event)
9397d5a220SFrederic Weisbecker {
946016ee13SNamhyung Kim 	struct hlist_head __percpu *list;
95ceec0b6fSJiri Olsa 	int ret = -ENOMEM;
961c024ecaSPeter Zijlstra 	int cpu;
9797d5a220SFrederic Weisbecker 
981c024ecaSPeter Zijlstra 	p_event->tp_event = tp_event;
991c024ecaSPeter Zijlstra 	if (tp_event->perf_refcount++ > 0)
10097d5a220SFrederic Weisbecker 		return 0;
10197d5a220SFrederic Weisbecker 
1021c024ecaSPeter Zijlstra 	list = alloc_percpu(struct hlist_head);
1031c024ecaSPeter Zijlstra 	if (!list)
1041c024ecaSPeter Zijlstra 		goto fail;
1051c024ecaSPeter Zijlstra 
1061c024ecaSPeter Zijlstra 	for_each_possible_cpu(cpu)
1071c024ecaSPeter Zijlstra 		INIT_HLIST_HEAD(per_cpu_ptr(list, cpu));
1081c024ecaSPeter Zijlstra 
1091c024ecaSPeter Zijlstra 	tp_event->perf_events = list;
11097d5a220SFrederic Weisbecker 
11197d5a220SFrederic Weisbecker 	if (!total_ref_count) {
1126016ee13SNamhyung Kim 		char __percpu *buf;
113b7e2ecefSPeter Zijlstra 		int i;
114b7e2ecefSPeter Zijlstra 
1157ae07ea3SFrederic Weisbecker 		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
1166016ee13SNamhyung Kim 			buf = (char __percpu *)alloc_percpu(perf_trace_t);
11797d5a220SFrederic Weisbecker 			if (!buf)
1181c024ecaSPeter Zijlstra 				goto fail;
11997d5a220SFrederic Weisbecker 
1201c024ecaSPeter Zijlstra 			perf_trace_buf[i] = buf;
121b7e2ecefSPeter Zijlstra 		}
12297d5a220SFrederic Weisbecker 	}
12397d5a220SFrederic Weisbecker 
124ceec0b6fSJiri Olsa 	ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER, NULL);
1251c024ecaSPeter Zijlstra 	if (ret)
1261c024ecaSPeter Zijlstra 		goto fail;
1271c024ecaSPeter Zijlstra 
12897d5a220SFrederic Weisbecker 	total_ref_count++;
12997d5a220SFrederic Weisbecker 	return 0;
13097d5a220SFrederic Weisbecker 
1311c024ecaSPeter Zijlstra fail:
132b7e2ecefSPeter Zijlstra 	if (!total_ref_count) {
133b7e2ecefSPeter Zijlstra 		int i;
134b7e2ecefSPeter Zijlstra 
1357ae07ea3SFrederic Weisbecker 		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
136b7e2ecefSPeter Zijlstra 			free_percpu(perf_trace_buf[i]);
137b7e2ecefSPeter Zijlstra 			perf_trace_buf[i] = NULL;
138b7e2ecefSPeter Zijlstra 		}
13997d5a220SFrederic Weisbecker 	}
14097d5a220SFrederic Weisbecker 
1411c024ecaSPeter Zijlstra 	if (!--tp_event->perf_refcount) {
1421c024ecaSPeter Zijlstra 		free_percpu(tp_event->perf_events);
1431c024ecaSPeter Zijlstra 		tp_event->perf_events = NULL;
14497d5a220SFrederic Weisbecker 	}
14597d5a220SFrederic Weisbecker 
14697d5a220SFrederic Weisbecker 	return ret;
14797d5a220SFrederic Weisbecker }
14897d5a220SFrederic Weisbecker 
149ceec0b6fSJiri Olsa static void perf_trace_event_unreg(struct perf_event *p_event)
150ceec0b6fSJiri Olsa {
1512425bcb9SSteven Rostedt (Red Hat) 	struct trace_event_call *tp_event = p_event->tp_event;
152ceec0b6fSJiri Olsa 	int i;
153ceec0b6fSJiri Olsa 
154ceec0b6fSJiri Olsa 	if (--tp_event->perf_refcount > 0)
155ceec0b6fSJiri Olsa 		goto out;
156ceec0b6fSJiri Olsa 
157ceec0b6fSJiri Olsa 	tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER, NULL);
158ceec0b6fSJiri Olsa 
159ceec0b6fSJiri Olsa 	/*
160ceec0b6fSJiri Olsa 	 * Ensure our callback won't be called anymore. The buffers
161ceec0b6fSJiri Olsa 	 * will be freed after that.
162ceec0b6fSJiri Olsa 	 */
163ceec0b6fSJiri Olsa 	tracepoint_synchronize_unregister();
164ceec0b6fSJiri Olsa 
165ceec0b6fSJiri Olsa 	free_percpu(tp_event->perf_events);
166ceec0b6fSJiri Olsa 	tp_event->perf_events = NULL;
167ceec0b6fSJiri Olsa 
168ceec0b6fSJiri Olsa 	if (!--total_ref_count) {
169ceec0b6fSJiri Olsa 		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
170ceec0b6fSJiri Olsa 			free_percpu(perf_trace_buf[i]);
171ceec0b6fSJiri Olsa 			perf_trace_buf[i] = NULL;
172ceec0b6fSJiri Olsa 		}
173ceec0b6fSJiri Olsa 	}
174ceec0b6fSJiri Olsa out:
175ceec0b6fSJiri Olsa 	module_put(tp_event->mod);
176ceec0b6fSJiri Olsa }
177ceec0b6fSJiri Olsa 
178ceec0b6fSJiri Olsa static int perf_trace_event_open(struct perf_event *p_event)
179ceec0b6fSJiri Olsa {
1802425bcb9SSteven Rostedt (Red Hat) 	struct trace_event_call *tp_event = p_event->tp_event;
181ceec0b6fSJiri Olsa 	return tp_event->class->reg(tp_event, TRACE_REG_PERF_OPEN, p_event);
182ceec0b6fSJiri Olsa }
183ceec0b6fSJiri Olsa 
184ceec0b6fSJiri Olsa static void perf_trace_event_close(struct perf_event *p_event)
185ceec0b6fSJiri Olsa {
1862425bcb9SSteven Rostedt (Red Hat) 	struct trace_event_call *tp_event = p_event->tp_event;
187ceec0b6fSJiri Olsa 	tp_event->class->reg(tp_event, TRACE_REG_PERF_CLOSE, p_event);
188ceec0b6fSJiri Olsa }
189ceec0b6fSJiri Olsa 
1902425bcb9SSteven Rostedt (Red Hat) static int perf_trace_event_init(struct trace_event_call *tp_event,
191ceec0b6fSJiri Olsa 				 struct perf_event *p_event)
192ceec0b6fSJiri Olsa {
193ceec0b6fSJiri Olsa 	int ret;
194ceec0b6fSJiri Olsa 
195ceec0b6fSJiri Olsa 	ret = perf_trace_event_perm(tp_event, p_event);
196ceec0b6fSJiri Olsa 	if (ret)
197ceec0b6fSJiri Olsa 		return ret;
198ceec0b6fSJiri Olsa 
199ceec0b6fSJiri Olsa 	ret = perf_trace_event_reg(tp_event, p_event);
200ceec0b6fSJiri Olsa 	if (ret)
201ceec0b6fSJiri Olsa 		return ret;
202ceec0b6fSJiri Olsa 
203ceec0b6fSJiri Olsa 	ret = perf_trace_event_open(p_event);
204ceec0b6fSJiri Olsa 	if (ret) {
205ceec0b6fSJiri Olsa 		perf_trace_event_unreg(p_event);
206ceec0b6fSJiri Olsa 		return ret;
207ceec0b6fSJiri Olsa 	}
208ceec0b6fSJiri Olsa 
209ceec0b6fSJiri Olsa 	return 0;
210ceec0b6fSJiri Olsa }
211ceec0b6fSJiri Olsa 
2121c024ecaSPeter Zijlstra int perf_trace_init(struct perf_event *p_event)
21397d5a220SFrederic Weisbecker {
2142425bcb9SSteven Rostedt (Red Hat) 	struct trace_event_call *tp_event;
2150022ceddSVince Weaver 	u64 event_id = p_event->attr.config;
21697d5a220SFrederic Weisbecker 	int ret = -EINVAL;
21797d5a220SFrederic Weisbecker 
21897d5a220SFrederic Weisbecker 	mutex_lock(&event_mutex);
2191c024ecaSPeter Zijlstra 	list_for_each_entry(tp_event, &ftrace_events, list) {
220ff5f149bSSteven Rostedt 		if (tp_event->event.type == event_id &&
221a1d0ce82SSteven Rostedt 		    tp_event->class && tp_event->class->reg &&
2221c024ecaSPeter Zijlstra 		    try_module_get(tp_event->mod)) {
2231c024ecaSPeter Zijlstra 			ret = perf_trace_event_init(tp_event, p_event);
2249cb627d5SLi Zefan 			if (ret)
2259cb627d5SLi Zefan 				module_put(tp_event->mod);
22697d5a220SFrederic Weisbecker 			break;
22797d5a220SFrederic Weisbecker 		}
22897d5a220SFrederic Weisbecker 	}
22997d5a220SFrederic Weisbecker 	mutex_unlock(&event_mutex);
23097d5a220SFrederic Weisbecker 
23197d5a220SFrederic Weisbecker 	return ret;
23297d5a220SFrederic Weisbecker }
23397d5a220SFrederic Weisbecker 
234ceec0b6fSJiri Olsa void perf_trace_destroy(struct perf_event *p_event)
235ceec0b6fSJiri Olsa {
236ceec0b6fSJiri Olsa 	mutex_lock(&event_mutex);
237ceec0b6fSJiri Olsa 	perf_trace_event_close(p_event);
238ceec0b6fSJiri Olsa 	perf_trace_event_unreg(p_event);
239ceec0b6fSJiri Olsa 	mutex_unlock(&event_mutex);
240ceec0b6fSJiri Olsa }
241ceec0b6fSJiri Olsa 
242e12f03d7SSong Liu #ifdef CONFIG_KPROBE_EVENTS
243e12f03d7SSong Liu int perf_kprobe_init(struct perf_event *p_event, bool is_retprobe)
244e12f03d7SSong Liu {
245e12f03d7SSong Liu 	int ret;
246e12f03d7SSong Liu 	char *func = NULL;
247e12f03d7SSong Liu 	struct trace_event_call *tp_event;
248e12f03d7SSong Liu 
249e12f03d7SSong Liu 	if (p_event->attr.kprobe_func) {
250e12f03d7SSong Liu 		func = kzalloc(KSYM_NAME_LEN, GFP_KERNEL);
251e12f03d7SSong Liu 		if (!func)
252e12f03d7SSong Liu 			return -ENOMEM;
253e12f03d7SSong Liu 		ret = strncpy_from_user(
254e12f03d7SSong Liu 			func, u64_to_user_ptr(p_event->attr.kprobe_func),
255e12f03d7SSong Liu 			KSYM_NAME_LEN);
2565da13ab8SMasami Hiramatsu 		if (ret == KSYM_NAME_LEN)
2575da13ab8SMasami Hiramatsu 			ret = -E2BIG;
258e12f03d7SSong Liu 		if (ret < 0)
259e12f03d7SSong Liu 			goto out;
260e12f03d7SSong Liu 
261e12f03d7SSong Liu 		if (func[0] == '\0') {
262e12f03d7SSong Liu 			kfree(func);
263e12f03d7SSong Liu 			func = NULL;
264e12f03d7SSong Liu 		}
265e12f03d7SSong Liu 	}
266e12f03d7SSong Liu 
267e12f03d7SSong Liu 	tp_event = create_local_trace_kprobe(
268e12f03d7SSong Liu 		func, (void *)(unsigned long)(p_event->attr.kprobe_addr),
269e12f03d7SSong Liu 		p_event->attr.probe_offset, is_retprobe);
270e12f03d7SSong Liu 	if (IS_ERR(tp_event)) {
271e12f03d7SSong Liu 		ret = PTR_ERR(tp_event);
272e12f03d7SSong Liu 		goto out;
273e12f03d7SSong Liu 	}
274e12f03d7SSong Liu 
275e12f03d7SSong Liu 	ret = perf_trace_event_init(tp_event, p_event);
276e12f03d7SSong Liu 	if (ret)
277e12f03d7SSong Liu 		destroy_local_trace_kprobe(tp_event);
278e12f03d7SSong Liu out:
279e12f03d7SSong Liu 	kfree(func);
280e12f03d7SSong Liu 	return ret;
281e12f03d7SSong Liu }
282e12f03d7SSong Liu 
283e12f03d7SSong Liu void perf_kprobe_destroy(struct perf_event *p_event)
284e12f03d7SSong Liu {
285e12f03d7SSong Liu 	perf_trace_event_close(p_event);
286e12f03d7SSong Liu 	perf_trace_event_unreg(p_event);
287e12f03d7SSong Liu 
288e12f03d7SSong Liu 	destroy_local_trace_kprobe(p_event->tp_event);
289e12f03d7SSong Liu }
290e12f03d7SSong Liu #endif /* CONFIG_KPROBE_EVENTS */
291e12f03d7SSong Liu 
29233ea4b24SSong Liu #ifdef CONFIG_UPROBE_EVENTS
293*a6ca88b2SSong Liu int perf_uprobe_init(struct perf_event *p_event,
294*a6ca88b2SSong Liu 		     unsigned long ref_ctr_offset, bool is_retprobe)
29533ea4b24SSong Liu {
29633ea4b24SSong Liu 	int ret;
29733ea4b24SSong Liu 	char *path = NULL;
29833ea4b24SSong Liu 	struct trace_event_call *tp_event;
29933ea4b24SSong Liu 
30033ea4b24SSong Liu 	if (!p_event->attr.uprobe_path)
30133ea4b24SSong Liu 		return -EINVAL;
30233ea4b24SSong Liu 	path = kzalloc(PATH_MAX, GFP_KERNEL);
30333ea4b24SSong Liu 	if (!path)
30433ea4b24SSong Liu 		return -ENOMEM;
30533ea4b24SSong Liu 	ret = strncpy_from_user(
30633ea4b24SSong Liu 		path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX);
3070eadcc7aSSong Liu 	if (ret == PATH_MAX)
3080eadcc7aSSong Liu 		return -E2BIG;
30933ea4b24SSong Liu 	if (ret < 0)
31033ea4b24SSong Liu 		goto out;
31133ea4b24SSong Liu 	if (path[0] == '\0') {
31233ea4b24SSong Liu 		ret = -EINVAL;
31333ea4b24SSong Liu 		goto out;
31433ea4b24SSong Liu 	}
31533ea4b24SSong Liu 
316*a6ca88b2SSong Liu 	tp_event = create_local_trace_uprobe(path, p_event->attr.probe_offset,
317*a6ca88b2SSong Liu 					     ref_ctr_offset, is_retprobe);
31833ea4b24SSong Liu 	if (IS_ERR(tp_event)) {
31933ea4b24SSong Liu 		ret = PTR_ERR(tp_event);
32033ea4b24SSong Liu 		goto out;
32133ea4b24SSong Liu 	}
32233ea4b24SSong Liu 
32333ea4b24SSong Liu 	/*
32433ea4b24SSong Liu 	 * local trace_uprobe need to hold event_mutex to call
32533ea4b24SSong Liu 	 * uprobe_buffer_enable() and uprobe_buffer_disable().
32633ea4b24SSong Liu 	 * event_mutex is not required for local trace_kprobes.
32733ea4b24SSong Liu 	 */
32833ea4b24SSong Liu 	mutex_lock(&event_mutex);
32933ea4b24SSong Liu 	ret = perf_trace_event_init(tp_event, p_event);
33033ea4b24SSong Liu 	if (ret)
33133ea4b24SSong Liu 		destroy_local_trace_uprobe(tp_event);
33233ea4b24SSong Liu 	mutex_unlock(&event_mutex);
33333ea4b24SSong Liu out:
33433ea4b24SSong Liu 	kfree(path);
33533ea4b24SSong Liu 	return ret;
33633ea4b24SSong Liu }
33733ea4b24SSong Liu 
33833ea4b24SSong Liu void perf_uprobe_destroy(struct perf_event *p_event)
33933ea4b24SSong Liu {
34033ea4b24SSong Liu 	mutex_lock(&event_mutex);
34133ea4b24SSong Liu 	perf_trace_event_close(p_event);
34233ea4b24SSong Liu 	perf_trace_event_unreg(p_event);
34333ea4b24SSong Liu 	mutex_unlock(&event_mutex);
34433ea4b24SSong Liu 	destroy_local_trace_uprobe(p_event->tp_event);
34533ea4b24SSong Liu }
34633ea4b24SSong Liu #endif /* CONFIG_UPROBE_EVENTS */
34733ea4b24SSong Liu 
348a4eaf7f1SPeter Zijlstra int perf_trace_add(struct perf_event *p_event, int flags)
34997d5a220SFrederic Weisbecker {
3502425bcb9SSteven Rostedt (Red Hat) 	struct trace_event_call *tp_event = p_event->tp_event;
351466c81c4SPeter Zijlstra 
352466c81c4SPeter Zijlstra 	if (!(flags & PERF_EF_START))
353466c81c4SPeter Zijlstra 		p_event->hw.state = PERF_HES_STOPPED;
354466c81c4SPeter Zijlstra 
355466c81c4SPeter Zijlstra 	/*
356466c81c4SPeter Zijlstra 	 * If TRACE_REG_PERF_ADD returns false; no custom action was performed
357466c81c4SPeter Zijlstra 	 * and we need to take the default action of enqueueing our event on
358466c81c4SPeter Zijlstra 	 * the right per-cpu hlist.
359466c81c4SPeter Zijlstra 	 */
360466c81c4SPeter Zijlstra 	if (!tp_event->class->reg(tp_event, TRACE_REG_PERF_ADD, p_event)) {
3616016ee13SNamhyung Kim 		struct hlist_head __percpu *pcpu_list;
3621c024ecaSPeter Zijlstra 		struct hlist_head *list;
36397d5a220SFrederic Weisbecker 
3646016ee13SNamhyung Kim 		pcpu_list = tp_event->perf_events;
3656016ee13SNamhyung Kim 		if (WARN_ON_ONCE(!pcpu_list))
3661c024ecaSPeter Zijlstra 			return -EINVAL;
36797d5a220SFrederic Weisbecker 
3686016ee13SNamhyung Kim 		list = this_cpu_ptr(pcpu_list);
3691c024ecaSPeter Zijlstra 		hlist_add_head_rcu(&p_event->hlist_entry, list);
370466c81c4SPeter Zijlstra 	}
3711c024ecaSPeter Zijlstra 
372466c81c4SPeter Zijlstra 	return 0;
3731c024ecaSPeter Zijlstra }
3741c024ecaSPeter Zijlstra 
375a4eaf7f1SPeter Zijlstra void perf_trace_del(struct perf_event *p_event, int flags)
3761c024ecaSPeter Zijlstra {
3772425bcb9SSteven Rostedt (Red Hat) 	struct trace_event_call *tp_event = p_event->tp_event;
378466c81c4SPeter Zijlstra 
379466c81c4SPeter Zijlstra 	/*
380466c81c4SPeter Zijlstra 	 * If TRACE_REG_PERF_DEL returns false; no custom action was performed
381466c81c4SPeter Zijlstra 	 * and we need to take the default action of dequeueing our event from
382466c81c4SPeter Zijlstra 	 * the right per-cpu hlist.
383466c81c4SPeter Zijlstra 	 */
384466c81c4SPeter Zijlstra 	if (!tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event))
3851c024ecaSPeter Zijlstra 		hlist_del_rcu(&p_event->hlist_entry);
3861c024ecaSPeter Zijlstra }
3871c024ecaSPeter Zijlstra 
3881e1dcd93SAlexei Starovoitov void *perf_trace_buf_alloc(int size, struct pt_regs **regs, int *rctxp)
38997d5a220SFrederic Weisbecker {
3901c024ecaSPeter Zijlstra 	char *raw_data;
3911e1dcd93SAlexei Starovoitov 	int rctx;
39297d5a220SFrederic Weisbecker 
393eb1e7961SFrederic Weisbecker 	BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long));
394eb1e7961SFrederic Weisbecker 
395cd92bf61SOleg Nesterov 	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
396cd92bf61SOleg Nesterov 		      "perf buffer not large enough"))
397cd92bf61SOleg Nesterov 		return NULL;
398cd92bf61SOleg Nesterov 
3991e1dcd93SAlexei Starovoitov 	*rctxp = rctx = perf_swevent_get_recursion_context();
4001e1dcd93SAlexei Starovoitov 	if (rctx < 0)
4011c024ecaSPeter Zijlstra 		return NULL;
40297d5a220SFrederic Weisbecker 
40386038c5eSPeter Zijlstra (Intel) 	if (regs)
4041e1dcd93SAlexei Starovoitov 		*regs = this_cpu_ptr(&__perf_regs[rctx]);
4051e1dcd93SAlexei Starovoitov 	raw_data = this_cpu_ptr(perf_trace_buf[rctx]);
40697d5a220SFrederic Weisbecker 
40797d5a220SFrederic Weisbecker 	/* zero the dead bytes from align to not leak stack to user */
408eb1e7961SFrederic Weisbecker 	memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64));
4091e1dcd93SAlexei Starovoitov 	return raw_data;
4101e1dcd93SAlexei Starovoitov }
4111e1dcd93SAlexei Starovoitov EXPORT_SYMBOL_GPL(perf_trace_buf_alloc);
4121e1dcd93SAlexei Starovoitov NOKPROBE_SYMBOL(perf_trace_buf_alloc);
41397d5a220SFrederic Weisbecker 
4141e1dcd93SAlexei Starovoitov void perf_trace_buf_update(void *record, u16 type)
4151e1dcd93SAlexei Starovoitov {
4161e1dcd93SAlexei Starovoitov 	struct trace_entry *entry = record;
4171e1dcd93SAlexei Starovoitov 	int pc = preempt_count();
4181e1dcd93SAlexei Starovoitov 	unsigned long flags;
4191e1dcd93SAlexei Starovoitov 
42087f44bbcSPeter Zijlstra 	local_save_flags(flags);
42187f44bbcSPeter Zijlstra 	tracing_generic_entry_update(entry, flags, pc);
42297d5a220SFrederic Weisbecker 	entry->type = type;
42397d5a220SFrederic Weisbecker }
4241e1dcd93SAlexei Starovoitov NOKPROBE_SYMBOL(perf_trace_buf_update);
425ced39002SJiri Olsa 
426ced39002SJiri Olsa #ifdef CONFIG_FUNCTION_TRACER
427ced39002SJiri Olsa static void
4282f5f6ad9SSteven Rostedt perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip,
429a1e2e31dSSteven Rostedt 			  struct ftrace_ops *ops, struct pt_regs *pt_regs)
430ced39002SJiri Olsa {
431ced39002SJiri Olsa 	struct ftrace_entry *entry;
432466c81c4SPeter Zijlstra 	struct perf_event *event;
433466c81c4SPeter Zijlstra 	struct hlist_head head;
434ced39002SJiri Olsa 	struct pt_regs regs;
435ced39002SJiri Olsa 	int rctx;
436ced39002SJiri Olsa 
437466c81c4SPeter Zijlstra 	if ((unsigned long)ops->private != smp_processor_id())
438b8ebfd3fSOleg Nesterov 		return;
439b8ebfd3fSOleg Nesterov 
440466c81c4SPeter Zijlstra 	event = container_of(ops, struct perf_event, ftrace_ops);
441466c81c4SPeter Zijlstra 
442466c81c4SPeter Zijlstra 	/*
443466c81c4SPeter Zijlstra 	 * @event->hlist entry is NULL (per INIT_HLIST_NODE), and all
444466c81c4SPeter Zijlstra 	 * the perf code does is hlist_for_each_entry_rcu(), so we can
445466c81c4SPeter Zijlstra 	 * get away with simply setting the @head.first pointer in order
446466c81c4SPeter Zijlstra 	 * to create a singular list.
447466c81c4SPeter Zijlstra 	 */
448466c81c4SPeter Zijlstra 	head.first = &event->hlist_entry;
449466c81c4SPeter Zijlstra 
450ced39002SJiri Olsa #define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \
451ced39002SJiri Olsa 		    sizeof(u64)) - sizeof(u32))
452ced39002SJiri Olsa 
453ced39002SJiri Olsa 	BUILD_BUG_ON(ENTRY_SIZE > PERF_MAX_TRACE_SIZE);
454ced39002SJiri Olsa 
455ec5e099dSAlexei Starovoitov 	memset(&regs, 0, sizeof(regs));
456ced39002SJiri Olsa 	perf_fetch_caller_regs(&regs);
457ced39002SJiri Olsa 
4581e1dcd93SAlexei Starovoitov 	entry = perf_trace_buf_alloc(ENTRY_SIZE, NULL, &rctx);
459ced39002SJiri Olsa 	if (!entry)
460ced39002SJiri Olsa 		return;
461ced39002SJiri Olsa 
462ced39002SJiri Olsa 	entry->ip = ip;
463ced39002SJiri Olsa 	entry->parent_ip = parent_ip;
4641e1dcd93SAlexei Starovoitov 	perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, TRACE_FN,
465466c81c4SPeter Zijlstra 			      1, &regs, &head, NULL);
466ced39002SJiri Olsa 
467ced39002SJiri Olsa #undef ENTRY_SIZE
468ced39002SJiri Olsa }
469ced39002SJiri Olsa 
470ced39002SJiri Olsa static int perf_ftrace_function_register(struct perf_event *event)
471ced39002SJiri Olsa {
472ced39002SJiri Olsa 	struct ftrace_ops *ops = &event->ftrace_ops;
473ced39002SJiri Olsa 
4741dd311e6SPeter Zijlstra 	ops->flags   = FTRACE_OPS_FL_RCU;
475ced39002SJiri Olsa 	ops->func    = perf_ftrace_function_call;
476466c81c4SPeter Zijlstra 	ops->private = (void *)(unsigned long)nr_cpu_ids;
477466c81c4SPeter Zijlstra 
478ced39002SJiri Olsa 	return register_ftrace_function(ops);
479ced39002SJiri Olsa }
480ced39002SJiri Olsa 
481ced39002SJiri Olsa static int perf_ftrace_function_unregister(struct perf_event *event)
482ced39002SJiri Olsa {
483ced39002SJiri Olsa 	struct ftrace_ops *ops = &event->ftrace_ops;
4845500fa51SJiri Olsa 	int ret = unregister_ftrace_function(ops);
4855500fa51SJiri Olsa 	ftrace_free_filter(ops);
4865500fa51SJiri Olsa 	return ret;
487ced39002SJiri Olsa }
488ced39002SJiri Olsa 
4892425bcb9SSteven Rostedt (Red Hat) int perf_ftrace_event_register(struct trace_event_call *call,
490ced39002SJiri Olsa 			       enum trace_reg type, void *data)
491ced39002SJiri Olsa {
492466c81c4SPeter Zijlstra 	struct perf_event *event = data;
493466c81c4SPeter Zijlstra 
494ced39002SJiri Olsa 	switch (type) {
495ced39002SJiri Olsa 	case TRACE_REG_REGISTER:
496ced39002SJiri Olsa 	case TRACE_REG_UNREGISTER:
497ced39002SJiri Olsa 		break;
498ced39002SJiri Olsa 	case TRACE_REG_PERF_REGISTER:
499ced39002SJiri Olsa 	case TRACE_REG_PERF_UNREGISTER:
500ced39002SJiri Olsa 		return 0;
501ced39002SJiri Olsa 	case TRACE_REG_PERF_OPEN:
502ced39002SJiri Olsa 		return perf_ftrace_function_register(data);
503ced39002SJiri Olsa 	case TRACE_REG_PERF_CLOSE:
504ced39002SJiri Olsa 		return perf_ftrace_function_unregister(data);
505ced39002SJiri Olsa 	case TRACE_REG_PERF_ADD:
506466c81c4SPeter Zijlstra 		event->ftrace_ops.private = (void *)(unsigned long)smp_processor_id();
507466c81c4SPeter Zijlstra 		return 1;
508ced39002SJiri Olsa 	case TRACE_REG_PERF_DEL:
509466c81c4SPeter Zijlstra 		event->ftrace_ops.private = (void *)(unsigned long)nr_cpu_ids;
510466c81c4SPeter Zijlstra 		return 1;
511ced39002SJiri Olsa 	}
512ced39002SJiri Olsa 
513ced39002SJiri Olsa 	return -EINVAL;
514ced39002SJiri Olsa }
515ced39002SJiri Olsa #endif /* CONFIG_FUNCTION_TRACER */
516