lttng-modules v0.19-stable: setup_trace_write: Fix recursive locking
[lttng-modules.git] / 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 {
126 int ret;
127 struct ltt_active_marker *pdata;
128 struct ltt_available_probe *probe;
129
130 ltt_lock_traces();
131 mutex_lock(&probes_mutex);
132 probe = get_probe_from_name(pname);
133 if (!probe) {
134 ret = -ENOENT;
135 goto end;
136 }
137 pdata = marker_get_private_data(channel, mname, probe->probe_func, 0);
138 if (pdata && !IS_ERR(pdata)) {
139 ret = -EEXIST;
140 goto end;
141 }
142 pdata = kmem_cache_zalloc(markers_loaded_cachep, GFP_KERNEL);
143 if (!pdata) {
144 ret = -ENOMEM;
145 goto end;
146 }
147 pdata->probe = probe;
148 /*
149 * ID has priority over channel in case of conflict.
150 */
151 ret = marker_probe_register(channel, mname, NULL,
152 probe->probe_func, pdata);
153 if (ret)
154 kmem_cache_free(markers_loaded_cachep, pdata);
155 else
156 list_add(&pdata->node, &markers_loaded_list);
157 end:
158 mutex_unlock(&probes_mutex);
159 ltt_unlock_traces();
160 return ret;
161 }
162 EXPORT_SYMBOL_GPL(ltt_marker_connect);
163
164 /*
165 * Disconnect marker "mname", probe "pname".
166 */
167 int ltt_marker_disconnect(const char *channel, const char *mname,
168 const char *pname)
169 {
170 struct ltt_active_marker *pdata;
171 struct ltt_available_probe *probe;
172 int ret = 0;
173
174 mutex_lock(&probes_mutex);
175 probe = get_probe_from_name(pname);
176 if (!probe) {
177 ret = -ENOENT;
178 goto end;
179 }
180 pdata = marker_get_private_data(channel, mname, probe->probe_func, 0);
181 if (IS_ERR(pdata)) {
182 ret = PTR_ERR(pdata);
183 goto end;
184 } else if (!pdata) {
185 /*
186 * Not registered by us.
187 */
188 ret = -EPERM;
189 goto end;
190 }
191 ret = marker_probe_unregister(channel, mname, probe->probe_func, pdata);
192 if (ret)
193 goto end;
194 else {
195 list_del(&pdata->node);
196 kmem_cache_free(markers_loaded_cachep, pdata);
197 }
198 end:
199 mutex_unlock(&probes_mutex);
200 return ret;
201 }
202 EXPORT_SYMBOL_GPL(ltt_marker_disconnect);
203
204 static void disconnect_all_markers(void)
205 {
206 struct ltt_active_marker *pdata, *tmp;
207
208 list_for_each_entry_safe(pdata, tmp, &markers_loaded_list, node) {
209 marker_probe_unregister_private_data(pdata->probe->probe_func,
210 pdata);
211 list_del(&pdata->node);
212 kmem_cache_free(markers_loaded_cachep, pdata);
213 }
214 }
215
216 static int __init marker_control_init(void)
217 {
218 int ret;
219
220 markers_loaded_cachep = KMEM_CACHE(ltt_active_marker, 0);
221
222 ret = ltt_probe_register(&default_probe);
223 BUG_ON(ret);
224 ret = ltt_marker_connect("metadata", "core_marker_format",
225 DEFAULT_PROBE);
226 BUG_ON(ret);
227 ret = ltt_marker_connect("metadata", "core_marker_id", DEFAULT_PROBE);
228 BUG_ON(ret);
229
230 return 0;
231 }
232 module_init(marker_control_init);
233
234 static void __exit marker_control_exit(void)
235 {
236 int ret;
237
238 ret = ltt_marker_disconnect("metadata", "core_marker_format",
239 DEFAULT_PROBE);
240 BUG_ON(ret);
241 ret = ltt_marker_disconnect("metadata", "core_marker_id",
242 DEFAULT_PROBE);
243 BUG_ON(ret);
244 ret = ltt_probe_unregister(&default_probe);
245 BUG_ON(ret);
246 disconnect_all_markers();
247 kmem_cache_destroy(markers_loaded_cachep);
248 marker_synchronize_unregister();
249 }
250 module_exit(marker_control_exit);
251
252 MODULE_LICENSE("GPL and additional rights");
253 MODULE_AUTHOR("Mathieu Desnoyers");
254 MODULE_DESCRIPTION("Linux Trace Toolkit Marker Control");
This page took 0.034054 seconds and 4 git commands to generate.