197e1c18eSMathieu Desnoyers /* 297e1c18eSMathieu Desnoyers * Copyright (C) 2008 Mathieu Desnoyers 397e1c18eSMathieu Desnoyers * 497e1c18eSMathieu Desnoyers * This program is free software; you can redistribute it and/or modify 597e1c18eSMathieu Desnoyers * it under the terms of the GNU General Public License as published by 697e1c18eSMathieu Desnoyers * the Free Software Foundation; either version 2 of the License, or 797e1c18eSMathieu Desnoyers * (at your option) any later version. 897e1c18eSMathieu Desnoyers * 997e1c18eSMathieu Desnoyers * This program is distributed in the hope that it will be useful, 1097e1c18eSMathieu Desnoyers * but WITHOUT ANY WARRANTY; without even the implied warranty of 1197e1c18eSMathieu Desnoyers * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1297e1c18eSMathieu Desnoyers * GNU General Public License for more details. 1397e1c18eSMathieu Desnoyers * 1497e1c18eSMathieu Desnoyers * You should have received a copy of the GNU General Public License 1597e1c18eSMathieu Desnoyers * along with this program; if not, write to the Free Software 1697e1c18eSMathieu Desnoyers * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1797e1c18eSMathieu Desnoyers */ 1897e1c18eSMathieu Desnoyers #include <linux/module.h> 1997e1c18eSMathieu Desnoyers #include <linux/mutex.h> 2097e1c18eSMathieu Desnoyers #include <linux/types.h> 2197e1c18eSMathieu Desnoyers #include <linux/jhash.h> 2297e1c18eSMathieu Desnoyers #include <linux/list.h> 2397e1c18eSMathieu Desnoyers #include <linux/rcupdate.h> 2497e1c18eSMathieu Desnoyers #include <linux/tracepoint.h> 2597e1c18eSMathieu Desnoyers #include <linux/err.h> 2697e1c18eSMathieu Desnoyers #include <linux/slab.h> 2797e1c18eSMathieu Desnoyers 2897e1c18eSMathieu Desnoyers extern struct tracepoint __start___tracepoints[]; 2997e1c18eSMathieu Desnoyers extern struct tracepoint __stop___tracepoints[]; 3097e1c18eSMathieu Desnoyers 3197e1c18eSMathieu Desnoyers /* Set to 1 to enable tracepoint debug output */ 3297e1c18eSMathieu Desnoyers static const int tracepoint_debug; 3397e1c18eSMathieu Desnoyers 3497e1c18eSMathieu Desnoyers /* 3597e1c18eSMathieu Desnoyers * tracepoints_mutex nests inside module_mutex. Tracepoints mutex protects the 3697e1c18eSMathieu Desnoyers * builtin and module tracepoints and the hash table. 3797e1c18eSMathieu Desnoyers */ 3897e1c18eSMathieu Desnoyers static DEFINE_MUTEX(tracepoints_mutex); 3997e1c18eSMathieu Desnoyers 4097e1c18eSMathieu Desnoyers /* 4197e1c18eSMathieu Desnoyers * Tracepoint hash table, containing the active tracepoints. 4297e1c18eSMathieu Desnoyers * Protected by tracepoints_mutex. 4397e1c18eSMathieu Desnoyers */ 4497e1c18eSMathieu Desnoyers #define TRACEPOINT_HASH_BITS 6 4597e1c18eSMathieu Desnoyers #define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS) 4619dba33cSLai Jiangshan static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE]; 4797e1c18eSMathieu Desnoyers 4897e1c18eSMathieu Desnoyers /* 4997e1c18eSMathieu Desnoyers * Note about RCU : 5097e1c18eSMathieu Desnoyers * It is used to to delay the free of multiple probes array until a quiescent 5197e1c18eSMathieu Desnoyers * state is reached. 5297e1c18eSMathieu Desnoyers * Tracepoint entries modifications are protected by the tracepoints_mutex. 5397e1c18eSMathieu Desnoyers */ 5497e1c18eSMathieu Desnoyers struct tracepoint_entry { 5597e1c18eSMathieu Desnoyers struct hlist_node hlist; 5697e1c18eSMathieu Desnoyers void **funcs; 5797e1c18eSMathieu Desnoyers int refcount; /* Number of times armed. 0 if disarmed. */ 5897e1c18eSMathieu Desnoyers char name[0]; 5997e1c18eSMathieu Desnoyers }; 6097e1c18eSMathieu Desnoyers 6119dba33cSLai Jiangshan struct tp_probes { 62*127cafbbSLai Jiangshan union { 6319dba33cSLai Jiangshan struct rcu_head rcu; 64*127cafbbSLai Jiangshan struct list_head list; 65*127cafbbSLai Jiangshan } u; 6619dba33cSLai Jiangshan void *probes[0]; 6719dba33cSLai Jiangshan }; 6897e1c18eSMathieu Desnoyers 6919dba33cSLai Jiangshan static inline void *allocate_probes(int count) 7097e1c18eSMathieu Desnoyers { 7119dba33cSLai Jiangshan struct tp_probes *p = kmalloc(count * sizeof(void *) 7219dba33cSLai Jiangshan + sizeof(struct tp_probes), GFP_KERNEL); 7319dba33cSLai Jiangshan return p == NULL ? NULL : p->probes; 7497e1c18eSMathieu Desnoyers } 7597e1c18eSMathieu Desnoyers 7619dba33cSLai Jiangshan static void rcu_free_old_probes(struct rcu_head *head) 7797e1c18eSMathieu Desnoyers { 78*127cafbbSLai Jiangshan kfree(container_of(head, struct tp_probes, u.rcu)); 7919dba33cSLai Jiangshan } 8019dba33cSLai Jiangshan 8119dba33cSLai Jiangshan static inline void release_probes(void *old) 8219dba33cSLai Jiangshan { 8319dba33cSLai Jiangshan if (old) { 8419dba33cSLai Jiangshan struct tp_probes *tp_probes = container_of(old, 8519dba33cSLai Jiangshan struct tp_probes, probes[0]); 86*127cafbbSLai Jiangshan call_rcu_sched(&tp_probes->u.rcu, rcu_free_old_probes); 8719dba33cSLai Jiangshan } 8897e1c18eSMathieu Desnoyers } 8997e1c18eSMathieu Desnoyers 9097e1c18eSMathieu Desnoyers static void debug_print_probes(struct tracepoint_entry *entry) 9197e1c18eSMathieu Desnoyers { 9297e1c18eSMathieu Desnoyers int i; 9397e1c18eSMathieu Desnoyers 9419dba33cSLai Jiangshan if (!tracepoint_debug || !entry->funcs) 9597e1c18eSMathieu Desnoyers return; 9697e1c18eSMathieu Desnoyers 9797e1c18eSMathieu Desnoyers for (i = 0; entry->funcs[i]; i++) 9897e1c18eSMathieu Desnoyers printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i]); 9997e1c18eSMathieu Desnoyers } 10097e1c18eSMathieu Desnoyers 10197e1c18eSMathieu Desnoyers static void * 10297e1c18eSMathieu Desnoyers tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe) 10397e1c18eSMathieu Desnoyers { 10497e1c18eSMathieu Desnoyers int nr_probes = 0; 10597e1c18eSMathieu Desnoyers void **old, **new; 10697e1c18eSMathieu Desnoyers 10797e1c18eSMathieu Desnoyers WARN_ON(!probe); 10897e1c18eSMathieu Desnoyers 10997e1c18eSMathieu Desnoyers debug_print_probes(entry); 11097e1c18eSMathieu Desnoyers old = entry->funcs; 11197e1c18eSMathieu Desnoyers if (old) { 11297e1c18eSMathieu Desnoyers /* (N -> N+1), (N != 0, 1) probes */ 11397e1c18eSMathieu Desnoyers for (nr_probes = 0; old[nr_probes]; nr_probes++) 11497e1c18eSMathieu Desnoyers if (old[nr_probes] == probe) 11597e1c18eSMathieu Desnoyers return ERR_PTR(-EEXIST); 11697e1c18eSMathieu Desnoyers } 11797e1c18eSMathieu Desnoyers /* + 2 : one for new probe, one for NULL func */ 11819dba33cSLai Jiangshan new = allocate_probes(nr_probes + 2); 11997e1c18eSMathieu Desnoyers if (new == NULL) 12097e1c18eSMathieu Desnoyers return ERR_PTR(-ENOMEM); 12197e1c18eSMathieu Desnoyers if (old) 12297e1c18eSMathieu Desnoyers memcpy(new, old, nr_probes * sizeof(void *)); 12397e1c18eSMathieu Desnoyers new[nr_probes] = probe; 12419dba33cSLai Jiangshan new[nr_probes + 1] = NULL; 12597e1c18eSMathieu Desnoyers entry->refcount = nr_probes + 1; 12697e1c18eSMathieu Desnoyers entry->funcs = new; 12797e1c18eSMathieu Desnoyers debug_print_probes(entry); 12897e1c18eSMathieu Desnoyers return old; 12997e1c18eSMathieu Desnoyers } 13097e1c18eSMathieu Desnoyers 13197e1c18eSMathieu Desnoyers static void * 13297e1c18eSMathieu Desnoyers tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe) 13397e1c18eSMathieu Desnoyers { 13497e1c18eSMathieu Desnoyers int nr_probes = 0, nr_del = 0, i; 13597e1c18eSMathieu Desnoyers void **old, **new; 13697e1c18eSMathieu Desnoyers 13797e1c18eSMathieu Desnoyers old = entry->funcs; 13897e1c18eSMathieu Desnoyers 139f66af459SFrederic Weisbecker if (!old) 14019dba33cSLai Jiangshan return ERR_PTR(-ENOENT); 141f66af459SFrederic Weisbecker 14297e1c18eSMathieu Desnoyers debug_print_probes(entry); 14397e1c18eSMathieu Desnoyers /* (N -> M), (N > 1, M >= 0) probes */ 14497e1c18eSMathieu Desnoyers for (nr_probes = 0; old[nr_probes]; nr_probes++) { 14597e1c18eSMathieu Desnoyers if ((!probe || old[nr_probes] == probe)) 14697e1c18eSMathieu Desnoyers nr_del++; 14797e1c18eSMathieu Desnoyers } 14897e1c18eSMathieu Desnoyers 14997e1c18eSMathieu Desnoyers if (nr_probes - nr_del == 0) { 15097e1c18eSMathieu Desnoyers /* N -> 0, (N > 1) */ 15197e1c18eSMathieu Desnoyers entry->funcs = NULL; 15297e1c18eSMathieu Desnoyers entry->refcount = 0; 15397e1c18eSMathieu Desnoyers debug_print_probes(entry); 15497e1c18eSMathieu Desnoyers return old; 15597e1c18eSMathieu Desnoyers } else { 15697e1c18eSMathieu Desnoyers int j = 0; 15797e1c18eSMathieu Desnoyers /* N -> M, (N > 1, M > 0) */ 15897e1c18eSMathieu Desnoyers /* + 1 for NULL */ 15919dba33cSLai Jiangshan new = allocate_probes(nr_probes - nr_del + 1); 16097e1c18eSMathieu Desnoyers if (new == NULL) 16197e1c18eSMathieu Desnoyers return ERR_PTR(-ENOMEM); 16297e1c18eSMathieu Desnoyers for (i = 0; old[i]; i++) 16397e1c18eSMathieu Desnoyers if ((probe && old[i] != probe)) 16497e1c18eSMathieu Desnoyers new[j++] = old[i]; 16519dba33cSLai Jiangshan new[nr_probes - nr_del] = NULL; 16697e1c18eSMathieu Desnoyers entry->refcount = nr_probes - nr_del; 16797e1c18eSMathieu Desnoyers entry->funcs = new; 16897e1c18eSMathieu Desnoyers } 16997e1c18eSMathieu Desnoyers debug_print_probes(entry); 17097e1c18eSMathieu Desnoyers return old; 17197e1c18eSMathieu Desnoyers } 17297e1c18eSMathieu Desnoyers 17397e1c18eSMathieu Desnoyers /* 17497e1c18eSMathieu Desnoyers * Get tracepoint if the tracepoint is present in the tracepoint hash table. 17597e1c18eSMathieu Desnoyers * Must be called with tracepoints_mutex held. 17697e1c18eSMathieu Desnoyers * Returns NULL if not present. 17797e1c18eSMathieu Desnoyers */ 17897e1c18eSMathieu Desnoyers static struct tracepoint_entry *get_tracepoint(const char *name) 17997e1c18eSMathieu Desnoyers { 18097e1c18eSMathieu Desnoyers struct hlist_head *head; 18197e1c18eSMathieu Desnoyers struct hlist_node *node; 18297e1c18eSMathieu Desnoyers struct tracepoint_entry *e; 18397e1c18eSMathieu Desnoyers u32 hash = jhash(name, strlen(name), 0); 18497e1c18eSMathieu Desnoyers 1859795302aSMathieu Desnoyers head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; 18697e1c18eSMathieu Desnoyers hlist_for_each_entry(e, node, head, hlist) { 18797e1c18eSMathieu Desnoyers if (!strcmp(name, e->name)) 18897e1c18eSMathieu Desnoyers return e; 18997e1c18eSMathieu Desnoyers } 19097e1c18eSMathieu Desnoyers return NULL; 19197e1c18eSMathieu Desnoyers } 19297e1c18eSMathieu Desnoyers 19397e1c18eSMathieu Desnoyers /* 19497e1c18eSMathieu Desnoyers * Add the tracepoint to the tracepoint hash table. Must be called with 19597e1c18eSMathieu Desnoyers * tracepoints_mutex held. 19697e1c18eSMathieu Desnoyers */ 19797e1c18eSMathieu Desnoyers static struct tracepoint_entry *add_tracepoint(const char *name) 19897e1c18eSMathieu Desnoyers { 19997e1c18eSMathieu Desnoyers struct hlist_head *head; 20097e1c18eSMathieu Desnoyers struct hlist_node *node; 20197e1c18eSMathieu Desnoyers struct tracepoint_entry *e; 20297e1c18eSMathieu Desnoyers size_t name_len = strlen(name) + 1; 20397e1c18eSMathieu Desnoyers u32 hash = jhash(name, name_len-1, 0); 20497e1c18eSMathieu Desnoyers 2059795302aSMathieu Desnoyers head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; 20697e1c18eSMathieu Desnoyers hlist_for_each_entry(e, node, head, hlist) { 20797e1c18eSMathieu Desnoyers if (!strcmp(name, e->name)) { 20897e1c18eSMathieu Desnoyers printk(KERN_NOTICE 20997e1c18eSMathieu Desnoyers "tracepoint %s busy\n", name); 21097e1c18eSMathieu Desnoyers return ERR_PTR(-EEXIST); /* Already there */ 21197e1c18eSMathieu Desnoyers } 21297e1c18eSMathieu Desnoyers } 21397e1c18eSMathieu Desnoyers /* 21497e1c18eSMathieu Desnoyers * Using kmalloc here to allocate a variable length element. Could 21597e1c18eSMathieu Desnoyers * cause some memory fragmentation if overused. 21697e1c18eSMathieu Desnoyers */ 21797e1c18eSMathieu Desnoyers e = kmalloc(sizeof(struct tracepoint_entry) + name_len, GFP_KERNEL); 21897e1c18eSMathieu Desnoyers if (!e) 21997e1c18eSMathieu Desnoyers return ERR_PTR(-ENOMEM); 22097e1c18eSMathieu Desnoyers memcpy(&e->name[0], name, name_len); 22197e1c18eSMathieu Desnoyers e->funcs = NULL; 22297e1c18eSMathieu Desnoyers e->refcount = 0; 22397e1c18eSMathieu Desnoyers hlist_add_head(&e->hlist, head); 22497e1c18eSMathieu Desnoyers return e; 22597e1c18eSMathieu Desnoyers } 22697e1c18eSMathieu Desnoyers 22797e1c18eSMathieu Desnoyers /* 22897e1c18eSMathieu Desnoyers * Remove the tracepoint from the tracepoint hash table. Must be called with 22997e1c18eSMathieu Desnoyers * mutex_lock held. 23097e1c18eSMathieu Desnoyers */ 23119dba33cSLai Jiangshan static inline void remove_tracepoint(struct tracepoint_entry *e) 23297e1c18eSMathieu Desnoyers { 23397e1c18eSMathieu Desnoyers hlist_del(&e->hlist); 23497e1c18eSMathieu Desnoyers kfree(e); 23597e1c18eSMathieu Desnoyers } 23697e1c18eSMathieu Desnoyers 23797e1c18eSMathieu Desnoyers /* 23897e1c18eSMathieu Desnoyers * Sets the probe callback corresponding to one tracepoint. 23997e1c18eSMathieu Desnoyers */ 24097e1c18eSMathieu Desnoyers static void set_tracepoint(struct tracepoint_entry **entry, 24197e1c18eSMathieu Desnoyers struct tracepoint *elem, int active) 24297e1c18eSMathieu Desnoyers { 24397e1c18eSMathieu Desnoyers WARN_ON(strcmp((*entry)->name, elem->name) != 0); 24497e1c18eSMathieu Desnoyers 24597e1c18eSMathieu Desnoyers /* 24697e1c18eSMathieu Desnoyers * rcu_assign_pointer has a smp_wmb() which makes sure that the new 24797e1c18eSMathieu Desnoyers * probe callbacks array is consistent before setting a pointer to it. 24897e1c18eSMathieu Desnoyers * This array is referenced by __DO_TRACE from 24997e1c18eSMathieu Desnoyers * include/linux/tracepoints.h. A matching smp_read_barrier_depends() 25097e1c18eSMathieu Desnoyers * is used. 25197e1c18eSMathieu Desnoyers */ 25297e1c18eSMathieu Desnoyers rcu_assign_pointer(elem->funcs, (*entry)->funcs); 25397e1c18eSMathieu Desnoyers elem->state = active; 25497e1c18eSMathieu Desnoyers } 25597e1c18eSMathieu Desnoyers 25697e1c18eSMathieu Desnoyers /* 25797e1c18eSMathieu Desnoyers * Disable a tracepoint and its probe callback. 25897e1c18eSMathieu Desnoyers * Note: only waiting an RCU period after setting elem->call to the empty 25997e1c18eSMathieu Desnoyers * function insures that the original callback is not used anymore. This insured 26097e1c18eSMathieu Desnoyers * by preempt_disable around the call site. 26197e1c18eSMathieu Desnoyers */ 26297e1c18eSMathieu Desnoyers static void disable_tracepoint(struct tracepoint *elem) 26397e1c18eSMathieu Desnoyers { 26497e1c18eSMathieu Desnoyers elem->state = 0; 26597e1c18eSMathieu Desnoyers } 26697e1c18eSMathieu Desnoyers 26797e1c18eSMathieu Desnoyers /** 26897e1c18eSMathieu Desnoyers * tracepoint_update_probe_range - Update a probe range 26997e1c18eSMathieu Desnoyers * @begin: beginning of the range 27097e1c18eSMathieu Desnoyers * @end: end of the range 27197e1c18eSMathieu Desnoyers * 27297e1c18eSMathieu Desnoyers * Updates the probe callback corresponding to a range of tracepoints. 27397e1c18eSMathieu Desnoyers */ 27497e1c18eSMathieu Desnoyers void tracepoint_update_probe_range(struct tracepoint *begin, 27597e1c18eSMathieu Desnoyers struct tracepoint *end) 27697e1c18eSMathieu Desnoyers { 27797e1c18eSMathieu Desnoyers struct tracepoint *iter; 27897e1c18eSMathieu Desnoyers struct tracepoint_entry *mark_entry; 27997e1c18eSMathieu Desnoyers 28097e1c18eSMathieu Desnoyers mutex_lock(&tracepoints_mutex); 28197e1c18eSMathieu Desnoyers for (iter = begin; iter < end; iter++) { 28297e1c18eSMathieu Desnoyers mark_entry = get_tracepoint(iter->name); 28397e1c18eSMathieu Desnoyers if (mark_entry) { 28497e1c18eSMathieu Desnoyers set_tracepoint(&mark_entry, iter, 28597e1c18eSMathieu Desnoyers !!mark_entry->refcount); 28697e1c18eSMathieu Desnoyers } else { 28797e1c18eSMathieu Desnoyers disable_tracepoint(iter); 28897e1c18eSMathieu Desnoyers } 28997e1c18eSMathieu Desnoyers } 29097e1c18eSMathieu Desnoyers mutex_unlock(&tracepoints_mutex); 29197e1c18eSMathieu Desnoyers } 29297e1c18eSMathieu Desnoyers 29397e1c18eSMathieu Desnoyers /* 29497e1c18eSMathieu Desnoyers * Update probes, removing the faulty probes. 29597e1c18eSMathieu Desnoyers */ 29697e1c18eSMathieu Desnoyers static void tracepoint_update_probes(void) 29797e1c18eSMathieu Desnoyers { 29897e1c18eSMathieu Desnoyers /* Core kernel tracepoints */ 29997e1c18eSMathieu Desnoyers tracepoint_update_probe_range(__start___tracepoints, 30097e1c18eSMathieu Desnoyers __stop___tracepoints); 30197e1c18eSMathieu Desnoyers /* tracepoints in modules. */ 30297e1c18eSMathieu Desnoyers module_update_tracepoints(); 30397e1c18eSMathieu Desnoyers } 30497e1c18eSMathieu Desnoyers 305*127cafbbSLai Jiangshan static void *tracepoint_add_probe(const char *name, void *probe) 306*127cafbbSLai Jiangshan { 307*127cafbbSLai Jiangshan struct tracepoint_entry *entry; 308*127cafbbSLai Jiangshan void *old; 309*127cafbbSLai Jiangshan 310*127cafbbSLai Jiangshan entry = get_tracepoint(name); 311*127cafbbSLai Jiangshan if (!entry) { 312*127cafbbSLai Jiangshan entry = add_tracepoint(name); 313*127cafbbSLai Jiangshan if (IS_ERR(entry)) 314*127cafbbSLai Jiangshan return entry; 315*127cafbbSLai Jiangshan } 316*127cafbbSLai Jiangshan old = tracepoint_entry_add_probe(entry, probe); 317*127cafbbSLai Jiangshan if (IS_ERR(old) && !entry->refcount) 318*127cafbbSLai Jiangshan remove_tracepoint(entry); 319*127cafbbSLai Jiangshan return old; 320*127cafbbSLai Jiangshan } 321*127cafbbSLai Jiangshan 32297e1c18eSMathieu Desnoyers /** 32397e1c18eSMathieu Desnoyers * tracepoint_probe_register - Connect a probe to a tracepoint 32497e1c18eSMathieu Desnoyers * @name: tracepoint name 32597e1c18eSMathieu Desnoyers * @probe: probe handler 32697e1c18eSMathieu Desnoyers * 32797e1c18eSMathieu Desnoyers * Returns 0 if ok, error value on error. 32897e1c18eSMathieu Desnoyers * The probe address must at least be aligned on the architecture pointer size. 32997e1c18eSMathieu Desnoyers */ 33097e1c18eSMathieu Desnoyers int tracepoint_probe_register(const char *name, void *probe) 33197e1c18eSMathieu Desnoyers { 33297e1c18eSMathieu Desnoyers void *old; 33397e1c18eSMathieu Desnoyers 33497e1c18eSMathieu Desnoyers mutex_lock(&tracepoints_mutex); 335*127cafbbSLai Jiangshan old = tracepoint_add_probe(name, probe); 33697e1c18eSMathieu Desnoyers mutex_unlock(&tracepoints_mutex); 337*127cafbbSLai Jiangshan if (IS_ERR(old)) 338*127cafbbSLai Jiangshan return PTR_ERR(old); 339*127cafbbSLai Jiangshan 34097e1c18eSMathieu Desnoyers tracepoint_update_probes(); /* may update entry */ 34119dba33cSLai Jiangshan release_probes(old); 34219dba33cSLai Jiangshan return 0; 34397e1c18eSMathieu Desnoyers } 34497e1c18eSMathieu Desnoyers EXPORT_SYMBOL_GPL(tracepoint_probe_register); 34597e1c18eSMathieu Desnoyers 346*127cafbbSLai Jiangshan static void *tracepoint_remove_probe(const char *name, void *probe) 347*127cafbbSLai Jiangshan { 348*127cafbbSLai Jiangshan struct tracepoint_entry *entry; 349*127cafbbSLai Jiangshan void *old; 350*127cafbbSLai Jiangshan 351*127cafbbSLai Jiangshan entry = get_tracepoint(name); 352*127cafbbSLai Jiangshan if (!entry) 353*127cafbbSLai Jiangshan return ERR_PTR(-ENOENT); 354*127cafbbSLai Jiangshan old = tracepoint_entry_remove_probe(entry, probe); 355*127cafbbSLai Jiangshan if (IS_ERR(old)) 356*127cafbbSLai Jiangshan return old; 357*127cafbbSLai Jiangshan if (!entry->refcount) 358*127cafbbSLai Jiangshan remove_tracepoint(entry); 359*127cafbbSLai Jiangshan return old; 360*127cafbbSLai Jiangshan } 361*127cafbbSLai Jiangshan 36297e1c18eSMathieu Desnoyers /** 36397e1c18eSMathieu Desnoyers * tracepoint_probe_unregister - Disconnect a probe from a tracepoint 36497e1c18eSMathieu Desnoyers * @name: tracepoint name 36597e1c18eSMathieu Desnoyers * @probe: probe function pointer 36697e1c18eSMathieu Desnoyers * 36797e1c18eSMathieu Desnoyers * We do not need to call a synchronize_sched to make sure the probes have 36897e1c18eSMathieu Desnoyers * finished running before doing a module unload, because the module unload 36997e1c18eSMathieu Desnoyers * itself uses stop_machine(), which insures that every preempt disabled section 37097e1c18eSMathieu Desnoyers * have finished. 37197e1c18eSMathieu Desnoyers */ 37297e1c18eSMathieu Desnoyers int tracepoint_probe_unregister(const char *name, void *probe) 37397e1c18eSMathieu Desnoyers { 37497e1c18eSMathieu Desnoyers void *old; 37597e1c18eSMathieu Desnoyers 37697e1c18eSMathieu Desnoyers mutex_lock(&tracepoints_mutex); 377*127cafbbSLai Jiangshan old = tracepoint_remove_probe(name, probe); 37897e1c18eSMathieu Desnoyers mutex_unlock(&tracepoints_mutex); 379*127cafbbSLai Jiangshan if (IS_ERR(old)) 380*127cafbbSLai Jiangshan return PTR_ERR(old); 381*127cafbbSLai Jiangshan 38297e1c18eSMathieu Desnoyers tracepoint_update_probes(); /* may update entry */ 38319dba33cSLai Jiangshan release_probes(old); 38419dba33cSLai Jiangshan return 0; 38597e1c18eSMathieu Desnoyers } 38697e1c18eSMathieu Desnoyers EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); 38797e1c18eSMathieu Desnoyers 388*127cafbbSLai Jiangshan static LIST_HEAD(old_probes); 389*127cafbbSLai Jiangshan static int need_update; 390*127cafbbSLai Jiangshan 391*127cafbbSLai Jiangshan static void tracepoint_add_old_probes(void *old) 392*127cafbbSLai Jiangshan { 393*127cafbbSLai Jiangshan need_update = 1; 394*127cafbbSLai Jiangshan if (old) { 395*127cafbbSLai Jiangshan struct tp_probes *tp_probes = container_of(old, 396*127cafbbSLai Jiangshan struct tp_probes, probes[0]); 397*127cafbbSLai Jiangshan list_add(&tp_probes->u.list, &old_probes); 398*127cafbbSLai Jiangshan } 399*127cafbbSLai Jiangshan } 400*127cafbbSLai Jiangshan 401*127cafbbSLai Jiangshan /** 402*127cafbbSLai Jiangshan * tracepoint_probe_register_noupdate - register a probe but not connect 403*127cafbbSLai Jiangshan * @name: tracepoint name 404*127cafbbSLai Jiangshan * @probe: probe handler 405*127cafbbSLai Jiangshan * 406*127cafbbSLai Jiangshan * caller must call tracepoint_probe_update_all() 407*127cafbbSLai Jiangshan */ 408*127cafbbSLai Jiangshan int tracepoint_probe_register_noupdate(const char *name, void *probe) 409*127cafbbSLai Jiangshan { 410*127cafbbSLai Jiangshan void *old; 411*127cafbbSLai Jiangshan 412*127cafbbSLai Jiangshan mutex_lock(&tracepoints_mutex); 413*127cafbbSLai Jiangshan old = tracepoint_add_probe(name, probe); 414*127cafbbSLai Jiangshan if (IS_ERR(old)) { 415*127cafbbSLai Jiangshan mutex_unlock(&tracepoints_mutex); 416*127cafbbSLai Jiangshan return PTR_ERR(old); 417*127cafbbSLai Jiangshan } 418*127cafbbSLai Jiangshan tracepoint_add_old_probes(old); 419*127cafbbSLai Jiangshan mutex_unlock(&tracepoints_mutex); 420*127cafbbSLai Jiangshan return 0; 421*127cafbbSLai Jiangshan } 422*127cafbbSLai Jiangshan EXPORT_SYMBOL_GPL(tracepoint_probe_register_noupdate); 423*127cafbbSLai Jiangshan 424*127cafbbSLai Jiangshan /** 425*127cafbbSLai Jiangshan * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect 426*127cafbbSLai Jiangshan * @name: tracepoint name 427*127cafbbSLai Jiangshan * @probe: probe function pointer 428*127cafbbSLai Jiangshan * 429*127cafbbSLai Jiangshan * caller must call tracepoint_probe_update_all() 430*127cafbbSLai Jiangshan */ 431*127cafbbSLai Jiangshan int tracepoint_probe_unregister_noupdate(const char *name, void *probe) 432*127cafbbSLai Jiangshan { 433*127cafbbSLai Jiangshan void *old; 434*127cafbbSLai Jiangshan 435*127cafbbSLai Jiangshan mutex_lock(&tracepoints_mutex); 436*127cafbbSLai Jiangshan old = tracepoint_remove_probe(name, probe); 437*127cafbbSLai Jiangshan if (IS_ERR(old)) { 438*127cafbbSLai Jiangshan mutex_unlock(&tracepoints_mutex); 439*127cafbbSLai Jiangshan return PTR_ERR(old); 440*127cafbbSLai Jiangshan } 441*127cafbbSLai Jiangshan tracepoint_add_old_probes(old); 442*127cafbbSLai Jiangshan mutex_unlock(&tracepoints_mutex); 443*127cafbbSLai Jiangshan return 0; 444*127cafbbSLai Jiangshan } 445*127cafbbSLai Jiangshan EXPORT_SYMBOL_GPL(tracepoint_probe_unregister_noupdate); 446*127cafbbSLai Jiangshan 447*127cafbbSLai Jiangshan /** 448*127cafbbSLai Jiangshan * tracepoint_probe_update_all - update tracepoints 449*127cafbbSLai Jiangshan */ 450*127cafbbSLai Jiangshan void tracepoint_probe_update_all(void) 451*127cafbbSLai Jiangshan { 452*127cafbbSLai Jiangshan LIST_HEAD(release_probes); 453*127cafbbSLai Jiangshan struct tp_probes *pos, *next; 454*127cafbbSLai Jiangshan 455*127cafbbSLai Jiangshan mutex_lock(&tracepoints_mutex); 456*127cafbbSLai Jiangshan if (!need_update) { 457*127cafbbSLai Jiangshan mutex_unlock(&tracepoints_mutex); 458*127cafbbSLai Jiangshan return; 459*127cafbbSLai Jiangshan } 460*127cafbbSLai Jiangshan if (!list_empty(&old_probes)) 461*127cafbbSLai Jiangshan list_replace_init(&old_probes, &release_probes); 462*127cafbbSLai Jiangshan need_update = 0; 463*127cafbbSLai Jiangshan mutex_unlock(&tracepoints_mutex); 464*127cafbbSLai Jiangshan 465*127cafbbSLai Jiangshan tracepoint_update_probes(); 466*127cafbbSLai Jiangshan list_for_each_entry_safe(pos, next, &release_probes, u.list) { 467*127cafbbSLai Jiangshan list_del(&pos->u.list); 468*127cafbbSLai Jiangshan call_rcu_sched(&pos->u.rcu, rcu_free_old_probes); 469*127cafbbSLai Jiangshan } 470*127cafbbSLai Jiangshan } 471*127cafbbSLai Jiangshan EXPORT_SYMBOL_GPL(tracepoint_probe_update_all); 472*127cafbbSLai Jiangshan 47397e1c18eSMathieu Desnoyers /** 47497e1c18eSMathieu Desnoyers * tracepoint_get_iter_range - Get a next tracepoint iterator given a range. 47597e1c18eSMathieu Desnoyers * @tracepoint: current tracepoints (in), next tracepoint (out) 47697e1c18eSMathieu Desnoyers * @begin: beginning of the range 47797e1c18eSMathieu Desnoyers * @end: end of the range 47897e1c18eSMathieu Desnoyers * 47997e1c18eSMathieu Desnoyers * Returns whether a next tracepoint has been found (1) or not (0). 48097e1c18eSMathieu Desnoyers * Will return the first tracepoint in the range if the input tracepoint is 48197e1c18eSMathieu Desnoyers * NULL. 48297e1c18eSMathieu Desnoyers */ 48397e1c18eSMathieu Desnoyers int tracepoint_get_iter_range(struct tracepoint **tracepoint, 48497e1c18eSMathieu Desnoyers struct tracepoint *begin, struct tracepoint *end) 48597e1c18eSMathieu Desnoyers { 48697e1c18eSMathieu Desnoyers if (!*tracepoint && begin != end) { 48797e1c18eSMathieu Desnoyers *tracepoint = begin; 48897e1c18eSMathieu Desnoyers return 1; 48997e1c18eSMathieu Desnoyers } 49097e1c18eSMathieu Desnoyers if (*tracepoint >= begin && *tracepoint < end) 49197e1c18eSMathieu Desnoyers return 1; 49297e1c18eSMathieu Desnoyers return 0; 49397e1c18eSMathieu Desnoyers } 49497e1c18eSMathieu Desnoyers EXPORT_SYMBOL_GPL(tracepoint_get_iter_range); 49597e1c18eSMathieu Desnoyers 49697e1c18eSMathieu Desnoyers static void tracepoint_get_iter(struct tracepoint_iter *iter) 49797e1c18eSMathieu Desnoyers { 49897e1c18eSMathieu Desnoyers int found = 0; 49997e1c18eSMathieu Desnoyers 50097e1c18eSMathieu Desnoyers /* Core kernel tracepoints */ 50197e1c18eSMathieu Desnoyers if (!iter->module) { 50297e1c18eSMathieu Desnoyers found = tracepoint_get_iter_range(&iter->tracepoint, 50397e1c18eSMathieu Desnoyers __start___tracepoints, __stop___tracepoints); 50497e1c18eSMathieu Desnoyers if (found) 50597e1c18eSMathieu Desnoyers goto end; 50697e1c18eSMathieu Desnoyers } 50797e1c18eSMathieu Desnoyers /* tracepoints in modules. */ 50897e1c18eSMathieu Desnoyers found = module_get_iter_tracepoints(iter); 50997e1c18eSMathieu Desnoyers end: 51097e1c18eSMathieu Desnoyers if (!found) 51197e1c18eSMathieu Desnoyers tracepoint_iter_reset(iter); 51297e1c18eSMathieu Desnoyers } 51397e1c18eSMathieu Desnoyers 51497e1c18eSMathieu Desnoyers void tracepoint_iter_start(struct tracepoint_iter *iter) 51597e1c18eSMathieu Desnoyers { 51697e1c18eSMathieu Desnoyers tracepoint_get_iter(iter); 51797e1c18eSMathieu Desnoyers } 51897e1c18eSMathieu Desnoyers EXPORT_SYMBOL_GPL(tracepoint_iter_start); 51997e1c18eSMathieu Desnoyers 52097e1c18eSMathieu Desnoyers void tracepoint_iter_next(struct tracepoint_iter *iter) 52197e1c18eSMathieu Desnoyers { 52297e1c18eSMathieu Desnoyers iter->tracepoint++; 52397e1c18eSMathieu Desnoyers /* 52497e1c18eSMathieu Desnoyers * iter->tracepoint may be invalid because we blindly incremented it. 52597e1c18eSMathieu Desnoyers * Make sure it is valid by marshalling on the tracepoints, getting the 52697e1c18eSMathieu Desnoyers * tracepoints from following modules if necessary. 52797e1c18eSMathieu Desnoyers */ 52897e1c18eSMathieu Desnoyers tracepoint_get_iter(iter); 52997e1c18eSMathieu Desnoyers } 53097e1c18eSMathieu Desnoyers EXPORT_SYMBOL_GPL(tracepoint_iter_next); 53197e1c18eSMathieu Desnoyers 53297e1c18eSMathieu Desnoyers void tracepoint_iter_stop(struct tracepoint_iter *iter) 53397e1c18eSMathieu Desnoyers { 53497e1c18eSMathieu Desnoyers } 53597e1c18eSMathieu Desnoyers EXPORT_SYMBOL_GPL(tracepoint_iter_stop); 53697e1c18eSMathieu Desnoyers 53797e1c18eSMathieu Desnoyers void tracepoint_iter_reset(struct tracepoint_iter *iter) 53897e1c18eSMathieu Desnoyers { 53997e1c18eSMathieu Desnoyers iter->module = NULL; 54097e1c18eSMathieu Desnoyers iter->tracepoint = NULL; 54197e1c18eSMathieu Desnoyers } 54297e1c18eSMathieu Desnoyers EXPORT_SYMBOL_GPL(tracepoint_iter_reset); 543