Update licensing info
[lttng-modules.git] / deprecated / ltt-marker-control.c
CommitLineData
1c8284eb
MD
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
24LIST_HEAD(probes_list);
25
26/*
27 * Mutex protecting the probe slab cache.
28 * Nests inside the traces mutex.
29 */
30DEFINE_MUTEX(probes_mutex);
31
32struct ltt_available_probe default_probe = {
33 .name = "default",
34 .format = NULL,
35 .probe_func = ltt_vtrace,
36 .callbacks[0] = ltt_serialize_data,
37};
38
39static struct kmem_cache *markers_loaded_cachep;
40static LIST_HEAD(markers_loaded_list);
41/*
42 * List sorted by name strcmp order.
43 */
44static LIST_HEAD(probes_registered_list);
45
46static 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
66int 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);
86end:
87 mutex_unlock(&probes_mutex);
88 return ret;
89}
90EXPORT_SYMBOL_GPL(ltt_probe_register);
91
92/*
93 * Called when a probe does not want to be called anymore.
94 */
95int 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);
112end:
113 mutex_unlock(&probes_mutex);
114 return ret;
115}
116EXPORT_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 */
122int ltt_marker_connect(const char *channel, const char *mname,
123 const char *pname)
1c8284eb
MD
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);
156end:
157 mutex_unlock(&probes_mutex);
158 ltt_unlock_traces();
159 return ret;
160}
161EXPORT_SYMBOL_GPL(ltt_marker_connect);
162
163/*
164 * Disconnect marker "mname", probe "pname".
165 */
166int 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 }
197end:
198 mutex_unlock(&probes_mutex);
199 return ret;
200}
201EXPORT_SYMBOL_GPL(ltt_marker_disconnect);
202
203static 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
215static 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}
231module_init(marker_control_init);
232
233static 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}
249module_exit(marker_control_exit);
250
251MODULE_LICENSE("GPL and additional rights");
252MODULE_AUTHOR("Mathieu Desnoyers");
253MODULE_DESCRIPTION("Linux Trace Toolkit Marker Control");
This page took 0.031063 seconds and 4 git commands to generate.