|
@@ -67,10 +67,7 @@ struct tracepoint_entry {
|
|
};
|
|
};
|
|
|
|
|
|
struct tp_probes {
|
|
struct tp_probes {
|
|
- union {
|
|
|
|
- struct rcu_head rcu;
|
|
|
|
- struct list_head list;
|
|
|
|
- } u;
|
|
|
|
|
|
+ struct rcu_head rcu;
|
|
struct tracepoint_func probes[0];
|
|
struct tracepoint_func probes[0];
|
|
};
|
|
};
|
|
|
|
|
|
@@ -83,7 +80,7 @@ static inline void *allocate_probes(int count)
|
|
|
|
|
|
static void rcu_free_old_probes(struct rcu_head *head)
|
|
static void rcu_free_old_probes(struct rcu_head *head)
|
|
{
|
|
{
|
|
- kfree(container_of(head, struct tp_probes, u.rcu));
|
|
|
|
|
|
+ kfree(container_of(head, struct tp_probes, rcu));
|
|
}
|
|
}
|
|
|
|
|
|
static inline void release_probes(struct tracepoint_func *old)
|
|
static inline void release_probes(struct tracepoint_func *old)
|
|
@@ -91,7 +88,7 @@ static inline void release_probes(struct tracepoint_func *old)
|
|
if (old) {
|
|
if (old) {
|
|
struct tp_probes *tp_probes = container_of(old,
|
|
struct tp_probes *tp_probes = container_of(old,
|
|
struct tp_probes, probes[0]);
|
|
struct tp_probes, probes[0]);
|
|
- call_rcu_sched(&tp_probes->u.rcu, rcu_free_old_probes);
|
|
|
|
|
|
+ call_rcu_sched(&tp_probes->rcu, rcu_free_old_probes);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -459,204 +456,11 @@ int tracepoint_probe_unregister(const char *name, void *probe, void *data)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(tracepoint_probe_unregister);
|
|
EXPORT_SYMBOL_GPL(tracepoint_probe_unregister);
|
|
|
|
|
|
-static LIST_HEAD(old_probes);
|
|
|
|
-static int need_update;
|
|
|
|
-
|
|
|
|
-static void tracepoint_add_old_probes(void *old)
|
|
|
|
-{
|
|
|
|
- need_update = 1;
|
|
|
|
- if (old) {
|
|
|
|
- struct tp_probes *tp_probes = container_of(old,
|
|
|
|
- struct tp_probes, probes[0]);
|
|
|
|
- list_add(&tp_probes->u.list, &old_probes);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * tracepoint_probe_register_noupdate - register a probe but not connect
|
|
|
|
- * @name: tracepoint name
|
|
|
|
- * @probe: probe handler
|
|
|
|
- * @data: probe private data
|
|
|
|
- *
|
|
|
|
- * caller must call tracepoint_probe_update_all()
|
|
|
|
- */
|
|
|
|
-int tracepoint_probe_register_noupdate(const char *name, void *probe,
|
|
|
|
- void *data)
|
|
|
|
-{
|
|
|
|
- struct tracepoint_func *old;
|
|
|
|
-
|
|
|
|
- mutex_lock(&tracepoints_mutex);
|
|
|
|
- old = tracepoint_add_probe(name, probe, data);
|
|
|
|
- if (IS_ERR(old)) {
|
|
|
|
- mutex_unlock(&tracepoints_mutex);
|
|
|
|
- return PTR_ERR(old);
|
|
|
|
- }
|
|
|
|
- tracepoint_add_old_probes(old);
|
|
|
|
- mutex_unlock(&tracepoints_mutex);
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(tracepoint_probe_register_noupdate);
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect
|
|
|
|
- * @name: tracepoint name
|
|
|
|
- * @probe: probe function pointer
|
|
|
|
- * @data: probe private data
|
|
|
|
- *
|
|
|
|
- * caller must call tracepoint_probe_update_all()
|
|
|
|
- */
|
|
|
|
-int tracepoint_probe_unregister_noupdate(const char *name, void *probe,
|
|
|
|
- void *data)
|
|
|
|
-{
|
|
|
|
- struct tracepoint_func *old;
|
|
|
|
-
|
|
|
|
- mutex_lock(&tracepoints_mutex);
|
|
|
|
- old = tracepoint_remove_probe(name, probe, data);
|
|
|
|
- if (IS_ERR(old)) {
|
|
|
|
- mutex_unlock(&tracepoints_mutex);
|
|
|
|
- return PTR_ERR(old);
|
|
|
|
- }
|
|
|
|
- tracepoint_add_old_probes(old);
|
|
|
|
- mutex_unlock(&tracepoints_mutex);
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(tracepoint_probe_unregister_noupdate);
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * tracepoint_probe_update_all - update tracepoints
|
|
|
|
- */
|
|
|
|
-void tracepoint_probe_update_all(void)
|
|
|
|
-{
|
|
|
|
- LIST_HEAD(release_probes);
|
|
|
|
- struct tp_probes *pos, *next;
|
|
|
|
-
|
|
|
|
- mutex_lock(&tracepoints_mutex);
|
|
|
|
- if (!need_update) {
|
|
|
|
- mutex_unlock(&tracepoints_mutex);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- if (!list_empty(&old_probes))
|
|
|
|
- list_replace_init(&old_probes, &release_probes);
|
|
|
|
- need_update = 0;
|
|
|
|
- tracepoint_update_probes();
|
|
|
|
- mutex_unlock(&tracepoints_mutex);
|
|
|
|
- list_for_each_entry_safe(pos, next, &release_probes, u.list) {
|
|
|
|
- list_del(&pos->u.list);
|
|
|
|
- call_rcu_sched(&pos->u.rcu, rcu_free_old_probes);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(tracepoint_probe_update_all);
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * tracepoint_get_iter_range - Get a next tracepoint iterator given a range.
|
|
|
|
- * @tracepoint: current tracepoints (in), next tracepoint (out)
|
|
|
|
- * @begin: beginning of the range
|
|
|
|
- * @end: end of the range
|
|
|
|
- *
|
|
|
|
- * Returns whether a next tracepoint has been found (1) or not (0).
|
|
|
|
- * Will return the first tracepoint in the range if the input tracepoint is
|
|
|
|
- * NULL.
|
|
|
|
- */
|
|
|
|
-static int tracepoint_get_iter_range(struct tracepoint * const **tracepoint,
|
|
|
|
- struct tracepoint * const *begin, struct tracepoint * const *end)
|
|
|
|
-{
|
|
|
|
- if (!*tracepoint && begin != end) {
|
|
|
|
- *tracepoint = begin;
|
|
|
|
- return 1;
|
|
|
|
- }
|
|
|
|
- if (*tracepoint >= begin && *tracepoint < end)
|
|
|
|
- return 1;
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#ifdef CONFIG_MODULES
|
|
|
|
-static void tracepoint_get_iter(struct tracepoint_iter *iter)
|
|
|
|
-{
|
|
|
|
- int found = 0;
|
|
|
|
- struct tp_module *iter_mod;
|
|
|
|
-
|
|
|
|
- /* Core kernel tracepoints */
|
|
|
|
- if (!iter->module) {
|
|
|
|
- found = tracepoint_get_iter_range(&iter->tracepoint,
|
|
|
|
- __start___tracepoints_ptrs,
|
|
|
|
- __stop___tracepoints_ptrs);
|
|
|
|
- if (found)
|
|
|
|
- goto end;
|
|
|
|
- }
|
|
|
|
- /* Tracepoints in modules */
|
|
|
|
- mutex_lock(&tracepoints_mutex);
|
|
|
|
- list_for_each_entry(iter_mod, &tracepoint_module_list, list) {
|
|
|
|
- /*
|
|
|
|
- * Sorted module list
|
|
|
|
- */
|
|
|
|
- if (iter_mod < iter->module)
|
|
|
|
- continue;
|
|
|
|
- else if (iter_mod > iter->module)
|
|
|
|
- iter->tracepoint = NULL;
|
|
|
|
- found = tracepoint_get_iter_range(&iter->tracepoint,
|
|
|
|
- iter_mod->tracepoints_ptrs,
|
|
|
|
- iter_mod->tracepoints_ptrs
|
|
|
|
- + iter_mod->num_tracepoints);
|
|
|
|
- if (found) {
|
|
|
|
- iter->module = iter_mod;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- mutex_unlock(&tracepoints_mutex);
|
|
|
|
-end:
|
|
|
|
- if (!found)
|
|
|
|
- tracepoint_iter_reset(iter);
|
|
|
|
-}
|
|
|
|
-#else /* CONFIG_MODULES */
|
|
|
|
-static void tracepoint_get_iter(struct tracepoint_iter *iter)
|
|
|
|
-{
|
|
|
|
- int found = 0;
|
|
|
|
-
|
|
|
|
- /* Core kernel tracepoints */
|
|
|
|
- found = tracepoint_get_iter_range(&iter->tracepoint,
|
|
|
|
- __start___tracepoints_ptrs,
|
|
|
|
- __stop___tracepoints_ptrs);
|
|
|
|
- if (!found)
|
|
|
|
- tracepoint_iter_reset(iter);
|
|
|
|
-}
|
|
|
|
-#endif /* CONFIG_MODULES */
|
|
|
|
-
|
|
|
|
-void tracepoint_iter_start(struct tracepoint_iter *iter)
|
|
|
|
-{
|
|
|
|
- tracepoint_get_iter(iter);
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(tracepoint_iter_start);
|
|
|
|
-
|
|
|
|
-void tracepoint_iter_next(struct tracepoint_iter *iter)
|
|
|
|
-{
|
|
|
|
- iter->tracepoint++;
|
|
|
|
- /*
|
|
|
|
- * iter->tracepoint may be invalid because we blindly incremented it.
|
|
|
|
- * Make sure it is valid by marshalling on the tracepoints, getting the
|
|
|
|
- * tracepoints from following modules if necessary.
|
|
|
|
- */
|
|
|
|
- tracepoint_get_iter(iter);
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(tracepoint_iter_next);
|
|
|
|
-
|
|
|
|
-void tracepoint_iter_stop(struct tracepoint_iter *iter)
|
|
|
|
-{
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(tracepoint_iter_stop);
|
|
|
|
-
|
|
|
|
-void tracepoint_iter_reset(struct tracepoint_iter *iter)
|
|
|
|
-{
|
|
|
|
-#ifdef CONFIG_MODULES
|
|
|
|
- iter->module = NULL;
|
|
|
|
-#endif /* CONFIG_MODULES */
|
|
|
|
- iter->tracepoint = NULL;
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
|
|
|
|
|
|
|
|
#ifdef CONFIG_MODULES
|
|
#ifdef CONFIG_MODULES
|
|
static int tracepoint_module_coming(struct module *mod)
|
|
static int tracepoint_module_coming(struct module *mod)
|
|
{
|
|
{
|
|
- struct tp_module *tp_mod, *iter;
|
|
|
|
|
|
+ struct tp_module *tp_mod;
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
if (!mod->num_tracepoints)
|
|
if (!mod->num_tracepoints)
|
|
@@ -677,23 +481,7 @@ static int tracepoint_module_coming(struct module *mod)
|
|
}
|
|
}
|
|
tp_mod->num_tracepoints = mod->num_tracepoints;
|
|
tp_mod->num_tracepoints = mod->num_tracepoints;
|
|
tp_mod->tracepoints_ptrs = mod->tracepoints_ptrs;
|
|
tp_mod->tracepoints_ptrs = mod->tracepoints_ptrs;
|
|
-
|
|
|
|
- /*
|
|
|
|
- * tracepoint_module_list is kept sorted by struct module pointer
|
|
|
|
- * address for iteration on tracepoints from a seq_file that can release
|
|
|
|
- * the mutex between calls.
|
|
|
|
- */
|
|
|
|
- list_for_each_entry_reverse(iter, &tracepoint_module_list, list) {
|
|
|
|
- BUG_ON(iter == tp_mod); /* Should never be in the list twice */
|
|
|
|
- if (iter < tp_mod) {
|
|
|
|
- /* We belong to the location right after iter. */
|
|
|
|
- list_add(&tp_mod->list, &iter->list);
|
|
|
|
- goto module_added;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- /* We belong to the beginning of the list */
|
|
|
|
- list_add(&tp_mod->list, &tracepoint_module_list);
|
|
|
|
-module_added:
|
|
|
|
|
|
+ list_add_tail(&tp_mod->list, &tracepoint_module_list);
|
|
tracepoint_update_probe_range(mod->tracepoints_ptrs,
|
|
tracepoint_update_probe_range(mod->tracepoints_ptrs,
|
|
mod->tracepoints_ptrs + mod->num_tracepoints);
|
|
mod->tracepoints_ptrs + mod->num_tracepoints);
|
|
end:
|
|
end:
|