Rework webprobe module
[kernel/swap-modules.git] / webprobe / webprobe_debugfs.c
1 /**
2  *  webprobe/webprobe_debugfs.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/debugfs.h>
26 #include <linux/uaccess.h>
27
28 #include <master/swap_debugfs.h>
29 #include <master/swap_initializer.h>
30
31 #include "webprobe_debugfs.h"
32 #include "webprobe.h"
33
34 static const char ENABLED_FILE[] =              "enabled";
35 static const char APP_INFO_FILE[] =             "app_info";
36 static const char INSPSERVER_START_FILE[] =     "inspector_server_start";
37 static const char TICK_PROBE_FILE[] =           "tick_probe";
38
39 enum { max_count = 256 };
40 static char app_info[max_count];
41
42 /* ============================================================================
43  * ===              DEBUGFS FOR WEBPROBE INSTRUMENTATION                    ===
44  * ============================================================================
45  */
46
47 static ssize_t read_enabled(struct file *file, char __user *user_buf,
48                             size_t count, loff_t *ppos)
49 {
50         char buf[2];
51
52         buf[0] = web_prof_enabled() ? '1' : '0';
53         buf[1] = '\n';
54
55         return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
56 }
57
58 static ssize_t write_enabled(struct file *file, const char __user *user_buf,
59                              size_t count, loff_t *ppos)
60 {
61         int ret = 0;
62         char buf[32];
63         size_t buf_size;
64
65         buf_size = min(count, (sizeof(buf) - 1));
66         if (copy_from_user(buf, user_buf, buf_size))
67                 return -EFAULT;
68
69         buf[buf_size] = '\0';
70         switch (buf[0]) {
71         case '1':
72                 ret = web_prof_enable();
73                 break;
74         case '0':
75                 ret = web_prof_disable();
76                 break;
77         default:
78                 return -EINVAL;
79         }
80
81         if (ret)
82                 return ret;
83
84         return count;
85 }
86
87 static const struct file_operations fops_enabled = {
88         .write =        write_enabled,
89         .read =         read_enabled,
90         .open =         swap_init_simple_open,
91         .release =      swap_init_simple_release,
92 };
93
94 static ssize_t write_app_info(struct file *file, const char __user *user_buf,
95                               size_t count, loff_t *ppos)
96 {
97         int ret = 0;
98         char *buf, *path, *id;
99         int n;
100
101         if (count > max_count)
102                 return -ENOMEM;
103
104         buf = kmalloc(count + 1, GFP_KERNEL);
105         if (!buf)
106                 return -ENOMEM;
107
108         if (copy_from_user(buf, user_buf, count)) {
109                 ret = -EFAULT;
110                 goto free_buf;
111         }
112
113         buf[count] = '\0';
114
115         path = kmalloc(count, GFP_KERNEL);
116         if (!path) {
117                 ret = -ENOMEM;
118                 goto free_buf;
119         }
120
121         id = kmalloc(count, GFP_KERNEL);
122         if (!id) {
123                 ret = -ENOMEM;
124                 goto free_path;
125         }
126
127         n = sscanf(buf, "%s %s", path, id);
128
129         if (n != 2) {
130                 ret = -EINVAL;
131                 goto free_app_info;
132         }
133
134         web_prof_data_set(path, id);
135         snprintf(app_info, sizeof(app_info), "%s\n", buf);
136
137 free_app_info:
138         kfree(id);
139 free_path:
140         kfree(path);
141 free_buf:
142         kfree(buf);
143
144         return ret ? ret : count;
145 }
146
147 static ssize_t read_app_info(struct file *file, char __user *userbuf,
148                              size_t count, loff_t *ppos)
149 {
150         return simple_read_from_buffer(userbuf, count, ppos, app_info,
151                                        sizeof(app_info) - 1);
152 }
153
154 static const struct file_operations fops_app_info = {
155         .write =        write_app_info,
156         .read =         read_app_info,
157         .open =         swap_init_simple_open,
158         .release =      swap_init_simple_release,
159 };
160
161 /* ============================================================================
162  * ===                             INIT/EXIT                                ===
163  * ============================================================================
164  */
165
166 static struct dentry *webprobe_dir;
167
168 void webprobe_debugfs_exit(void)
169 {
170         debugfs_remove_recursive(webprobe_dir);
171         webprobe_dir = NULL;
172 }
173
174 int webprobe_debugfs_init(void)
175 {
176         struct dentry *dentry;
177
178         dentry = swap_debugfs_getdir();
179         if (!dentry)
180                 return -ENOENT;
181
182         webprobe_dir = debugfs_create_dir("webprobe", dentry);
183         if (!webprobe_dir)
184                 return -ENOMEM;
185
186         dentry = debugfs_create_file(ENABLED_FILE, 0600, webprobe_dir, NULL,
187                                      &fops_enabled);
188
189         dentry = debugfs_create_file(APP_INFO_FILE, 0600, webprobe_dir,
190                                      NULL, &fops_app_info);
191         if (!dentry)
192                 goto fail;
193
194         dentry = debugfs_create_x64(INSPSERVER_START_FILE, 0600, webprobe_dir,
195                                     web_prof_addr_ptr(INSPSERVER_START));
196         if (!dentry)
197                 goto fail;
198
199         dentry = debugfs_create_x64(TICK_PROBE_FILE, 0600, webprobe_dir,
200                                     web_prof_addr_ptr(TICK_PROBE));
201         if (!dentry)
202                 goto fail;
203
204         return 0;
205
206 fail:
207         webprobe_debugfs_exit();
208         return -ENOMEM;
209 }