1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/module.h>
19#include <linux/mutex.h>
20#include <linux/types.h>
21#include <linux/jhash.h>
22#include <linux/list.h>
23#include <linux/rcupdate.h>
24#include <linux/marker.h>
25#include <linux/err.h>
26
27extern struct marker __start___markers[];
28extern struct marker __stop___markers[];
29
30
31
32
33
34static DEFINE_MUTEX(markers_mutex);
35
36
37
38
39
40
41
42
43
44static int deferred_sync;
45
46
47
48
49
50#define MARKER_HASH_BITS 6
51#define MARKER_TABLE_SIZE (1 << MARKER_HASH_BITS)
52
53struct marker_entry {
54 struct hlist_node hlist;
55 char *format;
56 marker_probe_func *probe;
57 void *private;
58 int refcount;
59 char name[0];
60};
61
62static struct hlist_head marker_table[MARKER_TABLE_SIZE];
63
64
65
66
67
68
69
70
71
72
73
74
75void __mark_empty_function(const struct marker *mdata, void *private,
76 const char *fmt, ...)
77{
78}
79EXPORT_SYMBOL_GPL(__mark_empty_function);
80
81
82
83
84
85
86static struct marker_entry *get_marker(const char *name)
87{
88 struct hlist_head *head;
89 struct hlist_node *node;
90 struct marker_entry *e;
91 u32 hash = jhash(name, strlen(name), 0);
92
93 head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)];
94 hlist_for_each_entry(e, node, head, hlist) {
95 if (!strcmp(name, e->name))
96 return e;
97 }
98 return NULL;
99}
100
101
102
103
104
105static int add_marker(const char *name, const char *format,
106 marker_probe_func *probe, void *private)
107{
108 struct hlist_head *head;
109 struct hlist_node *node;
110 struct marker_entry *e;
111 size_t name_len = strlen(name) + 1;
112 size_t format_len = 0;
113 u32 hash = jhash(name, name_len-1, 0);
114
115 if (format)
116 format_len = strlen(format) + 1;
117 head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)];
118 hlist_for_each_entry(e, node, head, hlist) {
119 if (!strcmp(name, e->name)) {
120 printk(KERN_NOTICE
121 "Marker %s busy, probe %p already installed\n",
122 name, e->probe);
123 return -EBUSY;
124 }
125 }
126
127
128
129
130 e = kmalloc(sizeof(struct marker_entry) + name_len + format_len,
131 GFP_KERNEL);
132 if (!e)
133 return -ENOMEM;
134 memcpy(&e->name[0], name, name_len);
135 if (format) {
136 e->format = &e->name[name_len];
137 memcpy(e->format, format, format_len);
138 trace_mark(core_marker_format, "name %s format %s",
139 e->name, e->format);
140 } else
141 e->format = NULL;
142 e->probe = probe;
143 e->private = private;
144 e->refcount = 0;
145 hlist_add_head(&e->hlist, head);
146 return 0;
147}
148
149
150
151
152
153static void *remove_marker(const char *name)
154{
155 struct hlist_head *head;
156 struct hlist_node *node;
157 struct marker_entry *e;
158 int found = 0;
159 size_t len = strlen(name) + 1;
160 void *private = NULL;
161 u32 hash = jhash(name, len-1, 0);
162
163 head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)];
164 hlist_for_each_entry(e, node, head, hlist) {
165 if (!strcmp(name, e->name)) {
166 found = 1;
167 break;
168 }
169 }
170 if (found) {
171 private = e->private;
172 hlist_del(&e->hlist);
173 kfree(e);
174 }
175 return private;
176}
177
178
179
180
181static int marker_set_format(struct marker_entry **entry, const char *format)
182{
183 struct marker_entry *e;
184 size_t name_len = strlen((*entry)->name) + 1;
185 size_t format_len = strlen(format) + 1;
186
187 e = kmalloc(sizeof(struct marker_entry) + name_len + format_len,
188 GFP_KERNEL);
189 if (!e)
190 return -ENOMEM;
191 memcpy(&e->name[0], (*entry)->name, name_len);
192 e->format = &e->name[name_len];
193 memcpy(e->format, format, format_len);
194 e->probe = (*entry)->probe;
195 e->private = (*entry)->private;
196 e->refcount = (*entry)->refcount;
197 hlist_add_before(&e->hlist, &(*entry)->hlist);
198 hlist_del(&(*entry)->hlist);
199 kfree(*entry);
200 *entry = e;
201 trace_mark(core_marker_format, "name %s format %s",
202 e->name, e->format);
203 return 0;
204}
205
206
207
208
209static int set_marker(struct marker_entry **entry, struct marker *elem)
210{
211 int ret;
212 WARN_ON(strcmp((*entry)->name, elem->name) != 0);
213
214 if ((*entry)->format) {
215 if (strcmp((*entry)->format, elem->format) != 0) {
216 printk(KERN_NOTICE
217 "Format mismatch for probe %s "
218 "(%s), marker (%s)\n",
219 (*entry)->name,
220 (*entry)->format,
221 elem->format);
222 return -EPERM;
223 }
224 } else {
225 ret = marker_set_format(entry, elem->format);
226 if (ret)
227 return ret;
228 }
229 elem->call = (*entry)->probe;
230 elem->private = (*entry)->private;
231 elem->state = 1;
232 return 0;
233}
234
235
236
237
238
239
240
241static void disable_marker(struct marker *elem)
242{
243 elem->state = 0;
244 elem->call = __mark_empty_function;
245
246
247
248
249
250}
251
252
253
254
255
256
257
258
259
260
261void marker_update_probe_range(struct marker *begin,
262 struct marker *end, struct module *probe_module,
263 int *refcount)
264{
265 struct marker *iter;
266 struct marker_entry *mark_entry;
267
268 mutex_lock(&markers_mutex);
269 for (iter = begin; iter < end; iter++) {
270 mark_entry = get_marker(iter->name);
271 if (mark_entry && mark_entry->refcount) {
272 set_marker(&mark_entry, iter);
273
274
275
276 if (probe_module)
277 if (probe_module ==
278 __module_text_address((unsigned long)mark_entry->probe))
279 (*refcount)++;
280 } else {
281 disable_marker(iter);
282 }
283 }
284 mutex_unlock(&markers_mutex);
285}
286
287
288
289
290
291
292
293static void marker_update_probes(struct module *probe_module)
294{
295 int refcount = 0;
296
297
298 marker_update_probe_range(__start___markers,
299 __stop___markers, probe_module, &refcount);
300
301 module_update_markers(probe_module, &refcount);
302 if (probe_module && refcount == 0) {
303 synchronize_sched();
304 deferred_sync = 0;
305 }
306}
307
308
309
310
311
312
313
314
315
316
317
318int marker_probe_register(const char *name, const char *format,
319 marker_probe_func *probe, void *private)
320{
321 struct marker_entry *entry;
322 int ret = 0;
323
324 mutex_lock(&markers_mutex);
325 entry = get_marker(name);
326 if (entry && entry->refcount) {
327 ret = -EBUSY;
328 goto end;
329 }
330 if (deferred_sync) {
331 synchronize_sched();
332 deferred_sync = 0;
333 }
334 ret = add_marker(name, format, probe, private);
335 if (ret)
336 goto end;
337 mutex_unlock(&markers_mutex);
338 marker_update_probes(NULL);
339 return ret;
340end:
341 mutex_unlock(&markers_mutex);
342 return ret;
343}
344EXPORT_SYMBOL_GPL(marker_probe_register);
345
346
347
348
349
350
351
352void *marker_probe_unregister(const char *name)
353{
354 struct module *probe_module;
355 struct marker_entry *entry;
356 void *private;
357
358 mutex_lock(&markers_mutex);
359 entry = get_marker(name);
360 if (!entry) {
361 private = ERR_PTR(-ENOENT);
362 goto end;
363 }
364 entry->refcount = 0;
365
366 probe_module = __module_text_address((unsigned long)entry->probe);
367 private = remove_marker(name);
368 deferred_sync = 1;
369 mutex_unlock(&markers_mutex);
370 marker_update_probes(probe_module);
371 return private;
372end:
373 mutex_unlock(&markers_mutex);
374 return private;
375}
376EXPORT_SYMBOL_GPL(marker_probe_unregister);
377
378
379
380
381
382
383
384
385void *marker_probe_unregister_private_data(void *private)
386{
387 struct module *probe_module;
388 struct hlist_head *head;
389 struct hlist_node *node;
390 struct marker_entry *entry;
391 int found = 0;
392 unsigned int i;
393
394 mutex_lock(&markers_mutex);
395 for (i = 0; i < MARKER_TABLE_SIZE; i++) {
396 head = &marker_table[i];
397 hlist_for_each_entry(entry, node, head, hlist) {
398 if (entry->private == private) {
399 found = 1;
400 goto iter_end;
401 }
402 }
403 }
404iter_end:
405 if (!found) {
406 private = ERR_PTR(-ENOENT);
407 goto end;
408 }
409 entry->refcount = 0;
410
411 probe_module = __module_text_address((unsigned long)entry->probe);
412 private = remove_marker(entry->name);
413 deferred_sync = 1;
414 mutex_unlock(&markers_mutex);
415 marker_update_probes(probe_module);
416 return private;
417end:
418 mutex_unlock(&markers_mutex);
419 return private;
420}
421EXPORT_SYMBOL_GPL(marker_probe_unregister_private_data);
422
423
424
425
426
427
428
429
430
431int marker_arm(const char *name)
432{
433 struct marker_entry *entry;
434 int ret = 0;
435
436 mutex_lock(&markers_mutex);
437 entry = get_marker(name);
438 if (!entry) {
439 ret = -ENOENT;
440 goto end;
441 }
442
443
444
445 if (entry->refcount++)
446 goto end;
447end:
448 mutex_unlock(&markers_mutex);
449 marker_update_probes(NULL);
450 return ret;
451}
452EXPORT_SYMBOL_GPL(marker_arm);
453
454
455
456
457
458
459
460
461
462int marker_disarm(const char *name)
463{
464 struct marker_entry *entry;
465 int ret = 0;
466
467 mutex_lock(&markers_mutex);
468 entry = get_marker(name);
469 if (!entry) {
470 ret = -ENOENT;
471 goto end;
472 }
473
474
475
476
477 if (entry->refcount) {
478 if (--entry->refcount)
479 goto end;
480 } else {
481 ret = -EPERM;
482 goto end;
483 }
484end:
485 mutex_unlock(&markers_mutex);
486 marker_update_probes(NULL);
487 return ret;
488}
489EXPORT_SYMBOL_GPL(marker_disarm);
490
491
492
493
494
495
496
497
498
499
500void *marker_get_private_data(const char *name)
501{
502 struct hlist_head *head;
503 struct hlist_node *node;
504 struct marker_entry *e;
505 size_t name_len = strlen(name) + 1;
506 u32 hash = jhash(name, name_len-1, 0);
507 int found = 0;
508
509 head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)];
510 hlist_for_each_entry(e, node, head, hlist) {
511 if (!strcmp(name, e->name)) {
512 found = 1;
513 return e->private;
514 }
515 }
516 return ERR_PTR(-ENOENT);
517}
518EXPORT_SYMBOL_GPL(marker_get_private_data);
519