518 lines · 13.2 KB · C
RawDownload
/* * 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)

Lines 1–500 of 518.