Rework WEBPROBE
[kernel/swap-modules.git] / webprobe / webprobe_prof.c
1 /**
2  *  webprobe/webprobe_prof.c
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  *
17  * Copyright (C) Samsung Electronics, 2015
18  *
19  * 2015          Anastasia Lyupa <a.lyupa@samsung.com>
20  *
21  */
22
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include <linux/version.h>
26
27 #include <us_manager/pf/pf_group.h>
28 #include <us_manager/probes/probes.h>
29 #include <us_manager/probes/probe_info_new.h>
30
31 #include "webprobe_prof.h"
32
33 static DEFINE_MUTEX(mutex_enable);
34
35 struct web_prof_data {
36         struct dentry *app_dentry;
37         struct dentry *lib_dentry;
38         struct pf_group *pfg;
39         u64 inspserver_addr;
40         struct probe_desc *inspserver;
41         u64 tick_addr;
42         struct probe_desc *tick_probe;
43         enum web_prof_state_t enabled;
44 };
45
46 static const char *CHROMIUM_EWK = "/usr/lib/libchromium-ewk.so";
47 static struct web_prof_data *web_data;
48
49 u64 *web_prof_addr_ptr(enum web_prof_addr_t type)
50 {
51         u64 *addr_ptr;
52
53         switch (type) {
54         case INSPSERVER_START:
55                 addr_ptr = &web_data->inspserver_addr;
56                 break;
57         case TICK_PROBE:
58                 addr_ptr = &web_data->tick_addr;
59                 break;
60         default:
61                 pr_err("ERROR: WEB_PROF_ADDR_PTR_TYPE=0x%x\n", type);
62                 addr_ptr = NULL;
63         }
64
65         return addr_ptr;
66 }
67
68 unsigned long web_prof_addr(enum web_prof_addr_t type)
69 {
70         unsigned long addr;
71
72         switch (type) {
73         case INSPSERVER_START:
74                 addr = web_data->inspserver_addr;
75                 break;
76         case TICK_PROBE:
77                 addr = web_data->tick_addr;
78                 break;
79         default:
80                 pr_err("ERROR: WEB_PROF_ADDR_TYPE=0x%x\n", type);
81                 addr = 0;
82         }
83
84         return addr;
85 }
86
87 static struct probe_desc *web_func_inst_add(unsigned long addr)
88 {
89         int ret;
90         struct probe_desc *probe = NULL;
91
92         probe = kmalloc(sizeof(*probe), GFP_KERNEL);
93
94         if (!probe)
95                 return NULL;
96
97         memset(probe, 0, sizeof(*probe));
98         probe->type = SWAP_WEBPROBE;
99
100         ret = pf_register_probe(web_data->pfg, web_data->lib_dentry,
101                                 addr, probe);
102
103         return probe;
104 }
105
106 static int __web_func_inst_remove(unsigned long addr, struct probe_desc *pd)
107 {
108         int ret;
109
110         if (!addr || !pd)
111                 return -EINVAL;
112
113         /* FIXME: check that address needs removing */
114         ret = pf_unregister_probe(web_data->pfg, web_data->lib_dentry,
115                                   addr, pd);
116
117         return ret;
118 }
119
120 int web_func_inst_remove(enum web_prof_addr_t type)
121 {
122         unsigned long addr = 0;
123         struct probe_desc *pd = NULL;
124
125         switch (type) {
126         case INSPSERVER_START:
127                 addr = web_data->inspserver_addr;
128                 pd = web_data->inspserver;
129                 break;
130         case TICK_PROBE:
131                 addr = web_data->tick_addr;
132                 pd = web_data->tick_probe;
133                 break;
134         default:
135                 pr_err("ERROR: WEB_PROF_ADDR_TYPE=0x%x\n", type);
136         }
137
138         return __web_func_inst_remove(addr, pd);
139 }
140
141 int web_prof_data_set(char *app_path, char *app_id)
142 {
143         web_data->app_dentry = dentry_by_path(app_path);
144         if (!web_data->app_dentry)
145                 return -EFAULT;
146
147         web_data->lib_dentry = dentry_by_path(CHROMIUM_EWK);
148         if (!web_data->lib_dentry)
149                 return -EFAULT;
150
151         if (web_data->pfg)
152                 put_pf_group(web_data->pfg);
153
154         web_data->pfg = get_pf_group_by_comm(app_id, web_data->app_dentry);
155         if (!web_data->pfg)
156                 return -EFAULT;
157
158         return 0;
159 }
160
161 struct dentry *web_prof_lib_dentry(void)
162 {
163         return web_data->lib_dentry;
164 }
165
166 enum web_prof_state_t web_prof_enabled(void)
167 {
168         return web_data->enabled;
169 }
170
171 int web_prof_enable(void)
172 {
173         int ret = 0;
174
175         mutex_lock(&mutex_enable);
176         if (web_data->enabled != PROF_OFF) {
177                 pr_err("ERROR: Web profiling is already enabled\n");
178                 goto out;
179         }
180
181         web_data->enabled = PROF_ON;
182
183         if (web_data->inspserver_addr) {
184                 web_data->inspserver =
185                         web_func_inst_add(web_data->inspserver_addr);
186         }
187
188         if (web_data->tick_addr) {
189                 web_data->tick_probe =
190                         web_func_inst_add(web_data->tick_addr);
191         }
192
193 out:
194         mutex_unlock(&mutex_enable);
195
196         return ret;
197 }
198
199 int web_prof_disable(void)
200 {
201         int ret = 0;
202
203         mutex_lock(&mutex_enable);
204         if (web_data->enabled != PROF_ON) {
205                 pr_err("ERROR: Web profiling is already disabled\n");
206                 ret = -EBUSY;
207                 goto out;
208         }
209
210         web_data->enabled = PROF_OFF;
211
212         if (web_data->inspserver_addr) {
213                 if (!__web_func_inst_remove(web_data->inspserver_addr,
214                                             web_data->inspserver)) {
215                         kfree(web_data->inspserver);
216                         web_data->inspserver = NULL;
217                 }
218         }
219
220         if (web_data->tick_addr) {
221                 if (!__web_func_inst_remove(web_data->tick_addr,
222                                             web_data->tick_probe)) {
223                         kfree(web_data->tick_probe);
224                         web_data->tick_probe = NULL;
225                 }
226         }
227
228 out:
229         mutex_unlock(&mutex_enable);
230
231         return ret;
232 }
233
234 int web_prof_init(void)
235 {
236         web_data = kmalloc(sizeof(*web_data), GFP_KERNEL);
237         if (!web_data)
238                 return -ENOMEM;
239
240         memset(web_data, 0, sizeof(struct web_prof_data));
241
242         web_data->enabled = PROF_OFF;
243
244         return 0;
245 }
246
247 void web_prof_exit(void)
248 {
249         if (web_data->pfg)
250                 put_pf_group(web_data->pfg);
251
252         kfree(web_data->inspserver);
253         kfree(web_data->tick_probe);
254         kfree(web_data);
255 }