[STYLE] Fix issues from checkpatch.pl
[platform/kernel/swap-modules.git] / writer / debugfs_writer.c
1 /**
2  * writer/debugfs_writer.c
3  * @author Vyacheslav Cherkashin <v.cherkashin@samsung.com>
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  * Writer debugfs implementation.
28  */
29
30
31 #include <linux/module.h>
32 #include <linux/debugfs.h>
33 #include <linux/vmalloc.h>
34 #include <linux/slab.h>
35 #include <linux/uaccess.h>
36 #include <master/swap_debugfs.h>
37 #include <master/swap_initializer.h>
38 #include "swap_writer_module.h"
39 #include "event_filter.h"
40
41
42 /* ============================================================================
43  * ===                               BUFFER                                 ===
44  * ============================================================================
45  */
46 static char *common_buf;
47 enum { subbuf_size = 8*1024 };
48 enum { common_buf_size = subbuf_size * NR_CPUS };
49
50 static int init_buffer(void)
51 {
52         common_buf = vmalloc(common_buf_size);
53
54         return common_buf ? 0 : -ENOMEM;
55 }
56
57 static void exit_buffer(void)
58 {
59         vfree(common_buf);
60         common_buf = NULL;
61 }
62
63 static void *get_current_buf(void)
64 {
65         return common_buf + subbuf_size * get_cpu();
66 }
67
68 static void put_current_buf(void)
69 {
70         put_cpu();
71 }
72
73
74
75
76
77 /* ============================================================================
78  * ===                             FOPS_RAW                                 ===
79  * ============================================================================
80  */
81 static ssize_t write_raw(struct file *file, const char __user *user_buf,
82                          size_t count, loff_t *ppos)
83 {
84         int ret;
85         void *buf;
86
87         if (count > subbuf_size)
88                 return -EINVAL;
89
90         buf = get_current_buf();
91         if (copy_from_user(buf, user_buf, count)) {
92                 ret = -EFAULT;
93                 goto put_buf;
94         }
95
96         ret = raw_msg(buf, count);
97
98 put_buf:
99         put_current_buf();
100         return ret;
101 }
102
103 static const struct file_operations fops_raw = {
104         .owner = THIS_MODULE,
105         .open = swap_init_simple_open,
106         .release = swap_init_simple_release,
107         .write =        write_raw,
108         .llseek =       default_llseek
109 };
110
111
112
113
114
115 /* ============================================================================
116  * ===                        FOPS_AVAILABLE_FILTERS                        ===
117  * ============================================================================
118  */
119 struct read_buf {
120         char *begin;
121         char *ptr;
122         char *end;
123 };
124
125 static void func_for_read(struct ev_filter *f, void *data)
126 {
127         struct read_buf *rbuf = (struct read_buf *)data;
128         int len = strlen(f->name);
129
130         if (rbuf->end - rbuf->ptr < len + 2)
131                 return;
132
133         if (rbuf->ptr != rbuf->begin) {
134                 *rbuf->ptr = ' ';
135                 ++rbuf->ptr;
136         }
137
138         memcpy(rbuf->ptr, f->name, len);
139         rbuf->ptr += len;
140 }
141
142 static ssize_t read_af(struct file *file, char __user *user_buf,
143                        size_t count, loff_t *ppos)
144 {
145         char buf[512];
146         struct read_buf rbuf = {
147                 .begin = buf,
148                 .ptr = buf,
149                 .end = buf + sizeof(buf)
150         };
151
152         event_filter_on_each(func_for_read, (void *)&rbuf);
153
154         *rbuf.ptr = '\n';
155         ++rbuf.ptr;
156
157         return simple_read_from_buffer(user_buf, count, ppos,
158                                        rbuf.begin, rbuf.ptr - rbuf.begin);
159 }
160
161 static const struct file_operations fops_available_filters = {
162         .owner = THIS_MODULE,
163         .open = swap_init_simple_open,
164         .release = swap_init_simple_release,
165         .read =         read_af,
166         .llseek =       default_llseek
167 };
168
169
170
171
172
173 /* ============================================================================
174  * ===                              FOPS_FILTER                             ===
175  * ============================================================================
176  */
177 static ssize_t read_filter(struct file *file, char __user *user_buf,
178                            size_t count, loff_t *ppos)
179 {
180         const char *name = event_filter_get();
181         int len = strlen(name);
182         char *buf;
183         ssize_t ret;
184
185         buf = kmalloc(len + 2, GFP_KERNEL);
186         memcpy(buf, name, len);
187
188         buf[len] = '\0';
189         buf[len + 1] = '\n';
190
191         ret = simple_read_from_buffer(user_buf, count, ppos, buf, len + 2);
192         kfree(buf);
193
194         return ret;
195 }
196
197 static ssize_t write_filter(struct file *file, const char __user *user_buf,
198                         size_t count, loff_t *ppos)
199 {
200         enum { len = 32 };
201         char buf[len], name[len];
202         size_t buf_size;
203         ssize_t ret;
204
205         buf_size = min(count, (size_t)(len - 1));
206         if (copy_from_user(buf, user_buf, buf_size))
207                 return -EFAULT;
208
209         buf[len - 1] = '\0';
210         ret = sscanf(buf, "%31s", name);
211         if (ret != 1)
212                 return -EINVAL;
213
214         ret = event_filter_set(name);
215         if (ret)
216                 return -EINVAL;
217
218         return count;
219 }
220
221 static const struct file_operations fops_filter = {
222         .owner = THIS_MODULE,
223         .open = swap_init_simple_open,
224         .release = swap_init_simple_release,
225         .read =         read_filter,
226         .write =        write_filter,
227         .llseek =       default_llseek
228 };
229
230
231
232
233
234 /* ============================================================================
235  * ===                              INIT/EXIT                               ===
236  * ============================================================================
237  */
238 static struct dentry *writer_dir;
239
240 /**
241  * @brief Removes writer debugfs.
242  *
243  * @return Void.
244  */
245 void exit_debugfs_writer(void)
246 {
247         if (writer_dir)
248                 debugfs_remove_recursive(writer_dir);
249
250         writer_dir = NULL;
251
252         exit_buffer();
253 }
254
255 /**
256  * @brief Initializes writer debugfs.
257  *
258  * @return 0 on success, error code on error.
259  */
260 int init_debugfs_writer(void)
261 {
262         int ret;
263         struct dentry *swap_dir, *dentry;
264
265         ret = init_buffer();
266         if (ret)
267                 return ret;
268
269         swap_dir = swap_debugfs_getdir();
270         if (swap_dir == NULL)
271                 return -ENOENT;
272
273         writer_dir = debugfs_create_dir("writer", swap_dir);
274         if (writer_dir == NULL)
275                 return -ENOMEM;
276
277         dentry = debugfs_create_file("raw", 0600, writer_dir, NULL, &fops_raw);
278         if (dentry == NULL)
279                 goto fail;
280
281         dentry = debugfs_create_file("available_filters", 0600, writer_dir,
282                                      NULL, &fops_available_filters);
283         if (dentry == NULL)
284                 goto fail;
285
286         dentry = debugfs_create_file("filter", 0600,
287                                      writer_dir, NULL, &fops_filter);
288         if (dentry == NULL)
289                 goto fail;
290
291         return 0;
292
293 fail:
294         exit_debugfs_writer();
295         return -ENOMEM;
296 }