[FIX] race condition, when stopped US instrumentation
[kernel/swap-modules.git] / us_manager / pf / pf_group.c
1 /*
2  *  SWAP uprobe manager
3  *  modules/us_manager/pf/pf_group.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, 2013
20  *
21  * 2013  Vyacheslav Cherkashin: SWAP us_manager implement
22  *
23  */
24
25
26 #include <linux/module.h>
27 #include <linux/slab.h>
28 #include <linux/list.h>
29 #include "proc_filters.h"
30 #include <us_manager/img/img_proc.h>
31 #include <us_manager/img/img_file.h>
32 #include <us_manager/img/img_ip.h>
33 #include <us_manager/sspt/sspt_proc.h>
34 #include <us_manager/helper.h>
35 #include <writer/swap_writer_module.h>
36
37 struct pf_group {
38         struct list_head list;
39         struct img_proc *i_proc;
40         struct proc_filter *filter;
41
42         /* TODO: proc_list*/
43         struct list_head proc_list;
44 };
45
46 struct pl_struct {
47         struct list_head list;
48         struct sspt_proc *proc;
49 };
50
51 static LIST_HEAD(pfg_list);
52
53 /* struct pl_struct */
54 static struct pl_struct *create_pl_struct(struct sspt_proc *proc)
55 {
56         struct pl_struct *pls = kmalloc(sizeof(*pls), GFP_KERNEL);
57
58         INIT_LIST_HEAD(&pls->list);
59         pls->proc = proc;
60
61         return pls;
62 }
63
64 static void free_pl_struct(struct pl_struct *pls)
65 {
66         kfree(pls);
67 }
68
69 static void add_pl_struct(struct pf_group *pfg, struct pl_struct *pls)
70 {
71         list_add(&pls->list, &pfg->proc_list);
72 }
73
74 static void del_pl_struct(struct pl_struct *pls)
75 {
76         list_del(&pls->list);
77 }
78
79 void copy_proc_form_img_to_sspt(struct img_proc *i_proc, struct sspt_proc *proc)
80 {
81         struct sspt_file *file;
82         struct img_file *i_file;
83         struct img_ip *i_ip;
84
85         list_for_each_entry(i_file, &i_proc->file_list, list) {
86                 file = sspt_proc_find_file_or_new(proc, i_file->dentry);
87
88                 list_for_each_entry(i_ip, &i_file->ip_list, list)
89                         sspt_file_add_ip(file, i_ip->addr, i_ip->args,
90                                          i_ip->ret_type);
91         }
92 }
93
94 static struct pl_struct *find_pl_struct(struct pf_group *pfg,
95                                         struct task_struct *task)
96 {
97         struct pl_struct *pls;
98
99         list_for_each_entry(pls, &pfg->proc_list, list) {
100                 if (pls->proc->tgid == task->tgid)
101                         return pls;
102         }
103
104         return NULL;
105 }
106
107 static struct sspt_proc *get_proc_by_pfg(struct pf_group *pfg,
108                                          struct task_struct *task)
109 {
110         struct pl_struct *pls;
111
112         pls = find_pl_struct(pfg, task);
113         if (pls)
114                 return pls->proc;
115
116         return NULL;
117 }
118
119 static struct sspt_proc *new_proc_by_pfg(struct pf_group *pfg,
120                                          struct task_struct *task)
121 {
122         struct pl_struct *pls;
123         struct sspt_proc *proc;
124
125         proc = sspt_proc_get_by_task_or_new(task, pfg->filter->priv);
126         copy_proc_form_img_to_sspt(pfg->i_proc, proc);
127
128         pls = create_pl_struct(proc);
129         add_pl_struct(pfg, pls);
130
131         return proc;
132 }
133 /* struct pl_struct */
134
135 static struct pf_group *create_pfg(struct proc_filter *filter)
136 {
137         struct pf_group *pfg = kmalloc(sizeof(*pfg), GFP_KERNEL);
138
139         INIT_LIST_HEAD(&pfg->list);
140         pfg->filter = filter;
141         pfg->i_proc = create_img_proc();
142         INIT_LIST_HEAD(&pfg->proc_list);
143
144         return pfg;
145 }
146
147 static void free_pfg(struct pf_group *pfg)
148 {
149         /* FIXME: */
150         kfree(pfg);
151 }
152
153 static void add_pfg_by_list(struct pf_group *pfg)
154 {
155         list_add(&pfg->list, &pfg_list);
156 }
157
158 static void del_pfg_by_list(struct pf_group *pfg)
159 {
160         list_del(&pfg->list);
161 }
162
163 struct pf_group *get_pf_group_by_dentry(struct dentry *dentry, void *priv)
164 {
165         struct pf_group *pfg;
166         struct proc_filter *filter;
167
168         list_for_each_entry(pfg, &pfg_list, list) {
169                 if (check_pf_by_dentry(pfg->filter, dentry))
170                         return pfg;
171         }
172
173         filter = create_pf_by_dentry(dentry, priv);
174         pfg = create_pfg(filter);
175
176         add_pfg_by_list(pfg);
177
178         return pfg;
179 }
180 EXPORT_SYMBOL_GPL(get_pf_group_by_dentry);
181
182 struct pf_group *get_pf_group_by_tgid(pid_t tgid, void *priv)
183 {
184         struct pf_group *pfg;
185         struct proc_filter *filter;
186
187         list_for_each_entry(pfg, &pfg_list, list) {
188                 if (check_pf_by_tgid(pfg->filter, tgid))
189                         return pfg;
190         }
191
192         filter = create_pf_by_tgid(tgid, priv);
193         pfg = create_pfg(filter);
194
195         add_pfg_by_list(pfg);
196
197         return pfg;
198 }
199 EXPORT_SYMBOL_GPL(get_pf_group_by_tgid);
200
201 struct pf_group *get_pf_group_dumb(void *priv)
202 {
203         struct pf_group *pfg;
204         struct proc_filter *filter;
205
206         list_for_each_entry(pfg, &pfg_list, list) {
207                 if (check_pf_dumb(pfg->filter))
208                         return pfg;
209         }
210
211         filter = create_pf_dumb(pfg->filter);
212         pfg = create_pfg(filter);
213
214         add_pfg_by_list(pfg);
215
216         return pfg;
217 }
218 EXPORT_SYMBOL_GPL(get_pf_group_dumb);
219
220 void put_pf_group(struct pf_group *pfg)
221 {
222
223 }
224
225 int pf_register_probe(struct pf_group *pfg, struct dentry *dentry,
226                       unsigned long offset, const char *args, char ret_type)
227 {
228         return img_proc_add_ip(pfg->i_proc, dentry, offset, args, ret_type);
229 }
230 EXPORT_SYMBOL_GPL(pf_register_probe);
231
232 int pf_unregister_probe(struct pf_group *pfg, struct dentry *dentry,
233                         unsigned long offset)
234 {
235         return img_proc_del_ip(pfg->i_proc, dentry, offset);
236 }
237 EXPORT_SYMBOL_GPL(pf_unregister_probe);
238
239 void call_page_fault(struct task_struct *task, unsigned long page_addr)
240 {
241         struct pf_group *pfg, *pfg_first = NULL;
242         struct sspt_proc *proc = NULL;
243
244         list_for_each_entry(pfg, &pfg_list, list) {
245                 if (check_task_f(pfg->filter, task) == NULL)
246                         continue;
247
248                 proc = get_proc_by_pfg(pfg, task);
249                 if (proc == NULL && task->tgid == task->pid) {
250                         proc = new_proc_by_pfg(pfg, task);
251                         pfg_first = pfg;
252                 }
253         }
254
255         if (proc) {
256                 if (pfg_first) {
257                         struct dentry *dentry;
258
259                         dentry = get_dentry_by_pf(pfg_first->filter);
260                         if (dentry == NULL) {
261                                 dentry = task->mm->exe_file ?
262                                          task->mm->exe_file->f_dentry :
263                                          NULL;
264                         }
265
266                         proc_info_msg(task, dentry);
267                         sspt_proc_install(proc);
268                 } else {
269                         sspt_proc_install_page(proc, page_addr);
270                 }
271         }
272 }
273
274 void uninstall_proc(struct sspt_proc *proc)
275 {
276         struct task_struct *task = proc->task;
277         struct pf_group *pfg;
278         struct pl_struct *pls;
279
280         list_for_each_entry(pfg, &pfg_list, list) {
281                 pls = find_pl_struct(pfg, task);
282                 if (pls) {
283                         del_pl_struct(pls);
284                         free_pl_struct(pls);
285                 }
286         }
287
288         task_lock(task);
289         BUG_ON(task->mm == NULL);
290         sspt_proc_uninstall(proc, task, US_UNREGS_PROBE);
291         task_unlock(task);
292
293         sspt_proc_free(proc);
294 }
295
296 void call_mm_release(struct task_struct *task)
297 {
298         struct sspt_proc *proc;
299
300         proc = sspt_proc_get_by_task(task);
301         if (proc)
302                 /* TODO: uninstall_proc - is not atomic context */
303                 uninstall_proc(proc);
304 }
305
306 void uninstall_page(unsigned long addr)
307 {
308
309 }
310
311 void install_all(void)
312 {
313         struct task_struct *task;
314         int tmp_oops_in_progress;
315
316         tmp_oops_in_progress = oops_in_progress;
317         oops_in_progress = 1;
318         rcu_read_lock();
319         for_each_process(task) {
320                 if (task->tgid != task->pid)
321                         continue;
322
323                 if (is_kthread(task))
324                         continue;
325
326                 call_page_fault(task, 0xba00baab);
327         }
328         rcu_read_unlock();
329         oops_in_progress = tmp_oops_in_progress;
330 }
331
332 static void clean_pfg(void)
333 {
334         struct pf_group *pfg, *n;
335
336         list_for_each_entry_safe(pfg, n, &pfg_list, list) {
337                 del_pfg_by_list(pfg);
338                 free_pfg(pfg);
339         }
340 }
341
342 static void on_each_uninstall_proc(struct sspt_proc *proc, void *data)
343 {
344         uninstall_proc(proc);
345 }
346
347 void uninstall_all(void)
348 {
349         wait_proc_lock();
350         on_each_proc_no_lock(on_each_uninstall_proc, NULL);
351         clean_pfg();
352 }
353
354 /* debug */
355 void pfg_print(struct pf_group *pfg)
356 {
357         img_proc_print(pfg->i_proc);
358 }
359 EXPORT_SYMBOL_GPL(pfg_print);
360 /* debug */