0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/kallsyms.h>
0010 #include <linux/uaccess.h>
0011 #include <linux/ftrace.h>
0012 #include <trace/events/sched.h>
0013
0014 #include "trace.h"
0015
0016 #define RECORD_CMDLINE 1
0017 #define RECORD_TGID 2
0018
0019 static int sched_cmdline_ref;
0020 static int sched_tgid_ref;
0021 static DEFINE_MUTEX(sched_register_mutex);
0022
0023 static void
0024 probe_sched_switch(void *ignore, bool preempt,
0025 struct task_struct *prev, struct task_struct *next,
0026 unsigned int prev_state)
0027 {
0028 int flags;
0029
0030 flags = (RECORD_TGID * !!sched_tgid_ref) +
0031 (RECORD_CMDLINE * !!sched_cmdline_ref);
0032
0033 if (!flags)
0034 return;
0035 tracing_record_taskinfo_sched_switch(prev, next, flags);
0036 }
0037
0038 static void
0039 probe_sched_wakeup(void *ignore, struct task_struct *wakee)
0040 {
0041 int flags;
0042
0043 flags = (RECORD_TGID * !!sched_tgid_ref) +
0044 (RECORD_CMDLINE * !!sched_cmdline_ref);
0045
0046 if (!flags)
0047 return;
0048 tracing_record_taskinfo_sched_switch(current, wakee, flags);
0049 }
0050
0051 static int tracing_sched_register(void)
0052 {
0053 int ret;
0054
0055 ret = register_trace_sched_wakeup(probe_sched_wakeup, NULL);
0056 if (ret) {
0057 pr_info("wakeup trace: Couldn't activate tracepoint"
0058 " probe to kernel_sched_wakeup\n");
0059 return ret;
0060 }
0061
0062 ret = register_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
0063 if (ret) {
0064 pr_info("wakeup trace: Couldn't activate tracepoint"
0065 " probe to kernel_sched_wakeup_new\n");
0066 goto fail_deprobe;
0067 }
0068
0069 ret = register_trace_sched_switch(probe_sched_switch, NULL);
0070 if (ret) {
0071 pr_info("sched trace: Couldn't activate tracepoint"
0072 " probe to kernel_sched_switch\n");
0073 goto fail_deprobe_wake_new;
0074 }
0075
0076 return ret;
0077 fail_deprobe_wake_new:
0078 unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
0079 fail_deprobe:
0080 unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
0081 return ret;
0082 }
0083
0084 static void tracing_sched_unregister(void)
0085 {
0086 unregister_trace_sched_switch(probe_sched_switch, NULL);
0087 unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
0088 unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
0089 }
0090
0091 static void tracing_start_sched_switch(int ops)
0092 {
0093 bool sched_register;
0094
0095 mutex_lock(&sched_register_mutex);
0096 sched_register = (!sched_cmdline_ref && !sched_tgid_ref);
0097
0098 switch (ops) {
0099 case RECORD_CMDLINE:
0100 sched_cmdline_ref++;
0101 break;
0102
0103 case RECORD_TGID:
0104 sched_tgid_ref++;
0105 break;
0106 }
0107
0108 if (sched_register && (sched_cmdline_ref || sched_tgid_ref))
0109 tracing_sched_register();
0110 mutex_unlock(&sched_register_mutex);
0111 }
0112
0113 static void tracing_stop_sched_switch(int ops)
0114 {
0115 mutex_lock(&sched_register_mutex);
0116
0117 switch (ops) {
0118 case RECORD_CMDLINE:
0119 sched_cmdline_ref--;
0120 break;
0121
0122 case RECORD_TGID:
0123 sched_tgid_ref--;
0124 break;
0125 }
0126
0127 if (!sched_cmdline_ref && !sched_tgid_ref)
0128 tracing_sched_unregister();
0129 mutex_unlock(&sched_register_mutex);
0130 }
0131
0132 void tracing_start_cmdline_record(void)
0133 {
0134 tracing_start_sched_switch(RECORD_CMDLINE);
0135 }
0136
0137 void tracing_stop_cmdline_record(void)
0138 {
0139 tracing_stop_sched_switch(RECORD_CMDLINE);
0140 }
0141
0142 void tracing_start_tgid_record(void)
0143 {
0144 tracing_start_sched_switch(RECORD_TGID);
0145 }
0146
0147 void tracing_stop_tgid_record(void)
0148 {
0149 tracing_stop_sched_switch(RECORD_TGID);
0150 }