Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 121050
b: refs/heads/master
c: 127cafb
h: refs/heads/master
v: v3
  • Loading branch information
Lai Jiangshan authored and Ingo Molnar committed Nov 3, 2008
1 parent 718365d commit f1982fa
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 39 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 19dba33c43a2f0f2aa727ae075ec3b11330775ef
refs/heads/master: 127cafbb276266b1b8da967bfe25a062ab1d42ab
4 changes: 4 additions & 0 deletions trunk/include/linux/tracepoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ extern int tracepoint_probe_register(const char *name, void *probe);
*/
extern int tracepoint_probe_unregister(const char *name, void *probe);

extern int tracepoint_probe_register_noupdate(const char *name, void *probe);
extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe);
extern void tracepoint_probe_update_all(void);

struct tracepoint_iter {
struct module *module;
struct tracepoint *tracepoint;
Expand Down
170 changes: 132 additions & 38 deletions trunk/kernel/tracepoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ struct tracepoint_entry {
};

struct tp_probes {
struct rcu_head rcu;
union {
struct rcu_head rcu;
struct list_head list;
} u;
void *probes[0];
};

Expand All @@ -72,15 +75,15 @@ static inline void *allocate_probes(int count)

static void rcu_free_old_probes(struct rcu_head *head)
{
kfree(container_of(head, struct tp_probes, rcu));
kfree(container_of(head, struct tp_probes, u.rcu));
}

static inline void release_probes(void *old)
{
if (old) {
struct tp_probes *tp_probes = container_of(old,
struct tp_probes, probes[0]);
call_rcu(&tp_probes->rcu, rcu_free_old_probes);
call_rcu_sched(&tp_probes->u.rcu, rcu_free_old_probes);
}
}

Expand Down Expand Up @@ -299,6 +302,23 @@ static void tracepoint_update_probes(void)
module_update_tracepoints();
}

static void *tracepoint_add_probe(const char *name, void *probe)
{
struct tracepoint_entry *entry;
void *old;

entry = get_tracepoint(name);
if (!entry) {
entry = add_tracepoint(name);
if (IS_ERR(entry))
return entry;
}
old = tracepoint_entry_add_probe(entry, probe);
if (IS_ERR(old) && !entry->refcount)
remove_tracepoint(entry);
return old;
}

/**
* tracepoint_probe_register - Connect a probe to a tracepoint
* @name: tracepoint name
Expand All @@ -309,36 +329,36 @@ static void tracepoint_update_probes(void)
*/
int tracepoint_probe_register(const char *name, void *probe)
{
struct tracepoint_entry *entry;
int ret = 0;
void *old;

mutex_lock(&tracepoints_mutex);
entry = get_tracepoint(name);
if (!entry) {
entry = add_tracepoint(name);
if (IS_ERR(entry)) {
ret = PTR_ERR(entry);
goto end;
}
}
old = tracepoint_entry_add_probe(entry, probe);
if (IS_ERR(old)) {
if (!entry->refcount)
remove_tracepoint(entry);
ret = PTR_ERR(old);
goto end;
}
old = tracepoint_add_probe(name, probe);
mutex_unlock(&tracepoints_mutex);
if (IS_ERR(old))
return PTR_ERR(old);

tracepoint_update_probes(); /* may update entry */
release_probes(old);
return 0;
end:
mutex_unlock(&tracepoints_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(tracepoint_probe_register);

static void *tracepoint_remove_probe(const char *name, void *probe)
{
struct tracepoint_entry *entry;
void *old;

entry = get_tracepoint(name);
if (!entry)
return ERR_PTR(-ENOENT);
old = tracepoint_entry_remove_probe(entry, probe);
if (IS_ERR(old))
return old;
if (!entry->refcount)
remove_tracepoint(entry);
return old;
}

/**
* tracepoint_probe_unregister - Disconnect a probe from a tracepoint
* @name: tracepoint name
Expand All @@ -351,31 +371,105 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_register);
*/
int tracepoint_probe_unregister(const char *name, void *probe)
{
struct tracepoint_entry *entry;
void *old;
int ret = -ENOENT;

mutex_lock(&tracepoints_mutex);
entry = get_tracepoint(name);
if (!entry)
goto end;
old = tracepoint_entry_remove_probe(entry, probe);
if (IS_ERR(old)) {
ret = PTR_ERR(old);
goto end;
}
if (!entry->refcount)
remove_tracepoint(entry);
old = tracepoint_remove_probe(name, probe);
mutex_unlock(&tracepoints_mutex);
if (IS_ERR(old))
return PTR_ERR(old);

tracepoint_update_probes(); /* may update entry */
release_probes(old);
return 0;
end:
mutex_unlock(&tracepoints_mutex);
return ret;
}
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
*
* caller must call tracepoint_probe_update_all()
*/
int tracepoint_probe_register_noupdate(const char *name, void *probe)
{
void *old;

mutex_lock(&tracepoints_mutex);
old = tracepoint_add_probe(name, probe);
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
*
* caller must call tracepoint_probe_update_all()
*/
int tracepoint_probe_unregister_noupdate(const char *name, void *probe)
{
void *old;

mutex_lock(&tracepoints_mutex);
old = tracepoint_remove_probe(name, probe);
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;
mutex_unlock(&tracepoints_mutex);

tracepoint_update_probes();
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)
Expand Down

0 comments on commit f1982fa

Please sign in to comment.