Merge tag 'v3.14.25' into backport/v3.14.24-ltsi-rc1+v3.14.25/snapshot-merge.wip
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / staging / lttng / lttng-probes.c
1 /*
2  * lttng-probes.c
3  *
4  * Holds LTTng probes registry.
5  *
6  * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; only
11  * version 2.1 of the License.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 #include <linux/module.h>
24 #include <linux/list.h>
25 #include <linux/mutex.h>
26 #include <linux/seq_file.h>
27
28 #include "lttng-events.h"
29
30 static LIST_HEAD(probe_list);
31 static DEFINE_MUTEX(probe_mutex);
32
33 static
34 const struct lttng_event_desc *find_event(const char *name)
35 {
36         struct lttng_probe_desc *probe_desc;
37         int i;
38
39         list_for_each_entry(probe_desc, &probe_list, head) {
40                 for (i = 0; i < probe_desc->nr_events; i++) {
41                         if (!strcmp(probe_desc->event_desc[i]->name, name))
42                                 return probe_desc->event_desc[i];
43                 }
44         }
45         return NULL;
46 }
47
48 int lttng_probe_register(struct lttng_probe_desc *desc)
49 {
50         int ret = 0;
51         int i;
52
53         mutex_lock(&probe_mutex);
54         /*
55          * TODO: This is O(N^2). Turn into a hash table when probe registration
56          * overhead becomes an issue.
57          */
58         for (i = 0; i < desc->nr_events; i++) {
59                 if (find_event(desc->event_desc[i]->name)) {
60                         ret = -EEXIST;
61                         goto end;
62                 }
63         }
64         list_add(&desc->head, &probe_list);
65 end:
66         mutex_unlock(&probe_mutex);
67         return ret;
68 }
69 EXPORT_SYMBOL_GPL(lttng_probe_register);
70
71 void lttng_probe_unregister(struct lttng_probe_desc *desc)
72 {
73         mutex_lock(&probe_mutex);
74         list_del(&desc->head);
75         mutex_unlock(&probe_mutex);
76 }
77 EXPORT_SYMBOL_GPL(lttng_probe_unregister);
78
79 const struct lttng_event_desc *lttng_event_get(const char *name)
80 {
81         const struct lttng_event_desc *event;
82         int ret;
83
84         mutex_lock(&probe_mutex);
85         event = find_event(name);
86         mutex_unlock(&probe_mutex);
87         if (!event)
88                 return NULL;
89         ret = try_module_get(event->owner);
90         WARN_ON_ONCE(!ret);
91         return event;
92 }
93 EXPORT_SYMBOL_GPL(lttng_event_get);
94
95 void lttng_event_put(const struct lttng_event_desc *event)
96 {
97         module_put(event->owner);
98 }
99 EXPORT_SYMBOL_GPL(lttng_event_put);
100
101 static
102 void *tp_list_start(struct seq_file *m, loff_t *pos)
103 {
104         struct lttng_probe_desc *probe_desc;
105         int iter = 0, i;
106
107         mutex_lock(&probe_mutex);
108         list_for_each_entry(probe_desc, &probe_list, head) {
109                 for (i = 0; i < probe_desc->nr_events; i++) {
110                         if (iter++ >= *pos)
111                                 return (void *) probe_desc->event_desc[i];
112                 }
113         }
114         /* End of list */
115         return NULL;
116 }
117
118 static
119 void *tp_list_next(struct seq_file *m, void *p, loff_t *ppos)
120 {
121         struct lttng_probe_desc *probe_desc;
122         int iter = 0, i;
123
124         (*ppos)++;
125         list_for_each_entry(probe_desc, &probe_list, head) {
126                 for (i = 0; i < probe_desc->nr_events; i++) {
127                         if (iter++ >= *ppos)
128                                 return (void *) probe_desc->event_desc[i];
129                 }
130         }
131         /* End of list */
132         return NULL;
133 }
134
135 static
136 void tp_list_stop(struct seq_file *m, void *p)
137 {
138         mutex_unlock(&probe_mutex);
139 }
140
141 static
142 int tp_list_show(struct seq_file *m, void *p)
143 {
144         const struct lttng_event_desc *probe_desc = p;
145
146         seq_printf(m,   "event { name = %s; };\n",
147                    probe_desc->name);
148         return 0;
149 }
150
151 static
152 const struct seq_operations lttng_tracepoint_list_seq_ops = {
153         .start = tp_list_start,
154         .next = tp_list_next,
155         .stop = tp_list_stop,
156         .show = tp_list_show,
157 };
158
159 static
160 int lttng_tracepoint_list_open(struct inode *inode, struct file *file)
161 {
162         return seq_open(file, &lttng_tracepoint_list_seq_ops);
163 }
164
165 const struct file_operations lttng_tracepoint_list_fops = {
166         .owner = THIS_MODULE,
167         .open = lttng_tracepoint_list_open,
168         .read = seq_read,
169         .llseek = seq_lseek,
170         .release = seq_release,
171 };