tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / kernel / swap / us_manager / probes / probes.c
1 /*
2  *  SWAP uprobe manager
3  *  modules/us_manager/probes/probes.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Copyright (C) Samsung Electronics, 2014
20  *
21  * 2014  Alexander Aksenov: Probes interface implement
22  *
23  */
24
25 #include "probes.h"
26 #include "register_probes.h"
27 #include "use_probes.h"
28
29 #include <linux/slab.h>
30 #include <linux/kernel.h>
31 #include <linux/errno.h>
32 #include <linux/module.h>
33
34
35 struct probe_info *probe_info_malloc(size_t size, enum probe_t type)
36 {
37         struct probe_info *info;
38
39         info = kmalloc(sizeof(*info) + size, GFP_ATOMIC);
40         if (info) {
41                 info->probe_type = type;
42                 info->size = size;
43         }
44
45         return info;
46 }
47 EXPORT_SYMBOL_GPL(probe_info_malloc);
48
49 struct probe_info *probe_info_dup(const struct probe_info *info)
50 {
51         struct probe_info *info_new;
52         size_t size = info->size;
53
54         info_new = probe_info_malloc(size, info->probe_type);
55         if (info_new && size)
56                 memcpy(info_new->data, info->data, size);
57
58         return info_new;
59 }
60 EXPORT_SYMBOL_GPL(probe_info_dup);
61
62 void probe_info_free(struct probe_info *info)
63 {
64         kfree(info);
65 }
66 EXPORT_SYMBOL_GPL(probe_info_free);
67
68
69 static struct probe_iface *probes_methods[SWAP_PROBE_MAX_VAL] = { NULL };
70
71 /* 1 - correct probe type
72    0 - wrong probe type
73 */
74 static inline int correct_probe_type(enum probe_t probe_type)
75 {
76         if (probe_type >= SWAP_PROBE_MAX_VAL)
77                 return 0;
78
79         return 1;
80 }
81
82 static inline int methods_exist(enum probe_t probe_type)
83 {
84         if (!correct_probe_type(probe_type))
85                 return 0;
86
87         if (probes_methods[probe_type] == NULL)
88                 return 0;
89
90         return 1;
91 }
92
93 /**
94  * @brief Calls specified probe type init method.
95  *
96  * @param pi Pointer to the probe_info.
97  * @param ip Pointer to the probe us_ip struct.
98  * @return Void.
99  */
100 void probe_info_init(struct probe_info *pi, struct us_ip *ip)
101 {
102         enum probe_t probe_type = pi->probe_type;
103
104         if (!methods_exist(probe_type)) {
105                 printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
106                 return;
107         }
108
109         probes_methods[probe_type]->init(ip);
110 }
111
112 /**
113  * @brief Calls specified probe type uninit method.
114  *
115  * @param pi Pointer to the probe_info.
116  * @param ip Pointer to the probe us_ip struct.
117  * @return Void.
118  */
119 void probe_info_uninit(struct probe_info *pi, struct us_ip *ip)
120 {
121         enum probe_t probe_type = pi->probe_type;
122
123         if (!methods_exist(probe_type)) {
124                 printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
125                 return;
126         }
127
128         probes_methods[probe_type]->uninit(ip);
129 }
130
131 /**
132  * @brief Calls specified probe type register method.
133  *
134  * @param pi Pointer to the probe_info.
135  * @param ip Pointer to the probe us_ip struct.
136  * @return -EINVAL on wrong probe type, method result otherwise.
137  */
138 int probe_info_register(struct probe_info *pi, struct us_ip *ip)
139 {
140         enum probe_t probe_type = pi->probe_type;
141
142         if (!methods_exist(probe_type)) {
143                 printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
144                 return -EINVAL;
145         }
146
147         return probes_methods[probe_type]->reg(ip);
148 }
149
150 /**
151  * @brief Calls specified probe type unregister method.
152  *
153  * @param pi Pointer to the probe_info.
154  * @param ip Pointer to the probe us_ip struct.
155  * @param disarm Disarm flag.
156  * @return Void.
157  */
158 void probe_info_unregister(struct probe_info *pi, struct us_ip *ip, int disarm)
159 {
160         enum probe_t probe_type = pi->probe_type;
161
162         if (!methods_exist(probe_type)) {
163                 printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
164                 return;
165         }
166
167         probes_methods[probe_type]->unreg(ip, disarm);
168 }
169
170 /**
171  * @brief Calls specified probe type get underlying uprobe method.
172  *
173  * @param pi Pointer to the probe_info.
174  * @param ip Pointer to the probe us_ip struct.
175  * @return Pointer to the uprobe struct, NULL on error.
176  */
177 struct uprobe *probe_info_get_uprobe(struct probe_info *pi, struct us_ip *ip)
178 {
179         enum probe_t probe_type = pi->probe_type;
180
181         if (!methods_exist(probe_type)) {
182                 printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
183                 return NULL;
184         }
185
186         return probes_methods[probe_type]->get_uprobe(ip);
187 }
188
189 /**
190  * @brief Calls specified probe type copy method.
191  *
192  * @param pi Pointer to the source probe_info.
193  * @param dest Pointer to the probe us_ip struct.
194  * @return -EINVAL on error, method result otherwise.
195  */
196 int probe_info_copy(const struct probe_info *pi, struct probe_info *dest)
197 {
198         enum probe_t probe_type = pi->probe_type;
199
200         if (!methods_exist(probe_type)) {
201                 printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
202                 return -EINVAL;
203         }
204
205         return probes_methods[probe_type]->copy(dest, pi);
206 }
207
208 /**
209  * @brief Calls specified probe type cleanup method.
210  *
211  * @param pi Pointer to the source probe_info.
212  * @return Void.
213  */
214 void probe_info_cleanup(struct probe_info *pi)
215 {
216         enum probe_t probe_type = pi->probe_type;
217
218         if (!methods_exist(probe_type)) {
219                 printk(KERN_WARNING "SWAP US_MANAGER: Wrong probe type!\n");
220                 return;
221         }
222
223         probes_methods[probe_type]->cleanup(pi);
224 }
225
226 /**
227  * @brief Registers probe type.
228  *
229  * @param probe_type Number, associated with this probe type.
230  * @param pi Pointer to the probe interface structure
231  * @return 0 on succes, error code on error.
232  */
233 int swap_register_probe_type(enum probe_t probe_type, struct probe_iface *pi)
234 {
235         if (!correct_probe_type(probe_type)) {
236                 printk(KERN_ERR "SWAP US_MANAGER: Wrong probe type!\n");
237                 return -EINVAL;
238         }
239
240         if (probes_methods[probe_type] != NULL)
241                 printk(KERN_WARNING "SWAP US_MANAGER: Re-registering probe %d\n",
242                    probe_type);
243
244         probes_methods[probe_type] = pi;
245
246         return 0;
247 }
248 EXPORT_SYMBOL_GPL(swap_register_probe_type);
249
250 /**
251  * @brief Unregisters probe type.
252  *
253  * @param probe_type Probe type that should be unregistered.
254  * @return Void.
255  */
256 void swap_unregister_probe_type(enum probe_t probe_type)
257 {
258         if (!correct_probe_type(probe_type)) {
259                 printk(KERN_ERR "SWAP US_MANAGER: Wrong probe type!\n");
260                 return;
261         }
262
263         probes_methods[probe_type] = NULL;
264 }
265 EXPORT_SYMBOL_GPL(swap_unregister_probe_type);