tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / kernel / swap / preload / preload_control.c
1 #include <linux/mm.h>
2 #include <linux/slab.h>
3 #include <linux/mutex.h>
4 #include <linux/limits.h>
5
6 #include <us_manager/sspt/ip.h>
7
8 #include "preload.h"
9
10 #include "preload_control.h"
11 #include "preload_probe.h"
12 #include "preload_module.h"
13
14
15 #define DEFAULT_SLOTS_COUNT 5
16 #define DEFAULT_SLOTS_STEP 2
17
18 struct bin_desc {
19         struct dentry *dentry;
20         char *filename;
21 };
22
23 static struct bin_desc *target_binaries = NULL;
24 static unsigned int target_binaries_cnt = 0;
25 static unsigned int target_binaries_slots = 0;
26
27 static DEFINE_MUTEX(__target_binaries_mutex);
28
29
30 static inline void __target_binaries_lock(void)
31 {
32         mutex_lock(&__target_binaries_mutex);
33 }
34
35 static inline void __target_binaries_unlock(void)
36 {
37         mutex_unlock(&__target_binaries_mutex);
38 }
39
40 static inline struct task_struct *__get_task_struct(void)
41 {
42         return current;
43 }
44
45 static int __alloc_target_binaries_no_lock(unsigned int cnt)
46 {
47         target_binaries = kmalloc(sizeof(*target_binaries) * cnt, GFP_KERNEL);
48         if (target_binaries == NULL)
49                 return -ENOMEM;
50
51         target_binaries_slots = cnt;
52
53         return 0;
54 }
55
56 static int __alloc_target_binaries(unsigned int cnt)
57 {
58         int ret;
59
60         __target_binaries_lock();
61         ret = __alloc_target_binaries_no_lock(cnt);
62         __target_binaries_unlock();
63
64         return ret;
65 }
66
67 static void __free_target_binaries(void)
68 {
69         int i;
70
71         __target_binaries_lock();
72
73         for (i = 0; i < target_binaries_cnt; i++) {
74                 put_dentry(target_binaries[i].dentry);
75                 kfree(target_binaries[i].filename);
76         }
77
78         kfree(target_binaries);
79         target_binaries_cnt = 0;
80         target_binaries_slots = 0;
81
82         __target_binaries_unlock();
83 }
84
85 static int __grow_target_binaries(void)
86 {
87         struct bin_desc *tmp = target_binaries;
88         int i, ret;
89
90         __target_binaries_lock();
91
92         ret = __alloc_target_binaries_no_lock(target_binaries_slots + DEFAULT_SLOTS_STEP);
93         if (ret != 0)
94                 return ret;
95
96         target_binaries_slots += DEFAULT_SLOTS_STEP;
97
98         for (i = 0; i < target_binaries_cnt; i++) {
99                 target_binaries[i].dentry = tmp[i].dentry;
100                 target_binaries[i].filename = tmp[i].filename;
101         }
102
103         __target_binaries_unlock();
104
105         kfree(tmp);
106
107         return 0;
108 }
109
110 static bool __check_dentry_already_exist(struct dentry *dentry)
111 {
112         int i;
113         bool ret = false;
114
115         __target_binaries_lock();
116
117         for (i = 0; i < target_binaries_cnt; i++) {
118                 if (target_binaries[i].dentry == dentry) {
119                         ret = true;
120                         goto check_dentry_unlock;
121                 }
122         }
123
124 check_dentry_unlock:
125         __target_binaries_unlock();
126
127         return ret;
128 }
129
130 static int __add_target_binary(struct dentry *dentry, char *filename)
131 {
132         int ret;
133         size_t len;
134
135         if (__check_dentry_already_exist(dentry)) {
136                 printk(PRELOAD_PREFIX "Binary already exist\n");
137                 return EALREADY;
138         }
139
140
141         if (target_binaries_slots == target_binaries_cnt) {
142                 ret = __grow_target_binaries();
143                 if (ret != 0)
144                         return ret;
145         }
146
147         /* Filename should be < PATH_MAX */
148         len = strnlen(filename, PATH_MAX);
149         if (len == PATH_MAX)
150                 return -EINVAL;
151
152         __target_binaries_lock();
153
154         target_binaries[target_binaries_cnt].dentry = dentry;
155         target_binaries[target_binaries_cnt].filename = kmalloc(len + 1, GFP_KERNEL);
156         memcpy(target_binaries[target_binaries_cnt].filename, filename, len + 1);
157         ++target_binaries_cnt;
158
159         __target_binaries_unlock();
160
161         return 0;
162 }
163
164 static char *__get_binary_name(struct bin_desc *bin)
165 {
166         return bin->filename;
167 }
168
169 static struct dentry *__get_caller_dentry(struct task_struct *task,
170                                           unsigned long caller)
171 {
172         struct vm_area_struct *vma = NULL;
173
174         if (unlikely(task->mm == NULL))
175                 goto get_caller_dentry_fail;
176
177         vma = find_vma_intersection(task->mm, caller, caller + 1);
178         if (unlikely(vma == NULL || vma->vm_file == NULL))
179                 goto get_caller_dentry_fail;
180
181         return vma->vm_file->f_dentry;
182
183 get_caller_dentry_fail:
184
185         return NULL;
186 }
187
188 static bool __check_if_instrumented(struct task_struct *task,
189                                     struct dentry *dentry)
190 {
191         int i;
192
193         for (i = 0; i < target_binaries_cnt; i++)
194                 if (target_binaries[i].dentry == dentry)
195                         return true;
196
197         return false;
198 }
199
200 static bool __is_instrumented(void *caller)
201 {
202         struct task_struct *task = __get_task_struct();
203         struct dentry *caller_dentry = __get_caller_dentry(task,
204                                                            (unsigned long) caller);
205
206         if (caller_dentry == NULL)
207                 return false;
208
209         return __check_if_instrumented(task, caller_dentry);
210 }
211
212
213 /* Called only form handlers. If we're there, then it is instrumented. */
214 enum preload_call_type preload_control_call_type_always_inst(void *caller)
215 {
216         if (__is_instrumented(caller))
217                 return INTERNAL_CALL;
218
219         return EXTERNAL_CALL;
220
221 }
222
223 enum preload_call_type preload_control_call_type(struct us_ip *ip, void *caller)
224 {
225         if (__is_instrumented(caller))
226                 return INTERNAL_CALL;
227
228         if (ip->info->pl_i.flags & SWAP_PRELOAD_ALWAYS_RUN)
229                 return EXTERNAL_CALL;
230
231         return NOT_INSTRUMENTED;
232 }
233
234 int preload_control_add_instrumented_binary(char *filename)
235 {
236         struct dentry *dentry = get_dentry(filename);
237         int res = 0;
238
239         if (dentry == NULL)
240                 return -EINVAL;
241
242         res = __add_target_binary(dentry, filename);
243         if (res != 0)
244                 put_dentry(dentry);
245
246         return res > 0 ? 0 : res;
247 }
248
249 int preload_control_clean_instrumented_bins(void)
250 {
251         __free_target_binaries();
252         return __alloc_target_binaries(DEFAULT_SLOTS_COUNT);
253 }
254
255 unsigned int preload_control_get_bin_names(char ***filenames_p)
256 {
257         int i;
258         unsigned int ret = 0;
259
260         if (target_binaries_cnt == 0)
261                 return 0;
262
263         __target_binaries_lock();
264
265         *filenames_p = kmalloc(sizeof(**filenames_p) * target_binaries_cnt,
266                            GFP_KERNEL);
267         if (*filenames_p == NULL)
268                 goto get_binaries_names_out;
269
270         for (i = 0; i < target_binaries_cnt; i++)
271                 (*filenames_p)[i] = __get_binary_name(&target_binaries[i]);
272
273         ret = target_binaries_cnt;
274
275 get_binaries_names_out:
276         __target_binaries_unlock();
277
278         return ret;
279 }
280
281 void preload_control_release_bin_names(char ***filenames_p)
282 {
283         kfree(*filenames_p);
284 }
285
286 int preload_control_init(void)
287 {
288         return __alloc_target_binaries(DEFAULT_SLOTS_COUNT);
289 }
290
291 void preload_control_exit(void)
292 {
293         __free_target_binaries();
294 }
295
296 #undef DEFAULT_SLOTS_STEP
297 #undef DEFAULT_SLOTS_COUNT