1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * trace context switch 4 * 5 * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com> 6 * 7 */ 8 #include <linux/module.h> 9 #include <linux/kallsyms.h> 10 #include <linux/uaccess.h> 11 #include <linux/ftrace.h> 12 #include <trace/events/sched.h> 13 14 #include "trace.h" 15 16 #define RECORD_CMDLINE 1 17 #define RECORD_TGID 2 18 19 static int sched_cmdline_ref; 20 static int sched_tgid_ref; 21 static DEFINE_MUTEX(sched_register_mutex); 22 23 static void 24 probe_sched_switch(void *ignore, bool preempt, 25 unsigned int prev_state, 26 struct task_struct *prev, struct task_struct *next) 27 { 28 int flags; 29 30 flags = (RECORD_TGID * !!sched_tgid_ref) + 31 (RECORD_CMDLINE * !!sched_cmdline_ref); 32 33 if (!flags) 34 return; 35 tracing_record_taskinfo_sched_switch(prev, next, flags); 36 } 37 38 static void 39 probe_sched_wakeup(void *ignore, struct task_struct *wakee) 40 { 41 int flags; 42 43 flags = (RECORD_TGID * !!sched_tgid_ref) + 44 (RECORD_CMDLINE * !!sched_cmdline_ref); 45 46 if (!flags) 47 return; 48 tracing_record_taskinfo_sched_switch(current, wakee, flags); 49 } 50 51 static int tracing_sched_register(void) 52 { 53 int ret; 54 55 ret = register_trace_sched_wakeup(probe_sched_wakeup, NULL); 56 if (ret) { 57 pr_info("wakeup trace: Couldn't activate tracepoint" 58 " probe to kernel_sched_wakeup\n"); 59 return ret; 60 } 61 62 ret = register_trace_sched_wakeup_new(probe_sched_wakeup, NULL); 63 if (ret) { 64 pr_info("wakeup trace: Couldn't activate tracepoint" 65 " probe to kernel_sched_wakeup_new\n"); 66 goto fail_deprobe; 67 } 68 69 ret = register_trace_sched_switch(probe_sched_switch, NULL); 70 if (ret) { 71 pr_info("sched trace: Couldn't activate tracepoint" 72 " probe to kernel_sched_switch\n"); 73 goto fail_deprobe_wake_new; 74 } 75 76 return ret; 77 fail_deprobe_wake_new: 78 unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL); 79 fail_deprobe: 80 unregister_trace_sched_wakeup(probe_sched_wakeup, NULL); 81 return ret; 82 } 83 84 static void tracing_sched_unregister(void) 85 { 86 unregister_trace_sched_switch(probe_sched_switch, NULL); 87 unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL); 88 unregister_trace_sched_wakeup(probe_sched_wakeup, NULL); 89 } 90 91 static void tracing_start_sched_switch(int ops) 92 { 93 bool sched_register; 94 95 mutex_lock(&sched_register_mutex); 96 sched_register = (!sched_cmdline_ref && !sched_tgid_ref); 97 98 switch (ops) { 99 case RECORD_CMDLINE: 100 sched_cmdline_ref++; 101 break; 102 103 case RECORD_TGID: 104 sched_tgid_ref++; 105 break; 106 } 107 108 if (sched_register && (sched_cmdline_ref || sched_tgid_ref)) 109 tracing_sched_register(); 110 mutex_unlock(&sched_register_mutex); 111 } 112 113 static void tracing_stop_sched_switch(int ops) 114 { 115 mutex_lock(&sched_register_mutex); 116 117 switch (ops) { 118 case RECORD_CMDLINE: 119 sched_cmdline_ref--; 120 break; 121 122 case RECORD_TGID: 123 sched_tgid_ref--; 124 break; 125 } 126 127 if (!sched_cmdline_ref && !sched_tgid_ref) 128 tracing_sched_unregister(); 129 mutex_unlock(&sched_register_mutex); 130 } 131 132 void tracing_start_cmdline_record(void) 133 { 134 tracing_start_sched_switch(RECORD_CMDLINE); 135 } 136 137 void tracing_stop_cmdline_record(void) 138 { 139 tracing_stop_sched_switch(RECORD_CMDLINE); 140 } 141 142 void tracing_start_tgid_record(void) 143 { 144 tracing_start_sched_switch(RECORD_TGID); 145 } 146 147 void tracing_stop_tgid_record(void) 148 { 149 tracing_stop_sched_switch(RECORD_TGID); 150 } 151