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