Commit | Line | Data |
---|---|---|
02119ee5 MD |
1 | /* |
2 | * ltt-probes.c | |
3 | * | |
4 | * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
5 | * | |
6 | * Holds LTTng probes registry. | |
7 | */ | |
8 | ||
9 | #include <linux/module.h> | |
10 | #include <linux/list.h> | |
11 | #include <linux/mutex.h> | |
12 | #include <linux/slab.h> | |
13 | ||
14 | struct ltt_probe { | |
15 | const char *name; | |
16 | void *cb; | |
17 | struct list_head list; | |
18 | }; | |
19 | ||
20 | static LIST_HEAD(probe_list); | |
21 | static DEFINE_MUTEX(probe_mutex); | |
22 | static struct kmem_cache *probe_cache; | |
23 | ||
dda6a249 | 24 | static struct ltt_probe *find_probe(const char *name) |
02119ee5 MD |
25 | { |
26 | struct ltt_probe *probe; | |
27 | ||
28 | list_for_each_entry(probe, &probe_list, list) { | |
29 | if (!strcmp(probe->name, name)) | |
dda6a249 | 30 | return probe; |
02119ee5 MD |
31 | } |
32 | return NULL; | |
33 | } | |
34 | ||
35 | int ltt_probe_register(const char *name, void *cb) | |
36 | { | |
37 | struct ltt_probe *probe; | |
38 | int ret = 0; | |
39 | ||
40 | if (!cb) | |
41 | return -EPERM; | |
42 | ||
43 | mutex_lock(&probe_mutex); | |
44 | if (find_probe(name)) { | |
45 | ret = -EEXIST; | |
46 | goto end; | |
47 | } | |
48 | probe = kmem_cache_zalloc(probe_cache, GFP_KERNEL); | |
49 | if (!probe) { | |
50 | ret = -ENOMEM; | |
51 | goto end; | |
52 | } | |
53 | probe->name = name; | |
54 | probe->cb = cb; | |
55 | list_add(&probe->list, &probe_list); | |
56 | end: | |
57 | mutex_unlock(&probe_mutex); | |
58 | return ret; | |
59 | } | |
60 | EXPORT_SYMBOL_GPL(ltt_probe_register); | |
61 | ||
62 | void ltt_probe_unregister(const char *name) | |
63 | { | |
64 | struct ltt_probe *probe; | |
65 | ||
66 | mutex_lock(&probe_mutex); | |
67 | probe = find_probe(name); | |
68 | WARN_ON_ONCE(!probe); | |
69 | list_del(&probe->list); | |
70 | mutex_unlock(&probe_mutex); | |
71 | kmem_cache_free(probe_cache, probe); | |
72 | } | |
73 | EXPORT_SYMBOL_GPL(ltt_probe_unregister); | |
74 | ||
75 | void *ltt_probe_get(const char *name) | |
76 | { | |
77 | struct ltt_probe *probe; | |
78 | void *cb = NULL; | |
79 | int ret; | |
80 | ||
81 | mutex_lock(&probe_mutex); | |
82 | probe = find_probe(name); | |
83 | if (!probe) | |
84 | goto end; | |
85 | cb = probe->cb; | |
86 | ret = try_module_get(__module_text_address((unsigned long) cb)); | |
87 | WARN_ON_ONCE(!ret); | |
88 | end: | |
89 | mutex_unlock(&probe_mutex); | |
90 | return cb; | |
91 | } | |
92 | EXPORT_SYMBOL_GPL(ltt_probe_get); | |
93 | ||
94 | void ltt_probe_put(void *cb) | |
95 | { | |
96 | module_put(__module_text_address((unsigned long) cb)); | |
97 | } | |
98 | EXPORT_SYMBOL_GPL(ltt_probe_put); | |
99 | ||
100 | int __init ltt_probes_init(void) | |
101 | { | |
102 | probe_cache = KMEM_CACHE(ltt_probe, 0); | |
103 | if (!probe_cache) | |
104 | return -ENOMEM; | |
105 | return 0; | |
106 | } | |
107 | ||
108 | void __exit ltt_probes_exit(void) | |
109 | { | |
110 | kmem_cache_destroy(probe_cache); | |
111 | } |