/* * Copyright (C) 2007 Mathieu Desnoyers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include extern struct marker __start___markers[]; extern struct marker __stop___markers[]; /* * markers_mutex nests inside module_mutex. Markers mutex protects the builtin * and module markers, the hash table and deferred_sync. */ static DEFINE_MUTEX(markers_mutex); /* * Marker deferred synchronization. * Upon marker probe_unregister, we delay call to synchronize_sched() to * accelerate mass unregistration (only when there is no more reference to a * given module do we call synchronize_sched()). However, we need to make sure * every critical region has ended before we re-arm a marker that has been * unregistered and then registered back with a different probe data. */ static int deferred_sync; /* * Marker hash table, containing the active markers. * Protected by module_mutex. */ #define MARKER_HASH_BITS 6 #define MARKER_TABLE_SIZE (1 << MARKER_HASH_BITS) struct marker_entry { struct hlist_node hlist; char *format; marker_probe_func *probe; void *private; int refcount; /* Number of times armed. 0 if disarmed. */ char name[0]; /* Contains name'\0'format'\0' */ }; static struct hlist_head marker_table[MARKER_TABLE_SIZE]; /** * __mark_empty_function - Empty probe callback * @mdata: pointer of type const struct marker * @fmt: format string * @...: variable argument list * * Empty callback provided as a probe to the markers. By providing this to a * disabled marker, we make sure the execution flow is always valid even * though the function pointer change and the marker enabling are two distinct * operations that modifies the execution flow of preemptible code. */ void __mark_empty_function(const struct marker *mdata, void *private, const char *fmt, ...) { } EXPORT_SYMBOL_GPL(__mark_empty_function); /* * Get marker if the marker is present in the marker hash table. * Must be called with markers_mutex held. * Returns NULL if not present. */ static struct marker_entry *get_marker(const char *name) { struct hlist_head *head; struct hlist_node *node; struct marker_entry *e; u32 hash = jhash(name, strlen(name), 0); head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(name, e->name)) return e; } return NULL; } /* * Add the marker to the marker hash table. Must be called with markers_mutex * held. */ static int add_marker(const char *name, const char *format, marker_probe_func *probe, void *private) { struct hlist_head *head; struct hlist_node *node; struct marker_entry *e; size_t name_len = strlen(name) + 1; size_t format_len = 0; u32 hash = jhash(name, name_len-1, 0); if (format) format_len = strlen(format) + 1; head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(name, e->name)) { printk(KERN_NOTICE "Marker %s busy, probe %p already installed\n", name, e->probe); return -EBUSY; /* Already there */ } } /* * Using kmalloc here to allocate a variable length element. Could * cause some memory fragmentation if overused. */ e = kmalloc(sizeof(struct marker_entry) + name_len + format_len, GFP_KERNEL); if (!e) return -ENOMEM; memcpy(&e->name[0], name, name_len); if (format) { e->format = &e->name[name_len]; memcpy(e->format, format, format_len); trace_mark(core_marker_format, "name %s format %s", e->name, e->format); } else e->format = NULL; e->probe = probe; e->private = private; e->refcount = 0; hlist_add_head(&e->hlist, head); return 0; } /* * Remove the marker from the marker hash table. Must be called with mutex_lock * held. */ static void *remove_marker(const char *name) { struct hlist_head *head; struct hlist_node *node; struct marker_entry *e; int found = 0; size_t len = strlen(name) + 1; void *private = NULL; u32 hash = jhash(name, len-1, 0); head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(name, e->name)) { found = 1; break; } } if (found) { private = e->private; hlist_del(&e->hlist); kfree(e); } return private; } /* * Set the mark_entry format to the format found in the element. */ static int marker_set_format(struct marker_entry **entry, const char *format) { struct marker_entry *e; size_t name_len = strlen((*entry)->name) + 1; size_t format_len = strlen(format) + 1; e = kmalloc(sizeof(struct marker_entry) + name_len + format_len, GFP_KERNEL); if (!e) return -ENOMEM; memcpy(&e->name[0], (*entry)->name, name_len); e->format = &e->name[name_len]; memcpy(e->format, format, format_len); e->probe = (*entry)->probe; e->private = (*entry)->private; e->refcount = (*entry)->refcount; hlist_add_before(&e->hlist, &(*entry)->hlist); hlist_del(&(*entry)->hlist); kfree(*entry); *entry = e; trace_mark(core_marker_format, "name %s format %s", e->name, e->format); return 0; } /* * Sets the probe callback corresponding to one marker. */ static int set_marker(struct marker_entry **entry, struct marker *elem) { int ret; WARN_ON(strcmp((*entry)->name, elem->name) != 0); if ((*entry)->format) { if (strcmp((*entry)->format, elem->format) != 0) { printk(KERN_NOTICE "Format mismatch for probe %s " "(%s), marker (%s)\n", (*entry)->name, (*entry)->format, elem->format); return -EPERM; } } else { ret = marker_set_format(entry, elem->format); if (ret) return ret; } elem->call = (*entry)->probe; elem->private = (*entry)->private; elem->state = 1; return 0; } /* * Disable a marker and its probe callback. * Note: only after a synchronize_sched() issued after setting elem->call to the * empty function insures that the original callback is not used anymore. This * insured by preemption disabling around the call site. */ static void disable_marker(struct marker *elem) { elem->state = 0; elem->call = __mark_empty_function; /* * Leave the private data and id there, because removal is racy and * should be done only after a synchronize_sched(). These are never used * until the next initialization anyway. */ } /** * marker_update_probe_range - Update a probe range * @begin: beginning of the range * @end: end of the range * @probe_module: module address of the probe being updated * @refcount: number of references left to the given probe_module (out) * * Updates the probe callback corresponding to a range of markers. */ void marker_update_probe_range(struct marker *begin, struct marker *end, struct module *probe_module, int *refcount) { struct marker *iter; struct marker_entry *mark_entry; mutex_lock(&markers_mutex); for (iter = begin; iter < end; iter++) { mark_entry = get_marker(iter->name); if (mark_entry && mark_entry->refcount) { set_marker(&mark_entry, iter); /* * ignore error, continue */ if (probe_module) if (probe_module == __module_text_address((unsigned long)mark_entry->probe)) (*refcount)++; } else { disable_marker(iter); } } mutex_unlock(&markers_mutex); } /* * Update probes, removing the faulty probes. * Issues a synchronize_sched() when no reference to the module passed * as parameter is found in the probes so the probe module can be * safely unloaded from now on. */ static void marker_update_probes(struct module *probe_module) { int refcount = 0; /* Core kernel markers */ marker_update_probe_range(__start___markers, __stop___markers, probe_module, &refcount); /* Markers in modules. */ module_update_markers(probe_module, &refcount); if (probe_module && refcount == 0) { synchronize_sched(); deferred_sync = 0; } } /** * marker_probe_register - Connect a probe to a marker * @name: marker name * @format: format string * @probe: probe handler * @private: probe private data * * private data must be a valid allocated memory address, or NULL. * Returns 0 if ok, error value on error. */ int marker_probe_register(const char *name, const char *format, marker_probe_func *probe, void *private) { struct marker_entry *entry; int ret = 0; mutex_lock(&markers_mutex); entry = get_marker(name); if (entry && entry->refcount) { ret = -EBUSY; goto end; } if (deferred_sync) { synchronize_sched(); deferred_sync = 0; } ret = add_marker(name, format, probe, private); if (ret) goto end; mutex_unlock(&markers_mutex); marker_update_probes(NULL); return ret; end: mutex_unlock(&markers_mutex); return ret; } EXPORT_SYMBOL_GPL(marker_probe_register); /** * marker_probe_unregister - Disconnect a probe from a marker * @name: marker name * * Returns the private data given to marker_probe_register, or an ERR_PTR(). */ void *marker_probe_unregister(const char *name) { struct module *probe_module; struct marker_entry *entry; void *private; mutex_lock(&markers_mutex); entry = get_marker(name); if (!entry) { private = ERR_PTR(-ENOENT); goto end; } entry->refcount = 0; /* In what module is the probe handler ? */ probe_module = __module_text_address((unsigned long)entry->probe); private = remove_marker(name); deferred_sync = 1; mutex_unlock(&markers_mutex); marker_update_probes(probe_module); return private; end: mutex_unlock(&markers_mutex); return private; } EXPORT_SYMBOL_GPL(marker_probe_unregister); /** * marker_probe_unregister_private_data - Disconnect a probe from a marker * @private: probe private data * * Unregister a marker by providing the registered private data. * Returns the private data given to marker_probe_register, or an ERR_PTR(). */ void *marker_probe_unregister_private_data(void *private) { struct module *probe_module; struct hlist_head *head; struct hlist_node *node; struct marker_entry *entry; int found = 0; unsigned int i; mutex_lock(&markers_mutex); for (i = 0; i < MARKER_TABLE_SIZE; i++) { head = &marker_table[i]; hlist_for_each_entry(entry, node, head, hlist) { if (entry->private == private) { found = 1; goto iter_end; } } } iter_end: if (!found) { private = ERR_PTR(-ENOENT); goto end; } entry->refcount = 0; /* In what module is the probe handler ? */ probe_module = __module_text_address((unsigned long)entry->probe); private = remove_marker(entry->name); deferred_sync = 1; mutex_unlock(&markers_mutex); marker_update_probes(probe_module); return private; end: mutex_unlock(&markers_mutex); return private; } EXPORT_SYMBOL_GPL(marker_probe_unregister_private_data); /** * marker_arm - Arm a marker * @name: marker name * * Activate a marker. It keeps a reference count of the number of * arming/disarming done. * Returns 0 if ok, error value on error. */ int marker_arm(const char *name) { struct marker_entry *entry; int ret = 0; mutex_lock(&markers_mutex); entry = get_marker(name); if (!entry) { ret = -ENOENT; goto end; } /* * Only need to update probes when refcount passes from 0 to 1. */ if (entry->refcount++) goto end; end: mutex_unlock(&markers_mutex); marker_update_probes(NULL); return ret; } EXPORT_SYMBOL_GPL(marker_arm); /** * marker_disarm - Disarm a marker * @name: marker name * * Disarm a marker. It keeps a reference count of the number of arming/disarming * done. * Returns 0 if ok, error value on error. */ int marker_disarm(const char *name) { struct marker_entry *entry; int ret = 0; mutex_lock(&markers_mutex); entry = get_marker(name); if (!entry) { ret = -ENOENT; goto end; } /* * Only permit decrement refcount if higher than 0. * Do probe update only on 1 -> 0 transition. */ if (entry->refcount) { if (--entry->refcount) goto end; } else { ret = -EPERM; goto end; } end: mutex_unlock(&markers_mutex); marker_update_probes(NULL); return ret; } EXPORT_SYMBOL_GPL(marker_disarm); /** * marker_get_private_data - Get a marker's probe private data * @name: marker name * * Returns the private data pointer, or an ERR_PTR. * The private data pointer should _only_ be dereferenced if the caller is the * owner of the data, or its content could vanish. This is mostly used to * confirm that a caller is the owner of a registered probe. */ void *marker_get_private_data(const char *name) { struct hlist_head *head; struct hlist_node *node; struct marker_entry *e; size_t name_len = strlen(name) + 1; u32 hash = jhash(name, name_len-1, 0); int found = 0; head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(name, e->name)) { found = 1; return e->private; } } return ERR_PTR(-ENOENT); } EXPORT_SYMBOL_GPL(marker_get_private_data);