ARM: tizen_tm1_defconfig: Enable missing features related with CGROUPS
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / kernel / swap / parser / us_inst.c
1 /**
2  * parser/us_inst.c
3  * @author Vyacheslav Cherkashin
4  *
5  * @section LICENSE
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  *
21  * @section COPYRIGHT
22  *
23  * Copyright (C) Samsung Electronics, 2013
24  *
25  * @section DESCRIPTION
26  *
27  * User-space instrumentation controls.
28  */
29
30
31 #include <linux/slab.h>
32 #include <linux/module.h>
33 #include <linux/version.h>
34 #include <linux/err.h>
35 #include <linux/errno.h>
36 #include <us_manager/pf/pf_group.h>
37 #include <us_manager/probes/probes.h>
38
39 #include "msg_parser.h"
40 #include "us_inst.h"
41 #include "usm_msg.h"
42
43
44 struct pfg_item {
45         struct list_head list;
46         struct pf_group *pfg;
47 };
48
49
50 static LIST_HEAD(pfg_item_list);
51 static DEFINE_SPINLOCK(pfg_item_lock);
52
53
54 static struct pfg_msg_cb msg_cb = {
55         .msg_info = usm_msg_info,
56         .msg_status_info = usm_msg_status_info,
57         .msg_term = usm_msg_term,
58         .msg_map = usm_msg_map,
59         .msg_unmap = usm_msg_unmap
60 };
61
62 static struct pfg_item *pfg_item_create(struct pf_group *pfg)
63 {
64         int ret;
65         struct pfg_item *item;
66
67         ret = pfg_msg_cb_set(pfg, &msg_cb);
68         if (ret)
69                 return ERR_PTR(ret);
70
71         item = kmalloc(sizeof(*item), GFP_KERNEL);
72         if (item == NULL)
73                 return ERR_PTR(-ENOMEM);
74
75         INIT_LIST_HEAD(&item->list);
76         item->pfg = pfg;
77
78         return item;
79 }
80
81 static void pfg_item_free(struct pfg_item *item)
82 {
83         pfg_msg_cb_reset(item->pfg);
84         kfree(item);
85 }
86
87 /* called with pfg_item_lock held */
88 static bool pfg_check(struct pf_group *pfg)
89 {
90         struct pfg_item *item;
91
92         list_for_each_entry(item, &pfg_item_list, list) {
93                 if (item->pfg == pfg)
94                         return true;
95         }
96
97         return false;
98 }
99
100 static int pfg_add(struct pf_group *pfg)
101 {
102         bool already;
103
104         spin_lock(&pfg_item_lock);
105         already = pfg_check(pfg);
106         spin_unlock(&pfg_item_lock);
107
108         if (already) {
109                 put_pf_group(pfg);
110         } else {
111                 struct pfg_item *item;
112
113                 item = pfg_item_create(pfg);
114                 if (IS_ERR(item))
115                         return PTR_ERR(item);
116
117                 spin_lock(&pfg_item_lock);
118                 list_add(&item->list, &pfg_item_list);
119                 spin_unlock(&pfg_item_lock);
120         }
121
122         return 0;
123 }
124
125 void pfg_put_all(void)
126 {
127         LIST_HEAD(tmp_list);
128         struct pfg_item *item, *n;
129
130         spin_lock(&pfg_item_lock);
131         list_splice_init(&pfg_item_list, &tmp_list);
132         spin_unlock(&pfg_item_lock);
133
134         list_for_each_entry_safe(item, n, &tmp_list, list) {
135                 struct pf_group *pfg = item->pfg;
136
137                 list_del(&item->list);
138                 pfg_item_free(item);
139                 put_pf_group(pfg);
140         }
141 }
142
143 static int mod_func_inst(struct func_inst_data *func, struct pf_group *pfg,
144                          struct dentry *dentry, enum MOD_TYPE mt)
145 {
146         int ret;
147
148         switch (mt) {
149         case MT_ADD:
150                 ret = pf_register_probe(pfg, dentry, func->addr,
151                                         &func->probe_i);
152                 break;
153         case MT_DEL:
154                 ret = pf_unregister_probe(pfg, dentry, func->addr);
155                 break;
156         default:
157                 printk(KERN_INFO "ERROR: mod_type=0x%x\n", mt);
158                 ret = -EINVAL;
159         }
160
161         return ret;
162 }
163
164 static int mod_lib_inst(struct lib_inst_data *lib, struct pf_group *pfg,
165                         enum MOD_TYPE mt)
166 {
167         int ret = 0, i;
168         struct dentry *dentry;
169
170         dentry = dentry_by_path(lib->path);
171         if (dentry == NULL) {
172                 printk(KERN_INFO "Cannot get dentry by path %s\n", lib->path);
173                 return -EINVAL;
174         }
175
176         for (i = 0; i < lib->cnt_func; ++i) {
177                 ret = mod_func_inst(lib->func[i], pfg, dentry, mt);
178                 if (ret) {
179                         printk(KERN_INFO "Cannot mod func inst, ret = %d\n",
180                                ret);
181                         return ret;
182                 }
183         }
184
185         return ret;
186 }
187
188 static int get_pfg_by_app_info(struct app_info_data *app_info,
189                                struct pf_group **pfg)
190 {
191         struct dentry *dentry;
192
193         dentry = dentry_by_path(app_info->exec_path);
194         if (dentry == NULL)
195                 return -EINVAL;
196
197         switch (app_info->app_type) {
198         case AT_PID:
199                 if (app_info->tgid == 0) {
200                         if (app_info->exec_path[0] == '\0')
201                                 *pfg = get_pf_group_dumb(dentry);
202                         else
203                                 goto pf_dentry;
204                 } else
205                         *pfg = get_pf_group_by_tgid(app_info->tgid, dentry);
206                 break;
207         case AT_TIZEN_WEB_APP:
208                 *pfg = get_pf_group_by_comm(app_info->app_id, dentry);
209                 break;
210         case AT_TIZEN_NATIVE_APP:
211         case AT_COMMON_EXEC:
212  pf_dentry:
213                 *pfg = get_pf_group_by_dentry(dentry, dentry);
214                 break;
215         default:
216                 printk(KERN_INFO "ERROR: app_type=0x%x\n", app_info->app_type);
217                 return -EINVAL;
218         }
219
220         return 0;
221 }
222
223 static int mod_us_app_inst(struct app_inst_data *app_inst, enum MOD_TYPE mt)
224 {
225         int ret, i;
226         struct pf_group *pfg;
227         struct dentry *dentry;
228
229         ret = get_pfg_by_app_info(app_inst->app_info, &pfg);
230         if (ret) {
231                 printk(KERN_INFO "Cannot get pfg by app info, ret = %d\n", ret);
232                 return ret;
233         }
234
235         ret = pfg_add(pfg);
236         if (ret) {
237                 put_pf_group(pfg);
238                 printk(KERN_INFO "Cannot pfg_add, ret=%d\n", ret);
239                 return ret;
240         }
241
242         for (i = 0; i < app_inst->cnt_func; ++i) {
243                 /* TODO: */
244                 dentry = dentry_by_path(app_inst->app_info->exec_path);
245                 if (dentry == NULL) {
246                         printk(KERN_INFO "Cannot find dentry by path %s\n",
247                                app_inst->app_info->exec_path);
248                         return -EINVAL;
249                 }
250
251                 ret = mod_func_inst(app_inst->func[i], pfg, dentry, mt);
252                 if (ret) {
253                         printk(KERN_INFO "Cannot mod func inst, ret = %d\n",
254                                ret);
255                         return ret;
256                 }
257         }
258
259         for (i = 0; i < app_inst->cnt_lib; ++i) {
260                 ret = mod_lib_inst(app_inst->lib[i], pfg, mt);
261                 if (ret) {
262                         printk(KERN_INFO "Cannot mod lib inst, ret = %d\n",
263                                ret);
264                         return ret;
265                 }
266         }
267
268         return 0;
269 }
270
271 /**
272  * @brief Registers probes.
273  *
274  * @param us_inst Pointer to the target us_inst_data struct.
275  * @param mt Modificator, indicates whether we install or remove probes.
276  * @return 0 on suceess, error code on error.
277  */
278 int mod_us_inst(struct us_inst_data *us_inst, enum MOD_TYPE mt)
279 {
280         u32 i;
281         int ret;
282
283         for (i = 0; i < us_inst->cnt; ++i) {
284                 ret = mod_us_app_inst(us_inst->app_inst[i], mt);
285                 if (ret) {
286                         printk(KERN_INFO "Cannot mod us app inst, ret = %d\n",
287                                ret);
288                         return ret;
289                 }
290         }
291
292         return 0;
293 }