| /* |
| * 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 <linux/module.h> |
| #include <linux/mutex.h> |
| #include <linux/types.h> |
| #include <linux/jhash.h> |
| #include <linux/list.h> |
| #include <linux/rcupdate.h> |
| #include <linux/marker.h> |
| #include <linux/err.h> |
| |
| 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); |