1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/module.h> 3 #include <linux/kthread.h> 4 #include <linux/trace.h> 5 #include <linux/trace_events.h> 6 #include <linux/timer.h> 7 #include <linux/err.h> 8 #include <linux/jiffies.h> 9 #include <linux/workqueue.h> 10 11 /* 12 * Any file that uses trace points, must include the header. 13 * But only one file, must include the header by defining 14 * CREATE_TRACE_POINTS first. This will make the C code that 15 * creates the handles for the trace points. 16 */ 17 #define CREATE_TRACE_POINTS 18 #include "sample-trace-array.h" 19 20 struct trace_array *tr; 21 static void mytimer_handler(struct timer_list *unused); 22 static struct task_struct *simple_tsk; 23 24 static void trace_work_fn(struct work_struct *work) 25 { 26 /* 27 * Disable tracing for event "sample_event". 28 */ 29 trace_array_set_clr_event(tr, "sample-subsystem", "sample_event", 30 false); 31 } 32 static DECLARE_WORK(trace_work, trace_work_fn); 33 34 /* 35 * mytimer: Timer setup to disable tracing for event "sample_event". This 36 * timer is only for the purposes of the sample module to demonstrate access of 37 * Ftrace instances from within kernel. 38 */ 39 static DEFINE_TIMER(mytimer, mytimer_handler); 40 41 static void mytimer_handler(struct timer_list *unused) 42 { 43 schedule_work(&trace_work); 44 } 45 46 static void simple_thread_func(int count) 47 { 48 set_current_state(TASK_INTERRUPTIBLE); 49 schedule_timeout(HZ); 50 51 /* 52 * Printing count value using trace_array_printk() - trace_printk() 53 * equivalent for the instance buffers. 54 */ 55 trace_array_printk(tr, _THIS_IP_, "trace_array_printk: count=%d\n", 56 count); 57 /* 58 * Tracepoint for event "sample_event". This will print the 59 * current value of count and current jiffies. 60 */ 61 trace_sample_event(count, jiffies); 62 } 63 64 static int simple_thread(void *arg) 65 { 66 int count = 0; 67 unsigned long delay = msecs_to_jiffies(5000); 68 69 /* 70 * Enable tracing for "sample_event". 71 */ 72 trace_array_set_clr_event(tr, "sample-subsystem", "sample_event", true); 73 74 /* 75 * Adding timer - mytimer. This timer will disable tracing after 76 * delay seconds. 77 * 78 */ 79 add_timer(&mytimer); 80 mod_timer(&mytimer, jiffies+delay); 81 82 while (!kthread_should_stop()) 83 simple_thread_func(count++); 84 85 del_timer(&mytimer); 86 cancel_work_sync(&trace_work); 87 88 /* 89 * trace_array_put() decrements the reference counter associated with 90 * the trace array - "tr". We are done using the trace array, hence 91 * decrement the reference counter so that it can be destroyed using 92 * trace_array_destroy(). 93 */ 94 trace_array_put(tr); 95 96 return 0; 97 } 98 99 static int __init sample_trace_array_init(void) 100 { 101 /* 102 * Return a pointer to the trace array with name "sample-instance" if it 103 * exists, else create a new trace array. 104 * 105 * NOTE: This function increments the reference counter 106 * associated with the trace array - "tr". 107 */ 108 tr = trace_array_get_by_name("sample-instance", "sched,timer,kprobes"); 109 110 if (!tr) 111 return -1; 112 /* 113 * If context specific per-cpu buffers havent already been allocated. 114 */ 115 trace_printk_init_buffers(); 116 117 simple_tsk = kthread_run(simple_thread, NULL, "sample-instance"); 118 if (IS_ERR(simple_tsk)) { 119 trace_array_put(tr); 120 trace_array_destroy(tr); 121 return -1; 122 } 123 124 return 0; 125 } 126 127 static void __exit sample_trace_array_exit(void) 128 { 129 kthread_stop(simple_tsk); 130 131 /* 132 * We are unloading our module and no longer require the trace array. 133 * Remove/destroy "tr" using trace_array_destroy() 134 */ 135 trace_array_destroy(tr); 136 } 137 138 module_init(sample_trace_array_init); 139 module_exit(sample_trace_array_exit); 140 141 MODULE_AUTHOR("Divya Indi"); 142 MODULE_DESCRIPTION("Sample module for kernel access to Ftrace instances"); 143 MODULE_LICENSE("GPL"); 144