[FIX] race condition when use sspt_proc
[kernel/swap-modules.git] / us_manager / us_manager.c
1 /*
2  *  SWAP uprobe manager
3  *  modules/us_manager/us_manager.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 #include <linux/module.h>
26 #include <linux/mutex.h>
27 #include <linux/stop_machine.h>
28 #include "pf/pf_group.h"
29 #include "sspt/sspt_proc.h"
30 #include "probes/probe_info_new.h"
31 #include "helper.h"
32 #include "us_manager.h"
33 #include "debugfs_us_manager.h"
34 #include "callbacks.h"
35 #include <writer/event_filter.h>
36 #include <master/swap_initializer.h>
37
38
39 static DEFINE_MUTEX(mutex_inst);
40 static enum status_type status = ST_OFF;
41
42
43 static int __do_usm_stop(void *data)
44 {
45         get_all_procs();
46
47         return 0;
48 }
49
50 static void do_usm_stop(void)
51 {
52         int ret;
53
54         exec_cbs(STOP_CB);
55         unregister_helper_top();
56
57         ret = stop_machine(__do_usm_stop, NULL, NULL);
58         if (ret)
59                 printk("do_usm_stop failed: %d\n", ret);
60
61         uninstall_all();
62         unregister_helper_bottom();
63         sspt_proc_check_empty();
64 }
65
66 static int do_usm_start(void)
67 {
68         int ret;
69
70         ret = register_helper();
71         if (ret)
72                 return ret;
73
74         install_all();
75
76         exec_cbs(START_CB);
77
78         return 0;
79 }
80
81 /**
82  * @brief Get instrumentation status
83  *
84  * @return Instrumentation status
85  */
86 enum status_type usm_get_status(void)
87 {
88         mutex_lock(&mutex_inst);
89         return status;
90 }
91 EXPORT_SYMBOL_GPL(usm_get_status);
92
93 /**
94  * @brief Put instrumentation status
95  *
96  * @param st Instrumentation status
97  * @return Void
98  */
99 void usm_put_status(enum status_type st)
100 {
101         status = st;
102         mutex_unlock(&mutex_inst);
103 }
104 EXPORT_SYMBOL_GPL(usm_put_status);
105
106 /**
107  * @brief Stop instrumentation
108  *
109  * @return Error code
110  */
111 int usm_stop(void)
112 {
113         int ret = 0;
114
115         if (usm_get_status() == ST_OFF) {
116                 printk(KERN_INFO "US instrumentation is not running!\n");
117                 ret = -EINVAL;
118                 goto put;
119         }
120
121         do_usm_stop();
122
123 put:
124         usm_put_status(ST_OFF);
125
126         return ret;
127 }
128 EXPORT_SYMBOL_GPL(usm_stop);
129
130 /**
131  * @brief Start instrumentation
132  *
133  * @return Error code
134  */
135 int usm_start(void)
136 {
137         int ret = -EINVAL;
138         enum status_type st;
139
140         st = usm_get_status();
141         if (st == ST_ON) {
142                 printk(KERN_INFO "US instrumentation is already run!\n");
143                 goto put;
144         }
145
146         ret = do_usm_start();
147         if (ret == 0)
148                 st = ST_ON;
149
150 put:
151         usm_put_status(st);
152
153         return ret;
154 }
155 EXPORT_SYMBOL_GPL(usm_start);
156
157
158
159
160
161 /* ============================================================================
162  * ===                                QUIET                                 ===
163  * ============================================================================
164  */
165 static enum quiet_type quiet = QT_ON;
166
167 /**
168  * @brief Set quiet mode
169  *
170  * @param q Quiet mode
171  * @return Void
172  */
173 void set_quiet(enum quiet_type q)
174 {
175         quiet = q;
176 }
177 EXPORT_SYMBOL_GPL(set_quiet);
178
179 /**
180  * @brief Get quiet mode
181  *
182  * @return Quiet mode
183  */
184 enum quiet_type get_quiet(void)
185 {
186         return quiet;
187 }
188 EXPORT_SYMBOL_GPL(get_quiet);
189
190
191
192
193
194 /* ============================================================================
195  * ===                              US_FILTER                               ===
196  * ============================================================================
197  */
198 static int us_filter(struct task_struct *task)
199 {
200         struct sspt_proc *proc;
201
202         /* FIXME: add read lock (deadlock in sampler) */
203         proc = sspt_proc_by_task(task);
204         if (proc)
205                 return sspt_proc_is_send_event(proc);
206
207         return 0;
208 }
209
210 static struct ev_filter ev_us_filter = {
211         .name = "traced_process_only",
212         .filter = us_filter
213 };
214
215 static int init_us_filter(void)
216 {
217         int ret;
218
219         ret = event_filter_register(&ev_us_filter);
220         if (ret)
221                 return ret;
222
223         return event_filter_set(ev_us_filter.name);
224 }
225
226 static void exit_us_filter(void)
227 {
228         event_filter_unregister(&ev_us_filter);
229 }
230
231
232
233
234
235 static int usm_once(void)
236 {
237         int ret;
238
239         ret = once_helper();
240
241         return ret;
242 }
243
244 static int init_us_manager(void)
245 {
246         int ret;
247
248         ret = sspt_proc_init();
249         if (ret)
250                 return ret;
251
252         ret = pin_init();
253         if (ret)
254                 goto uninit_proc;
255
256         ret = init_us_filter();
257         if (ret)
258                 goto uninit_pin;
259
260         return 0;
261
262 uninit_pin:
263         pin_exit();
264 uninit_proc:
265         sspt_proc_uninit();
266
267         return ret;
268 }
269
270 static void exit_us_manager(void)
271 {
272         if (status == ST_ON)
273                 do_usm_stop();
274
275         remove_all_cbs();
276
277         exit_us_filter();
278         pin_exit();
279         sspt_proc_uninit();
280 }
281
282 SWAP_LIGHT_INIT_MODULE(usm_once, init_us_manager, exit_us_manager,
283                        init_debugfs_us_manager, exit_debugfs_us_manager);
284
285 MODULE_LICENSE("GPL");