LTTng modules now builds again
[lttng-modules.git] / discard / ltt-marker-control.c
1 /*
2 * Copyright (C) 2007 Mathieu Desnoyers
3 *
4 * Dual LGPL v2.1/GPL v2 license.
5 */
6
7 #include <linux/module.h>
8 #include <linux/stat.h>
9 #include <linux/vmalloc.h>
10 #include <linux/marker.h>
11 #include <linux/uaccess.h>
12 #include <linux/string.h>
13 #include <linux/ctype.h>
14 #include <linux/list.h>
15 #include <linux/mutex.h>
16 #include <linux/seq_file.h>
17 #include <linux/slab.h>
18
19 #include "ltt-tracer.h"
20
21 #define DEFAULT_CHANNEL "cpu"
22 #define DEFAULT_PROBE "default"
23
24 LIST_HEAD(probes_list);
25
26 /*
27 * Mutex protecting the probe slab cache.
28 * Nests inside the traces mutex.
29 */
30 DEFINE_MUTEX(probes_mutex);
31
32 struct ltt_available_probe default_probe = {
33 .name = "default",
34 .format = NULL,
35 .probe_func = ltt_vtrace,
36 .callbacks[0] = ltt_serialize_data,
37 };
38
39 static struct kmem_cache *markers_loaded_cachep;
40 static LIST_HEAD(markers_loaded_list);
41 /*
42 * List sorted by name strcmp order.
43 */
44 static LIST_HEAD(probes_registered_list);
45
46 static struct ltt_available_probe *get_probe_from_name(const char *pname)
47 {
48 struct ltt_available_probe *iter;
49 int comparison, found = 0;
50
51 if (!pname)
52 pname = DEFAULT_PROBE;
53 list_for_each_entry(iter, &probes_registered_list, node) {
54 comparison = strcmp(pname, iter->name);
55 if (!comparison)
56 found = 1;
57 if (comparison <= 0)
58 break;
59 }
60 if (found)
61 return iter;
62 else
63 return NULL;
64 }
65
66 int ltt_probe_register(struct ltt_available_probe *pdata)
67 {
68 int ret = 0;
69 int comparison;
70 struct ltt_available_probe *iter;
71
72 mutex_lock(&probes_mutex);
73 list_for_each_entry_reverse(iter, &probes_registered_list, node) {
74 comparison = strcmp(pdata->name, iter->name);
75 if (!comparison) {
76 ret = -EBUSY;
77 goto end;
78 } else if (comparison > 0) {
79 /* We belong to the location right after iter. */
80 list_add(&pdata->node, &iter->node);
81 goto end;
82 }
83 }
84 /* Should be added at the head of the list */
85 list_add(&pdata->node, &probes_registered_list);
86 end:
87 mutex_unlock(&probes_mutex);
88 return ret;
89 }
90 EXPORT_SYMBOL_GPL(ltt_probe_register);
91
92 /*
93 * Called when a probe does not want to be called anymore.
94 */
95 int ltt_probe_unregister(struct ltt_available_probe *pdata)
96 {
97 int ret = 0;
98 struct ltt_active_marker *amark, *tmp;
99
100 mutex_lock(&probes_mutex);
101 list_for_each_entry_safe(amark, tmp, &markers_loaded_list, node) {
102 if (amark->probe == pdata) {
103 ret = marker_probe_unregister_private_data(
104 pdata->probe_func, amark);
105 if (ret)
106 goto end;
107 list_del(&amark->node);
108 kmem_cache_free(markers_loaded_cachep, amark);
109 }
110 }
111 list_del(&pdata->node);
112 end:
113 mutex_unlock(&probes_mutex);
114 return ret;
115 }
116 EXPORT_SYMBOL_GPL(ltt_probe_unregister);
117
118 /*
119 * Connect marker "mname" to probe "pname".
120 * Only allow _only_ probe instance to be connected to a marker.
121 */
122 int ltt_marker_connect(const char *channel, const char *mname,
123 const char *pname)
124 {
125 int ret;
126 struct ltt_active_marker *pdata;
127 struct ltt_available_probe *probe;
128
129 ltt_lock_traces();
130 mutex_lock(&probes_mutex);
131 probe = get_probe_from_name(pname);
132 if (!probe) {
133 ret = -ENOENT;
134 goto end;
135 }
136 pdata = marker_get_private_data(channel, mname, probe->probe_func, 0);
137 if (pdata && !IS_ERR(pdata)) {
138 ret = -EEXIST;
139 goto end;
140 }
141 pdata = kmem_cache_zalloc(markers_loaded_cachep, GFP_KERNEL);
142 if (!pdata) {
143 ret = -ENOMEM;
144 goto end;
145 }
146 pdata->probe = probe;
147 /*
148 * ID has priority over channel in case of conflict.
149 */
150 ret = marker_probe_register(channel, mname, NULL,
151 probe->probe_func, pdata);
152 if (ret)
153 kmem_cache_free(markers_loaded_cachep, pdata);
154 else
155 list_add(&pdata->node, &markers_loaded_list);
156 end:
157 mutex_unlock(&probes_mutex);
158 ltt_unlock_traces();
159 return ret;
160 }
161 EXPORT_SYMBOL_GPL(ltt_marker_connect);
162
163 /*
164 * Disconnect marker "mname", probe "pname".
165 */
166 int ltt_marker_disconnect(const char *channel, const char *mname,
167 const char *pname)
168 {
169 struct ltt_active_marker *pdata;
170 struct ltt_available_probe *probe;
171 int ret = 0;
172
173 mutex_lock(&probes_mutex);
174 probe = get_probe_from_name(pname);
175 if (!probe) {
176 ret = -ENOENT;
177 goto end;
178 }
179 pdata = marker_get_private_data(channel, mname, probe->probe_func, 0);
180 if (IS_ERR(pdata)) {
181 ret = PTR_ERR(pdata);
182 goto end;
183 } else if (!pdata) {
184 /*
185 * Not registered by us.
186 */
187 ret = -EPERM;
188 goto end;
189 }
190 ret = marker_probe_unregister(channel, mname, probe->probe_func, pdata);
191 if (ret)
192 goto end;
193 else {
194 list_del(&pdata->node);
195 kmem_cache_free(markers_loaded_cachep, pdata);
196 }
197 end:
198 mutex_unlock(&probes_mutex);
199 return ret;
200 }
201 EXPORT_SYMBOL_GPL(ltt_marker_disconnect);
202
203 static void disconnect_all_markers(void)
204 {
205 struct ltt_active_marker *pdata, *tmp;
206
207 list_for_each_entry_safe(pdata, tmp, &markers_loaded_list, node) {
208 marker_probe_unregister_private_data(pdata->probe->probe_func,
209 pdata);
210 list_del(&pdata->node);
211 kmem_cache_free(markers_loaded_cachep, pdata);
212 }
213 }
214
215 static int __init marker_control_init(void)
216 {
217 int ret;
218
219 markers_loaded_cachep = KMEM_CACHE(ltt_active_marker, 0);
220
221 ret = ltt_probe_register(&default_probe);
222 BUG_ON(ret);
223 ret = ltt_marker_connect("metadata", "core_marker_format",
224 DEFAULT_PROBE);
225 BUG_ON(ret);
226 ret = ltt_marker_connect("metadata", "core_marker_id", DEFAULT_PROBE);
227 BUG_ON(ret);
228
229 return 0;
230 }
231 module_init(marker_control_init);
232
233 static void __exit marker_control_exit(void)
234 {
235 int ret;
236
237 ret = ltt_marker_disconnect("metadata", "core_marker_format",
238 DEFAULT_PROBE);
239 BUG_ON(ret);
240 ret = ltt_marker_disconnect("metadata", "core_marker_id",
241 DEFAULT_PROBE);
242 BUG_ON(ret);
243 ret = ltt_probe_unregister(&default_probe);
244 BUG_ON(ret);
245 disconnect_all_markers();
246 kmem_cache_destroy(markers_loaded_cachep);
247 marker_synchronize_unregister();
248 }
249 module_exit(marker_control_exit);
250
251 MODULE_LICENSE("GPL and additional rights");
252 MODULE_AUTHOR("Mathieu Desnoyers");
253 MODULE_DESCRIPTION("Linux Trace Toolkit Marker Control");
This page took 0.033521 seconds and 4 git commands to generate.