···18421842 # cat buffer_size_kb18431843851844184418451845+Snapshot18461846+--------18471847+CONFIG_TRACER_SNAPSHOT makes a generic snapshot feature18481848+available to all non latency tracers. (Latency tracers which18491849+record max latency, such as "irqsoff" or "wakeup", can't use18501850+this feature, since those are already using the snapshot18511851+mechanism internally.)18521852+18531853+Snapshot preserves a current trace buffer at a particular point18541854+in time without stopping tracing. Ftrace swaps the current18551855+buffer with a spare buffer, and tracing continues in the new18561856+current (=previous spare) buffer.18571857+18581858+The following debugfs files in "tracing" are related to this18591859+feature:18601860+18611861+ snapshot:18621862+18631863+ This is used to take a snapshot and to read the output18641864+ of the snapshot. Echo 1 into this file to allocate a18651865+ spare buffer and to take a snapshot (swap), then read18661866+ the snapshot from this file in the same format as18671867+ "trace" (described above in the section "The File18681868+ System"). Both reads snapshot and tracing are executable18691869+ in parallel. When the spare buffer is allocated, echoing18701870+ 0 frees it, and echoing else (positive) values clear the18711871+ snapshot contents.18721872+ More details are shown in the table below.18731873+18741874+ status\input | 0 | 1 | else |18751875+ --------------+------------+------------+------------+18761876+ not allocated |(do nothing)| alloc+swap | EINVAL |18771877+ --------------+------------+------------+------------+18781878+ allocated | free | swap | clear |18791879+ --------------+------------+------------+------------+18801880+18811881+Here is an example of using the snapshot feature.18821882+18831883+ # echo 1 > events/sched/enable18841884+ # echo 1 > snapshot18851885+ # cat snapshot18861886+# tracer: nop18871887+#18881888+# entries-in-buffer/entries-written: 71/71 #P:818891889+#18901890+# _-----=> irqs-off18911891+# / _----=> need-resched18921892+# | / _---=> hardirq/softirq18931893+# || / _--=> preempt-depth18941894+# ||| / delay18951895+# TASK-PID CPU# |||| TIMESTAMP FUNCTION18961896+# | | | |||| | |18971897+ <idle>-0 [005] d... 2440.603828: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2242 next_prio=12018981898+ sleep-2242 [005] d... 2440.603846: sched_switch: prev_comm=snapshot-test-2 prev_pid=2242 prev_prio=120 prev_state=R ==> next_comm=kworker/5:1 next_pid=60 next_prio=12018991899+[...]19001900+ <idle>-0 [002] d... 2440.707230: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2229 next_prio=12019011901+19021902+ # cat trace19031903+# tracer: nop19041904+#19051905+# entries-in-buffer/entries-written: 77/77 #P:819061906+#19071907+# _-----=> irqs-off19081908+# / _----=> need-resched19091909+# | / _---=> hardirq/softirq19101910+# || / _--=> preempt-depth19111911+# ||| / delay19121912+# TASK-PID CPU# |||| TIMESTAMP FUNCTION19131913+# | | | |||| | |19141914+ <idle>-0 [007] d... 2440.707395: sched_switch: prev_comm=swapper/7 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2243 next_prio=12019151915+ snapshot-test-2-2229 [002] d... 2440.707438: sched_switch: prev_comm=snapshot-test-2 prev_pid=2229 prev_prio=120 prev_state=S ==> next_comm=swapper/2 next_pid=0 next_prio=12019161916+[...]19171917+19181918+19191919+If you try to use this snapshot feature when current tracer is19201920+one of the latency tracers, you will get the following results.19211921+19221922+ # echo wakeup > current_tracer19231923+ # echo 1 > snapshot19241924+bash: echo: write error: Device or resource busy19251925+ # cat snapshot19261926+cat: snapshot: Device or resource busy19271927+18451928-----------1846192918471930More details can be found in the source code, in the
+3
include/linux/ftrace_event.h
···8383 long idx;84848585 cpumask_var_t started;8686+8787+ /* it's true when current open file is snapshot */8888+ bool snapshot;8689};87908891enum trace_iter_flags {
+1
include/linux/ring_buffer.h
···167167unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu);168168unsigned long ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu);169169unsigned long ring_buffer_dropped_events_cpu(struct ring_buffer *buffer, int cpu);170170+unsigned long ring_buffer_read_events_cpu(struct ring_buffer *buffer, int cpu);170171171172u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu);172173void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer,
+10
kernel/trace/Kconfig
···253253 help254254 Basic tracer to catch the syscall entry and exit events.255255256256+config TRACER_SNAPSHOT257257+ bool "Create a snapshot trace buffer"258258+ select TRACER_MAX_TRACE259259+ help260260+ Allow tracing users to take snapshot of the current buffer using the261261+ ftrace interface, e.g.:262262+263263+ echo 1 > /sys/kernel/debug/tracing/snapshot264264+ cat snapshot265265+256266config TRACE_BRANCH_PROFILING257267 bool258268 select GENERIC_TRACER
+18
kernel/trace/ring_buffer.c
···31033103EXPORT_SYMBOL_GPL(ring_buffer_dropped_events_cpu);3104310431053105/**31063106+ * ring_buffer_read_events_cpu - get the number of events successfully read31073107+ * @buffer: The ring buffer31083108+ * @cpu: The per CPU buffer to get the number of events read31093109+ */31103110+unsigned long31113111+ring_buffer_read_events_cpu(struct ring_buffer *buffer, int cpu)31123112+{31133113+ struct ring_buffer_per_cpu *cpu_buffer;31143114+31153115+ if (!cpumask_test_cpu(cpu, buffer->cpumask))31163116+ return 0;31173117+31183118+ cpu_buffer = buffer->buffers[cpu];31193119+ return cpu_buffer->read;31203120+}31213121+EXPORT_SYMBOL_GPL(ring_buffer_read_events_cpu);31223122+31233123+/**31063124 * ring_buffer_entries - get the number of entries in a buffer31073125 * @buffer: The ring buffer31083126 *
+163-59
kernel/trace/trace.c
···249249static struct tracer *trace_types __read_mostly;250250251251/* current_trace points to the tracer that is currently active */252252-static struct tracer *current_trace __read_mostly;252252+static struct tracer *current_trace __read_mostly = &nop_trace;253253254254/*255255 * trace_types_lock is used to protect the trace_types list.···710710711711 WARN_ON_ONCE(!irqs_disabled());712712713713- /* If we disabled the tracer, stop now */714714- if (current_trace == &nop_trace)713713+ if (!current_trace->allocated_snapshot) {714714+ /* Only the nop tracer should hit this when disabling */715715+ WARN_ON_ONCE(current_trace != &nop_trace);715716 return;716716-717717- if (WARN_ON_ONCE(!current_trace->use_max_tr))718718- return;717717+ }719718720719 arch_spin_lock(&ftrace_max_lock);721720···742743 return;743744744745 WARN_ON_ONCE(!irqs_disabled());745745- if (!current_trace->use_max_tr) {746746- WARN_ON_ONCE(1);746746+ if (WARN_ON_ONCE(!current_trace->allocated_snapshot))747747 return;748748- }749748750749 arch_spin_lock(&ftrace_max_lock);751750···863866864867 current_trace = type;865868866866- /* If we expanded the buffers, make sure the max is expanded too */867867- if (ring_buffer_expanded && type->use_max_tr)868868- ring_buffer_resize(max_tr.buffer, trace_buf_size,869869- RING_BUFFER_ALL_CPUS);869869+ if (type->use_max_tr) {870870+ /* If we expanded the buffers, make sure the max is expanded too */871871+ if (ring_buffer_expanded)872872+ ring_buffer_resize(max_tr.buffer, trace_buf_size,873873+ RING_BUFFER_ALL_CPUS);874874+ type->allocated_snapshot = true;875875+ }870876871877 /* the test is responsible for initializing and enabling */872878 pr_info("Testing tracer %s: ", type->name);···885885 /* Only reset on passing, to avoid touching corrupted buffers */886886 tracing_reset_online_cpus(tr);887887888888- /* Shrink the max buffer again */889889- if (ring_buffer_expanded && type->use_max_tr)890890- ring_buffer_resize(max_tr.buffer, 1,891891- RING_BUFFER_ALL_CPUS);888888+ if (type->use_max_tr) {889889+ type->allocated_snapshot = false;890890+891891+ /* Shrink the max buffer again */892892+ if (ring_buffer_expanded)893893+ ring_buffer_resize(max_tr.buffer, 1,894894+ RING_BUFFER_ALL_CPUS);895895+ }892896893897 printk(KERN_CONT "PASSED\n");894898 }···13481344 */13491345 preempt_disable_notrace();1350134613511351- use_stack = ++__get_cpu_var(ftrace_stack_reserve);13471347+ use_stack = __this_cpu_inc_return(ftrace_stack_reserve);13521348 /*13531349 * We don't need any atomic variables, just a barrier.13541350 * If an interrupt comes in, we don't care, because it would···14021398 out:14031399 /* Again, don't let gcc optimize things here */14041400 barrier();14051405- __get_cpu_var(ftrace_stack_reserve)--;14011401+ __this_cpu_dec(ftrace_stack_reserve);14061402 preempt_enable_notrace();1407140314081404}···19521948static void *s_start(struct seq_file *m, loff_t *pos)19531949{19541950 struct trace_iterator *iter = m->private;19551955- static struct tracer *old_tracer;19561951 int cpu_file = iter->cpu_file;19571952 void *p = NULL;19581953 loff_t l = 0;19591954 int cpu;1960195519611961- /* copy the tracer to avoid using a global lock all around */19561956+ /*19571957+ * copy the tracer to avoid using a global lock all around.19581958+ * iter->trace is a copy of current_trace, the pointer to the19591959+ * name may be used instead of a strcmp(), as iter->trace->name19601960+ * will point to the same string as current_trace->name.19611961+ */19621962 mutex_lock(&trace_types_lock);19631963- if (unlikely(old_tracer != current_trace && current_trace)) {19641964- old_tracer = current_trace;19631963+ if (unlikely(current_trace && iter->trace->name != current_trace->name))19651964 *iter->trace = *current_trace;19661966- }19671965 mutex_unlock(&trace_types_lock);1968196619691969- atomic_inc(&trace_record_cmdline_disabled);19671967+ if (iter->snapshot && iter->trace->use_max_tr)19681968+ return ERR_PTR(-EBUSY);19691969+19701970+ if (!iter->snapshot)19711971+ atomic_inc(&trace_record_cmdline_disabled);1970197219711973 if (*pos != iter->pos) {19721974 iter->ent = NULL;···20112001{20122002 struct trace_iterator *iter = m->private;2013200320142014- atomic_dec(&trace_record_cmdline_disabled);20042004+ if (iter->snapshot && iter->trace->use_max_tr)20052005+ return;20062006+20072007+ if (!iter->snapshot)20082008+ atomic_dec(&trace_record_cmdline_disabled);20152009 trace_access_unlock(iter->cpu_file);20162010 trace_event_read_unlock();20172011}···21002086 unsigned long total;21012087 const char *name = "preemption";2102208821032103- if (type)21042104- name = type->name;20892089+ name = type->name;2105209021062091 get_total_entries(tr, &total, &entries);21072092···24492436};2450243724512438static struct trace_iterator *24522452-__tracing_open(struct inode *inode, struct file *file)24392439+__tracing_open(struct inode *inode, struct file *file, bool snapshot)24532440{24542441 long cpu_file = (long) inode->i_private;24552442 struct trace_iterator *iter;···24762463 if (!iter->trace)24772464 goto fail;2478246524792479- if (current_trace)24802480- *iter->trace = *current_trace;24662466+ *iter->trace = *current_trace;2481246724822468 if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL))24832469 goto fail;2484247024852485- if (current_trace && current_trace->print_max)24712471+ if (current_trace->print_max || snapshot)24862472 iter->tr = &max_tr;24872473 else24882474 iter->tr = &global_trace;24752475+ iter->snapshot = snapshot;24892476 iter->pos = -1;24902477 mutex_init(&iter->mutex);24912478 iter->cpu_file = cpu_file;···25022489 if (trace_clocks[trace_clock_id].in_ns)25032490 iter->iter_flags |= TRACE_FILE_TIME_IN_NS;2504249125052505- /* stop the trace while dumping */25062506- tracing_stop();24922492+ /* stop the trace while dumping if we are not opening "snapshot" */24932493+ if (!iter->snapshot)24942494+ tracing_stop();2507249525082496 if (iter->cpu_file == TRACE_PIPE_ALL_CPU) {25092497 for_each_tracing_cpu(cpu) {···25672553 if (iter->trace && iter->trace->close)25682554 iter->trace->close(iter);2569255525702570- /* reenable tracing if it was previously enabled */25712571- tracing_start();25562556+ if (!iter->snapshot)25572557+ /* reenable tracing if it was previously enabled */25582558+ tracing_start();25722559 mutex_unlock(&trace_types_lock);2573256025742561 mutex_destroy(&iter->mutex);···25972582 }2598258325992584 if (file->f_mode & FMODE_READ) {26002600- iter = __tracing_open(inode, file);25852585+ iter = __tracing_open(inode, file, false);26012586 if (IS_ERR(iter))26022587 ret = PTR_ERR(iter);26032588 else if (trace_flags & TRACE_ITER_LATENCY_FMT)···30353020 int r;3036302130373022 mutex_lock(&trace_types_lock);30383038- if (current_trace)30393039- r = sprintf(buf, "%s\n", current_trace->name);30403040- else30413041- r = sprintf(buf, "\n");30233023+ r = sprintf(buf, "%s\n", current_trace->name);30423024 mutex_unlock(&trace_types_lock);3043302530443026 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);···32263214 goto out;3227321532283216 trace_branch_disable();32293229- if (current_trace && current_trace->reset)32173217+ if (current_trace->reset)32303218 current_trace->reset(tr);3231321932323232- had_max_tr = current_trace && current_trace->use_max_tr;32203220+ had_max_tr = current_trace->allocated_snapshot;32333221 current_trace = &nop_trace;3234322232353223 if (had_max_tr && !t->use_max_tr) {···32483236 */32493237 ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS);32503238 set_buffer_entries(&max_tr, 1);32393239+ tracing_reset_online_cpus(&max_tr);32403240+ current_trace->allocated_snapshot = false;32513241 }32523242 destroy_trace_option_files(topts);32533243···32603246 RING_BUFFER_ALL_CPUS);32613247 if (ret < 0)32623248 goto out;32493249+ t->allocated_snapshot = true;32633250 }3264325132653252 if (t->init) {···33683353 ret = -ENOMEM;33693354 goto fail;33703355 }33713371- if (current_trace)33723372- *iter->trace = *current_trace;33563356+ *iter->trace = *current_trace;3373335733743358 if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) {33753359 ret = -ENOMEM;···35083494 size_t cnt, loff_t *ppos)35093495{35103496 struct trace_iterator *iter = filp->private_data;35113511- static struct tracer *old_tracer;35123497 ssize_t sret;3513349835143499 /* return any leftover data */···3519350635203507 /* copy the tracer to avoid using a global lock all around */35213508 mutex_lock(&trace_types_lock);35223522- if (unlikely(old_tracer != current_trace && current_trace)) {35233523- old_tracer = current_trace;35093509+ if (unlikely(iter->trace->name != current_trace->name))35243510 *iter->trace = *current_trace;35253525- }35263511 mutex_unlock(&trace_types_lock);3527351235283513 /*···36763665 .ops = &tracing_pipe_buf_ops,36773666 .spd_release = tracing_spd_release_pipe,36783667 };36793679- static struct tracer *old_tracer;36803668 ssize_t ret;36813669 size_t rem;36823670 unsigned int i;···3685367536863676 /* copy the tracer to avoid using a global lock all around */36873677 mutex_lock(&trace_types_lock);36883688- if (unlikely(old_tracer != current_trace && current_trace)) {36893689- old_tracer = current_trace;36783678+ if (unlikely(iter->trace->name != current_trace->name))36903679 *iter->trace = *current_trace;36913691- }36923680 mutex_unlock(&trace_types_lock);3693368136943682 mutex_lock(&iter->mutex);···40784070 return single_open(file, tracing_clock_show, NULL);40794071}4080407240734073+#ifdef CONFIG_TRACER_SNAPSHOT40744074+static int tracing_snapshot_open(struct inode *inode, struct file *file)40754075+{40764076+ struct trace_iterator *iter;40774077+ int ret = 0;40784078+40794079+ if (file->f_mode & FMODE_READ) {40804080+ iter = __tracing_open(inode, file, true);40814081+ if (IS_ERR(iter))40824082+ ret = PTR_ERR(iter);40834083+ }40844084+ return ret;40854085+}40864086+40874087+static ssize_t40884088+tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,40894089+ loff_t *ppos)40904090+{40914091+ unsigned long val;40924092+ int ret;40934093+40944094+ ret = tracing_update_buffers();40954095+ if (ret < 0)40964096+ return ret;40974097+40984098+ ret = kstrtoul_from_user(ubuf, cnt, 10, &val);40994099+ if (ret)41004100+ return ret;41014101+41024102+ mutex_lock(&trace_types_lock);41034103+41044104+ if (current_trace->use_max_tr) {41054105+ ret = -EBUSY;41064106+ goto out;41074107+ }41084108+41094109+ switch (val) {41104110+ case 0:41114111+ if (current_trace->allocated_snapshot) {41124112+ /* free spare buffer */41134113+ ring_buffer_resize(max_tr.buffer, 1,41144114+ RING_BUFFER_ALL_CPUS);41154115+ set_buffer_entries(&max_tr, 1);41164116+ tracing_reset_online_cpus(&max_tr);41174117+ current_trace->allocated_snapshot = false;41184118+ }41194119+ break;41204120+ case 1:41214121+ if (!current_trace->allocated_snapshot) {41224122+ /* allocate spare buffer */41234123+ ret = resize_buffer_duplicate_size(&max_tr,41244124+ &global_trace, RING_BUFFER_ALL_CPUS);41254125+ if (ret < 0)41264126+ break;41274127+ current_trace->allocated_snapshot = true;41284128+ }41294129+41304130+ local_irq_disable();41314131+ /* Now, we're going to swap */41324132+ update_max_tr(&global_trace, current, smp_processor_id());41334133+ local_irq_enable();41344134+ break;41354135+ default:41364136+ if (current_trace->allocated_snapshot)41374137+ tracing_reset_online_cpus(&max_tr);41384138+ else41394139+ ret = -EINVAL;41404140+ break;41414141+ }41424142+41434143+ if (ret >= 0) {41444144+ *ppos += cnt;41454145+ ret = cnt;41464146+ }41474147+out:41484148+ mutex_unlock(&trace_types_lock);41494149+ return ret;41504150+}41514151+#endif /* CONFIG_TRACER_SNAPSHOT */41524152+41534153+40814154static const struct file_operations tracing_max_lat_fops = {40824155 .open = tracing_open_generic,40834156 .read = tracing_max_lat_read,···42144125 .release = single_release,42154126 .write = tracing_clock_write,42164127};41284128+41294129+#ifdef CONFIG_TRACER_SNAPSHOT41304130+static const struct file_operations snapshot_fops = {41314131+ .open = tracing_snapshot_open,41324132+ .read = seq_read,41334133+ .write = tracing_snapshot_write,41344134+ .llseek = tracing_seek,41354135+ .release = tracing_release,41364136+};41374137+#endif /* CONFIG_TRACER_SNAPSHOT */4217413842184139struct ftrace_buffer_info {42194140 struct trace_array *tr;···45294430 cnt = ring_buffer_dropped_events_cpu(tr->buffer, cpu);45304431 trace_seq_printf(s, "dropped events: %ld\n", cnt);4531443244334433+ cnt = ring_buffer_read_events_cpu(tr->buffer, cpu);44344434+ trace_seq_printf(s, "read events: %ld\n", cnt);44354435+45324436 count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);4533443745344438 kfree(s);···4608450646094507static struct dentry *d_percpu;4610450846114611-struct dentry *tracing_dentry_percpu(void)45094509+static struct dentry *tracing_dentry_percpu(void)46124510{46134511 static int once;46144512 struct dentry *d_tracer;···50244922 &ftrace_update_tot_cnt, &tracing_dyn_info_fops);50254923#endif5026492449254925+#ifdef CONFIG_TRACER_SNAPSHOT49264926+ trace_create_file("snapshot", 0644, d_tracer,49274927+ (void *) TRACE_PIPE_ALL_CPU, &snapshot_fops);49284928+#endif49294929+50274930 create_trace_options_dir();5028493150294932 for_each_tracing_cpu(cpu)···51375030 if (disable_tracing)51385031 ftrace_kill();5139503250335033+ /* Simulate the iterator */51405034 trace_init_global_iter(&iter);5141503551425036 for_each_tracing_cpu(cpu) {···5148504051495041 /* don't look at user memory in panic mode */51505042 trace_flags &= ~TRACE_ITER_SYM_USEROBJ;51515151-51525152- /* Simulate the iterator */51535153- iter.tr = &global_trace;51545154- iter.trace = current_trace;5155504351565044 switch (oops_dump_mode) {51575045 case DUMP_ALL:···52935189 init_irq_work(&trace_work_wakeup, trace_wake_up);5294519052955191 register_tracer(&nop_trace);52965296- current_trace = &nop_trace;51925192+52975193 /* All seems OK, enable tracing */52985194 tracing_disabled = 0;52995195
···8484 local_irq_save(flags);85858686 this_cpu = raw_smp_processor_id();8787- now = cpu_clock(this_cpu);8787+ now = sched_clock_cpu(this_cpu);8888 /*8989 * If in an NMI context then dont risk lockups and return the9090 * cpu_clock() time:
+7-1
kernel/trace/trace_functions_graph.c
···191191192192 ftrace_pop_return_trace(&trace, &ret, frame_pointer);193193 trace.rettime = trace_clock_local();194194- ftrace_graph_return(&trace);195194 barrier();196195 current->curr_ret_stack--;196196+197197+ /*198198+ * The trace should run after decrementing the ret counter199199+ * in case an interrupt were to come in. We don't want to200200+ * lose the interrupt if max_depth is set.201201+ */202202+ ftrace_graph_return(&trace);197203198204 if (unlikely(!ret)) {199205 ftrace_graph_stop();
-6
samples/Kconfig
···5566if SAMPLES7788-config SAMPLE_TRACEPOINTS99- tristate "Build tracepoints examples -- loadable modules only"1010- depends on TRACEPOINTS && m1111- help1212- This build tracepoints example modules.1313-148config SAMPLE_TRACE_EVENTS159 tristate "Build trace_events examples -- loadable modules only"1610 depends on EVENT_TRACING && m
···11-# builds the tracepoint example kernel modules;22-# then to use one (as root): insmod <module_name.ko>33-44-obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-sample.o55-obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-probe-sample.o66-obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-probe-sample2.o
···11-/*22- * tracepoint-probe-sample.c33- *44- * sample tracepoint probes.55- */66-77-#include <linux/module.h>88-#include <linux/file.h>99-#include <linux/dcache.h>1010-#include "tp-samples-trace.h"1111-1212-/*1313- * Here the caller only guarantees locking for struct file and struct inode.1414- * Locking must therefore be done in the probe to use the dentry.1515- */1616-static void probe_subsys_event(void *ignore,1717- struct inode *inode, struct file *file)1818-{1919- path_get(&file->f_path);2020- dget(file->f_path.dentry);2121- printk(KERN_INFO "Event is encountered with filename %s\n",2222- file->f_path.dentry->d_name.name);2323- dput(file->f_path.dentry);2424- path_put(&file->f_path);2525-}2626-2727-static void probe_subsys_eventb(void *ignore)2828-{2929- printk(KERN_INFO "Event B is encountered\n");3030-}3131-3232-static int __init tp_sample_trace_init(void)3333-{3434- int ret;3535-3636- ret = register_trace_subsys_event(probe_subsys_event, NULL);3737- WARN_ON(ret);3838- ret = register_trace_subsys_eventb(probe_subsys_eventb, NULL);3939- WARN_ON(ret);4040-4141- return 0;4242-}4343-4444-module_init(tp_sample_trace_init);4545-4646-static void __exit tp_sample_trace_exit(void)4747-{4848- unregister_trace_subsys_eventb(probe_subsys_eventb, NULL);4949- unregister_trace_subsys_event(probe_subsys_event, NULL);5050- tracepoint_synchronize_unregister();5151-}5252-5353-module_exit(tp_sample_trace_exit);5454-5555-MODULE_LICENSE("GPL");5656-MODULE_AUTHOR("Mathieu Desnoyers");5757-MODULE_DESCRIPTION("Tracepoint Probes Samples");
-44
samples/tracepoints/tracepoint-probe-sample2.c
···11-/*22- * tracepoint-probe-sample2.c33- *44- * 2nd sample tracepoint probes.55- */66-77-#include <linux/module.h>88-#include <linux/fs.h>99-#include "tp-samples-trace.h"1010-1111-/*1212- * Here the caller only guarantees locking for struct file and struct inode.1313- * Locking must therefore be done in the probe to use the dentry.1414- */1515-static void probe_subsys_event(void *ignore,1616- struct inode *inode, struct file *file)1717-{1818- printk(KERN_INFO "Event is encountered with inode number %lu\n",1919- inode->i_ino);2020-}2121-2222-static int __init tp_sample_trace_init(void)2323-{2424- int ret;2525-2626- ret = register_trace_subsys_event(probe_subsys_event, NULL);2727- WARN_ON(ret);2828-2929- return 0;3030-}3131-3232-module_init(tp_sample_trace_init);3333-3434-static void __exit tp_sample_trace_exit(void)3535-{3636- unregister_trace_subsys_event(probe_subsys_event, NULL);3737- tracepoint_synchronize_unregister();3838-}3939-4040-module_exit(tp_sample_trace_exit);4141-4242-MODULE_LICENSE("GPL");4343-MODULE_AUTHOR("Mathieu Desnoyers");4444-MODULE_DESCRIPTION("Tracepoint Probes Samples");
-57
samples/tracepoints/tracepoint-sample.c
···11-/* tracepoint-sample.c22- *33- * Executes a tracepoint when /proc/tracepoint-sample is opened.44- *55- * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>66- *77- * This file is released under the GPLv2.88- * See the file COPYING for more details.99- */1010-1111-#include <linux/module.h>1212-#include <linux/sched.h>1313-#include <linux/proc_fs.h>1414-#include "tp-samples-trace.h"1515-1616-DEFINE_TRACE(subsys_event);1717-DEFINE_TRACE(subsys_eventb);1818-1919-struct proc_dir_entry *pentry_sample;2020-2121-static int my_open(struct inode *inode, struct file *file)2222-{2323- int i;2424-2525- trace_subsys_event(inode, file);2626- for (i = 0; i < 10; i++)2727- trace_subsys_eventb();2828- return -EPERM;2929-}3030-3131-static const struct file_operations mark_ops = {3232- .open = my_open,3333- .llseek = noop_llseek,3434-};3535-3636-static int __init sample_init(void)3737-{3838- printk(KERN_ALERT "sample init\n");3939- pentry_sample = proc_create("tracepoint-sample", 0444, NULL,4040- &mark_ops);4141- if (!pentry_sample)4242- return -EPERM;4343- return 0;4444-}4545-4646-static void __exit sample_exit(void)4747-{4848- printk(KERN_ALERT "sample exit\n");4949- remove_proc_entry("tracepoint-sample", NULL);5050-}5151-5252-module_init(sample_init)5353-module_exit(sample_exit)5454-5555-MODULE_LICENSE("GPL");5656-MODULE_AUTHOR("Mathieu Desnoyers");5757-MODULE_DESCRIPTION("Tracepoint sample");