1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
235e8e302SSteven Rostedt /*
335e8e302SSteven Rostedt  * trace context switch
435e8e302SSteven Rostedt  *
535e8e302SSteven Rostedt  * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com>
635e8e302SSteven Rostedt  *
735e8e302SSteven Rostedt  */
835e8e302SSteven Rostedt #include <linux/module.h>
935e8e302SSteven Rostedt #include <linux/kallsyms.h>
1035e8e302SSteven Rostedt #include <linux/uaccess.h>
1135e8e302SSteven Rostedt #include <linux/ftrace.h>
12ad8d75ffSSteven Rostedt #include <trace/events/sched.h>
1335e8e302SSteven Rostedt 
1435e8e302SSteven Rostedt #include "trace.h"
1535e8e302SSteven Rostedt 
16d914ba37SJoel Fernandes #define RECORD_CMDLINE	1
17d914ba37SJoel Fernandes #define RECORD_TGID	2
18d914ba37SJoel Fernandes 
19d914ba37SJoel Fernandes static int		sched_cmdline_ref;
20d914ba37SJoel Fernandes static int		sched_tgid_ref;
21efade6e7SFrederic Weisbecker static DEFINE_MUTEX(sched_register_mutex);
2282e04af4SFrederic Weisbecker 
23e309b41dSIngo Molnar static void
probe_sched_switch(void * ignore,bool preempt,struct task_struct * prev,struct task_struct * next,unsigned int prev_state)24c73464b1SPeter Zijlstra probe_sched_switch(void *ignore, bool preempt,
25*9c2136beSDelyan Kratunov 		   struct task_struct *prev, struct task_struct *next,
26*9c2136beSDelyan Kratunov 		   unsigned int prev_state)
2735e8e302SSteven Rostedt {
28d914ba37SJoel Fernandes 	int flags;
29b07c3f19SMathieu Desnoyers 
30d914ba37SJoel Fernandes 	flags = (RECORD_TGID * !!sched_tgid_ref) +
31d914ba37SJoel Fernandes 		(RECORD_CMDLINE * !!sched_cmdline_ref);
32d914ba37SJoel Fernandes 
33d914ba37SJoel Fernandes 	if (!flags)
34d914ba37SJoel Fernandes 		return;
35d914ba37SJoel Fernandes 	tracing_record_taskinfo_sched_switch(prev, next, flags);
3635e8e302SSteven Rostedt }
3735e8e302SSteven Rostedt 
385b82a1b0SMathieu Desnoyers static void
probe_sched_wakeup(void * ignore,struct task_struct * wakee)39fbd705a0SPeter Zijlstra probe_sched_wakeup(void *ignore, struct task_struct *wakee)
405b82a1b0SMathieu Desnoyers {
41d914ba37SJoel Fernandes 	int flags;
42dcef788eSZhaolei 
43d914ba37SJoel Fernandes 	flags = (RECORD_TGID * !!sched_tgid_ref) +
44d914ba37SJoel Fernandes 		(RECORD_CMDLINE * !!sched_cmdline_ref);
45d914ba37SJoel Fernandes 
46d914ba37SJoel Fernandes 	if (!flags)
47d914ba37SJoel Fernandes 		return;
4855bc8384SSteven Rostedt (Google) 	tracing_record_taskinfo_sched_switch(current, wakee, flags);
4957422797SIngo Molnar }
5057422797SIngo Molnar 
tracing_sched_register(void)515b82a1b0SMathieu Desnoyers static int tracing_sched_register(void)
525b82a1b0SMathieu Desnoyers {
535b82a1b0SMathieu Desnoyers 	int ret;
545b82a1b0SMathieu Desnoyers 
5538516ab5SSteven Rostedt 	ret = register_trace_sched_wakeup(probe_sched_wakeup, NULL);
565b82a1b0SMathieu Desnoyers 	if (ret) {
57b07c3f19SMathieu Desnoyers 		pr_info("wakeup trace: Couldn't activate tracepoint"
585b82a1b0SMathieu Desnoyers 			" probe to kernel_sched_wakeup\n");
595b82a1b0SMathieu Desnoyers 		return ret;
605b82a1b0SMathieu Desnoyers 	}
615b82a1b0SMathieu Desnoyers 
6238516ab5SSteven Rostedt 	ret = register_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
635b82a1b0SMathieu Desnoyers 	if (ret) {
64b07c3f19SMathieu Desnoyers 		pr_info("wakeup trace: Couldn't activate tracepoint"
655b82a1b0SMathieu Desnoyers 			" probe to kernel_sched_wakeup_new\n");
665b82a1b0SMathieu Desnoyers 		goto fail_deprobe;
675b82a1b0SMathieu Desnoyers 	}
685b82a1b0SMathieu Desnoyers 
6938516ab5SSteven Rostedt 	ret = register_trace_sched_switch(probe_sched_switch, NULL);
705b82a1b0SMathieu Desnoyers 	if (ret) {
71b07c3f19SMathieu Desnoyers 		pr_info("sched trace: Couldn't activate tracepoint"
7273d8b8bcSWenji Huang 			" probe to kernel_sched_switch\n");
735b82a1b0SMathieu Desnoyers 		goto fail_deprobe_wake_new;
745b82a1b0SMathieu Desnoyers 	}
755b82a1b0SMathieu Desnoyers 
765b82a1b0SMathieu Desnoyers 	return ret;
775b82a1b0SMathieu Desnoyers fail_deprobe_wake_new:
7838516ab5SSteven Rostedt 	unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
795b82a1b0SMathieu Desnoyers fail_deprobe:
8038516ab5SSteven Rostedt 	unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
815b82a1b0SMathieu Desnoyers 	return ret;
825b82a1b0SMathieu Desnoyers }
835b82a1b0SMathieu Desnoyers 
tracing_sched_unregister(void)845b82a1b0SMathieu Desnoyers static void tracing_sched_unregister(void)
855b82a1b0SMathieu Desnoyers {
8638516ab5SSteven Rostedt 	unregister_trace_sched_switch(probe_sched_switch, NULL);
8738516ab5SSteven Rostedt 	unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
8838516ab5SSteven Rostedt 	unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
895b82a1b0SMathieu Desnoyers }
905b82a1b0SMathieu Desnoyers 
tracing_start_sched_switch(int ops)91d914ba37SJoel Fernandes static void tracing_start_sched_switch(int ops)
925b82a1b0SMathieu Desnoyers {
9364ae572bSMathieu Desnoyers 	bool sched_register;
9464ae572bSMathieu Desnoyers 
95efade6e7SFrederic Weisbecker 	mutex_lock(&sched_register_mutex);
9664ae572bSMathieu Desnoyers 	sched_register = (!sched_cmdline_ref && !sched_tgid_ref);
97d914ba37SJoel Fernandes 
98d914ba37SJoel Fernandes 	switch (ops) {
99d914ba37SJoel Fernandes 	case RECORD_CMDLINE:
100d914ba37SJoel Fernandes 		sched_cmdline_ref++;
101d914ba37SJoel Fernandes 		break;
102d914ba37SJoel Fernandes 
103d914ba37SJoel Fernandes 	case RECORD_TGID:
104d914ba37SJoel Fernandes 		sched_tgid_ref++;
105d914ba37SJoel Fernandes 		break;
106d914ba37SJoel Fernandes 	}
107d914ba37SJoel Fernandes 
108d914ba37SJoel Fernandes 	if (sched_register && (sched_cmdline_ref || sched_tgid_ref))
1095b82a1b0SMathieu Desnoyers 		tracing_sched_register();
110efade6e7SFrederic Weisbecker 	mutex_unlock(&sched_register_mutex);
1115b82a1b0SMathieu Desnoyers }
1125b82a1b0SMathieu Desnoyers 
tracing_stop_sched_switch(int ops)113d914ba37SJoel Fernandes static void tracing_stop_sched_switch(int ops)
1145b82a1b0SMathieu Desnoyers {
115efade6e7SFrederic Weisbecker 	mutex_lock(&sched_register_mutex);
116d914ba37SJoel Fernandes 
117d914ba37SJoel Fernandes 	switch (ops) {
118d914ba37SJoel Fernandes 	case RECORD_CMDLINE:
119d914ba37SJoel Fernandes 		sched_cmdline_ref--;
120d914ba37SJoel Fernandes 		break;
121d914ba37SJoel Fernandes 
122d914ba37SJoel Fernandes 	case RECORD_TGID:
123d914ba37SJoel Fernandes 		sched_tgid_ref--;
124d914ba37SJoel Fernandes 		break;
125d914ba37SJoel Fernandes 	}
126d914ba37SJoel Fernandes 
127d914ba37SJoel Fernandes 	if (!sched_cmdline_ref && !sched_tgid_ref)
1285b82a1b0SMathieu Desnoyers 		tracing_sched_unregister();
129efade6e7SFrederic Weisbecker 	mutex_unlock(&sched_register_mutex);
1305b82a1b0SMathieu Desnoyers }
1315b82a1b0SMathieu Desnoyers 
tracing_start_cmdline_record(void)13241bc8144SSteven Rostedt void tracing_start_cmdline_record(void)
13341bc8144SSteven Rostedt {
134d914ba37SJoel Fernandes 	tracing_start_sched_switch(RECORD_CMDLINE);
13541bc8144SSteven Rostedt }
13641bc8144SSteven Rostedt 
tracing_stop_cmdline_record(void)13741bc8144SSteven Rostedt void tracing_stop_cmdline_record(void)
13841bc8144SSteven Rostedt {
139d914ba37SJoel Fernandes 	tracing_stop_sched_switch(RECORD_CMDLINE);
140d914ba37SJoel Fernandes }
141d914ba37SJoel Fernandes 
tracing_start_tgid_record(void)142d914ba37SJoel Fernandes void tracing_start_tgid_record(void)
143d914ba37SJoel Fernandes {
144d914ba37SJoel Fernandes 	tracing_start_sched_switch(RECORD_TGID);
145d914ba37SJoel Fernandes }
146d914ba37SJoel Fernandes 
tracing_stop_tgid_record(void)147d914ba37SJoel Fernandes void tracing_stop_tgid_record(void)
148d914ba37SJoel Fernandes {
149d914ba37SJoel Fernandes 	tracing_stop_sched_switch(RECORD_TGID);
15041bc8144SSteven Rostedt }
151