162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/module.h> 362306a36Sopenharmony_ci#include <linux/kthread.h> 462306a36Sopenharmony_ci#include <linux/trace.h> 562306a36Sopenharmony_ci#include <linux/trace_events.h> 662306a36Sopenharmony_ci#include <linux/timer.h> 762306a36Sopenharmony_ci#include <linux/err.h> 862306a36Sopenharmony_ci#include <linux/jiffies.h> 962306a36Sopenharmony_ci#include <linux/workqueue.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * Any file that uses trace points, must include the header. 1362306a36Sopenharmony_ci * But only one file, must include the header by defining 1462306a36Sopenharmony_ci * CREATE_TRACE_POINTS first. This will make the C code that 1562306a36Sopenharmony_ci * creates the handles for the trace points. 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 1862306a36Sopenharmony_ci#include "sample-trace-array.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct trace_array *tr; 2162306a36Sopenharmony_cistatic void mytimer_handler(struct timer_list *unused); 2262306a36Sopenharmony_cistatic struct task_struct *simple_tsk; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic void trace_work_fn(struct work_struct *work) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci /* 2762306a36Sopenharmony_ci * Disable tracing for event "sample_event". 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci trace_array_set_clr_event(tr, "sample-subsystem", "sample_event", 3062306a36Sopenharmony_ci false); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_cistatic DECLARE_WORK(trace_work, trace_work_fn); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * mytimer: Timer setup to disable tracing for event "sample_event". This 3662306a36Sopenharmony_ci * timer is only for the purposes of the sample module to demonstrate access of 3762306a36Sopenharmony_ci * Ftrace instances from within kernel. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_cistatic DEFINE_TIMER(mytimer, mytimer_handler); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic void mytimer_handler(struct timer_list *unused) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci schedule_work(&trace_work); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void simple_thread_func(int count) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 4962306a36Sopenharmony_ci schedule_timeout(HZ); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* 5262306a36Sopenharmony_ci * Printing count value using trace_array_printk() - trace_printk() 5362306a36Sopenharmony_ci * equivalent for the instance buffers. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci trace_array_printk(tr, _THIS_IP_, "trace_array_printk: count=%d\n", 5662306a36Sopenharmony_ci count); 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * Tracepoint for event "sample_event". This will print the 5962306a36Sopenharmony_ci * current value of count and current jiffies. 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci trace_sample_event(count, jiffies); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int simple_thread(void *arg) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci int count = 0; 6762306a36Sopenharmony_ci unsigned long delay = msecs_to_jiffies(5000); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* 7062306a36Sopenharmony_ci * Enable tracing for "sample_event". 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci trace_array_set_clr_event(tr, "sample-subsystem", "sample_event", true); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* 7562306a36Sopenharmony_ci * Adding timer - mytimer. This timer will disable tracing after 7662306a36Sopenharmony_ci * delay seconds. 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci add_timer(&mytimer); 8062306a36Sopenharmony_ci mod_timer(&mytimer, jiffies+delay); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci while (!kthread_should_stop()) 8362306a36Sopenharmony_ci simple_thread_func(count++); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci del_timer(&mytimer); 8662306a36Sopenharmony_ci cancel_work_sync(&trace_work); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* 8962306a36Sopenharmony_ci * trace_array_put() decrements the reference counter associated with 9062306a36Sopenharmony_ci * the trace array - "tr". We are done using the trace array, hence 9162306a36Sopenharmony_ci * decrement the reference counter so that it can be destroyed using 9262306a36Sopenharmony_ci * trace_array_destroy(). 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci trace_array_put(tr); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int __init sample_trace_array_init(void) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * Return a pointer to the trace array with name "sample-instance" if it 10362306a36Sopenharmony_ci * exists, else create a new trace array. 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * NOTE: This function increments the reference counter 10662306a36Sopenharmony_ci * associated with the trace array - "tr". 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci tr = trace_array_get_by_name("sample-instance"); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (!tr) 11162306a36Sopenharmony_ci return -1; 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * If context specific per-cpu buffers havent already been allocated. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci trace_printk_init_buffers(); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci simple_tsk = kthread_run(simple_thread, NULL, "sample-instance"); 11862306a36Sopenharmony_ci if (IS_ERR(simple_tsk)) { 11962306a36Sopenharmony_ci trace_array_put(tr); 12062306a36Sopenharmony_ci trace_array_destroy(tr); 12162306a36Sopenharmony_ci return -1; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic void __exit sample_trace_array_exit(void) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci kthread_stop(simple_tsk); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* 13262306a36Sopenharmony_ci * We are unloading our module and no longer require the trace array. 13362306a36Sopenharmony_ci * Remove/destroy "tr" using trace_array_destroy() 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci trace_array_destroy(tr); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cimodule_init(sample_trace_array_init); 13962306a36Sopenharmony_cimodule_exit(sample_trace_array_exit); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciMODULE_AUTHOR("Divya Indi"); 14262306a36Sopenharmony_ciMODULE_DESCRIPTION("Sample module for kernel access to Ftrace instances"); 14362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 144