blob: 3a13ef3b357e3d737e25bd8e2ae1e33240acf293 [file] [log] [blame]
Dhoat Harpalf76b2362018-03-22 20:37:38 +05301/* Copyright (c) 2012-2015,2017-2018 The Linux Foundation. All rights reserved.
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -06002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/slab.h>
15#include <linux/uaccess.h>
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/kernel.h>
19#include <linux/errno.h>
20#include <linux/jiffies.h>
21#include <linux/debugfs.h>
22#include <linux/io.h>
23#include <linux/idr.h>
24#include <linux/string.h>
25#include <linux/sched.h>
26#include <linux/wait.h>
27#include <linux/delay.h>
28#include <linux/completion.h>
29#include <linux/ipc_logging.h>
30
31#include "ipc_logging_private.h"
32
33static DEFINE_MUTEX(ipc_log_debugfs_init_lock);
34static struct dentry *root_dent;
35
36static int debug_log(struct ipc_log_context *ilctxt,
37 char *buff, int size, int cont)
38{
39 int i = 0;
40 int ret;
41
42 if (size < MAX_MSG_DECODED_SIZE) {
43 pr_err("%s: buffer size %d < %d\n", __func__, size,
44 MAX_MSG_DECODED_SIZE);
45 return -ENOMEM;
46 }
47 do {
48 i = ipc_log_extract(ilctxt, buff, size - 1);
49 if (cont && i == 0) {
50 ret = wait_for_completion_interruptible(
51 &ilctxt->read_avail);
52 if (ret < 0)
53 return ret;
54 }
55 } while (cont && i == 0);
56
57 return i;
58}
59
60/*
61 * VFS Read operation helper which dispatches the call to the debugfs
62 * read command stored in file->private_data.
63 *
64 * @file File structure
65 * @buff user buffer
66 * @count size of user buffer
67 * @ppos file position to read from (only a value of 0 is accepted)
68 * @cont 1 = continuous mode (don't return 0 to signal end-of-file)
69 *
70 * @returns ==0 end of file
71 * >0 number of bytes read
72 * <0 error
73 */
74static ssize_t debug_read_helper(struct file *file, char __user *buff,
75 size_t count, loff_t *ppos, int cont)
76{
Lynus Vaz802d7382017-06-30 15:10:26 +053077 struct ipc_log_context *ilctxt;
78 struct dentry *d = file->f_path.dentry;
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -060079 char *buffer;
80 int bsize;
Lynus Vaz802d7382017-06-30 15:10:26 +053081 int r;
82
Tingwei Zhang56025082018-06-08 20:08:04 +080083 r = debugfs_file_get(d);
Lynus Vaz802d7382017-06-30 15:10:26 +053084 if (!r) {
85 ilctxt = file->private_data;
86 r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO;
Tingwei Zhang56025082018-06-08 20:08:04 +080087 } else {
Lynus Vaz802d7382017-06-30 15:10:26 +053088 return r;
Tingwei Zhang56025082018-06-08 20:08:04 +080089 }
90 debugfs_file_put(d);
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -060091
92 buffer = kmalloc(count, GFP_KERNEL);
Lynus Vaz802d7382017-06-30 15:10:26 +053093 if (!buffer) {
94 bsize = -ENOMEM;
95 goto done;
96 }
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -060097
98 bsize = debug_log(ilctxt, buffer, count, cont);
Lynus Vaz802d7382017-06-30 15:10:26 +053099
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -0600100 if (bsize > 0) {
101 if (copy_to_user(buff, buffer, bsize)) {
Lynus Vaz802d7382017-06-30 15:10:26 +0530102 bsize = -EFAULT;
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -0600103 kfree(buffer);
Lynus Vaz802d7382017-06-30 15:10:26 +0530104 goto done;
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -0600105 }
106 *ppos += bsize;
107 }
108 kfree(buffer);
Lynus Vaz802d7382017-06-30 15:10:26 +0530109
110done:
111 ipc_log_context_put(ilctxt);
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -0600112 return bsize;
113}
114
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530115static ssize_t debug_write_ctrl(struct file *file, const char __user *buff,
116 size_t count, loff_t *ppos)
117{
118 struct ipc_log_context *ilctxt;
119 struct dentry *d = file->f_path.dentry;
120 int bsize = 1;
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530121 int r;
122 char local_buf[3];
123
Tingwei Zhang56025082018-06-08 20:08:04 +0800124 r = debugfs_file_get(d);
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530125 if (!r) {
126 ilctxt = file->private_data;
127 r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO;
Tingwei Zhang56025082018-06-08 20:08:04 +0800128 } else {
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530129 return r;
Tingwei Zhang56025082018-06-08 20:08:04 +0800130 }
131 debugfs_file_put(d);
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530132
133 if (copy_from_user(local_buf, buff, bsize)) {
134 count = -EFAULT;
135 goto done;
136 }
137
138 if (*local_buf == '1') {
139 ipc_log_string(ilctxt, "LOGGING DISABLED FOR THIS CLIENT!!\n");
140 ilctxt->disabled = true;
141 } else if (*local_buf == '0') {
142 ilctxt->disabled = false;
143 ipc_log_string(ilctxt, "LOGGING ENABLED FOR THIS CLIENT!!\n");
144 }
145
146done:
147 ipc_log_context_put(ilctxt);
148 return count;
149}
150
151
152static ssize_t debug_write_ctrl_all(struct file *file, const char __user *buff,
153 size_t count, loff_t *ppos)
154{
155 int bsize = 1;
156 char local_buf[3];
157
158 if (copy_from_user(local_buf, buff, bsize))
159 return -EFAULT;
160 if (*local_buf == '1')
161 ipc_log_ctrl_all(true);
162 else if (*local_buf == '0')
163 ipc_log_ctrl_all(false);
164 return count;
165}
166
167static ssize_t debug_read_ctrl(struct file *file, char __user *buff,
168 size_t count, loff_t *ppos)
169{
170 struct ipc_log_context *ilctxt;
171 struct dentry *d = file->f_path.dentry;
172 int bsize = 2;
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530173 int r;
174
Tingwei Zhang56025082018-06-08 20:08:04 +0800175 r = debugfs_file_get(d);
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530176 if (!r) {
177 ilctxt = file->private_data;
178 r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO;
Tingwei Zhang56025082018-06-08 20:08:04 +0800179 } else {
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530180 return r;
Tingwei Zhang56025082018-06-08 20:08:04 +0800181 }
182 debugfs_file_put(d);
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530183
184 bsize = simple_read_from_buffer(buff, count, ppos,
185 ilctxt->disabled?"1\n":"0\n", bsize);
186 ipc_log_context_put(ilctxt);
187 return bsize;
188}
189
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -0600190static ssize_t debug_read(struct file *file, char __user *buff,
191 size_t count, loff_t *ppos)
192{
193 return debug_read_helper(file, buff, count, ppos, 0);
194}
195
196static ssize_t debug_read_cont(struct file *file, char __user *buff,
197 size_t count, loff_t *ppos)
198{
199 return debug_read_helper(file, buff, count, ppos, 1);
200}
201
202static int debug_open(struct inode *inode, struct file *file)
203{
204 file->private_data = inode->i_private;
205 return 0;
206}
207
208static const struct file_operations debug_ops = {
209 .read = debug_read,
210 .open = debug_open,
211};
212
213static const struct file_operations debug_ops_cont = {
214 .read = debug_read_cont,
215 .open = debug_open,
216};
217
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530218static const struct file_operations debug_ops_ctrl = {
219 .read = debug_read_ctrl,
220 .write = debug_write_ctrl,
221 .open = debug_open,
222};
223
224static const struct file_operations debug_ops_ctrl_all = {
225 .write = debug_write_ctrl_all,
226};
227
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -0600228static void debug_create(const char *name, mode_t mode,
229 struct dentry *dent,
230 struct ipc_log_context *ilctxt,
231 const struct file_operations *fops)
232{
Lynus Vaz802d7382017-06-30 15:10:26 +0530233 debugfs_create_file_unsafe(name, mode, dent, ilctxt, fops);
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -0600234}
235
236static void dfunc_string(struct encode_context *ectxt,
237 struct decode_context *dctxt)
238{
239 tsv_timestamp_read(ectxt, dctxt, "");
240 tsv_qtimer_read(ectxt, dctxt, " ");
241 tsv_byte_array_read(ectxt, dctxt, "");
242
243 /* add trailing \n if necessary */
244 if (*(dctxt->buff - 1) != '\n') {
245 if (dctxt->size) {
246 ++dctxt->buff;
247 --dctxt->size;
248 }
249 *(dctxt->buff - 1) = '\n';
250 }
251}
252
253void check_and_create_debugfs(void)
254{
255 mutex_lock(&ipc_log_debugfs_init_lock);
256 if (!root_dent) {
257 root_dent = debugfs_create_dir("ipc_logging", 0);
258
259 if (IS_ERR(root_dent)) {
260 pr_err("%s: unable to create debugfs %ld\n",
261 __func__, PTR_ERR(root_dent));
262 root_dent = NULL;
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530263 } else {
264 debug_create("ctrl_all", 0444, root_dent,
265 NULL, &debug_ops_ctrl_all);
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -0600266 }
267 }
268 mutex_unlock(&ipc_log_debugfs_init_lock);
269}
270EXPORT_SYMBOL(check_and_create_debugfs);
271
272void create_ctx_debugfs(struct ipc_log_context *ctxt,
273 const char *mod_name)
274{
275 if (!root_dent)
276 check_and_create_debugfs();
277
278 if (root_dent) {
279 ctxt->dent = debugfs_create_dir(mod_name, root_dent);
280 if (!IS_ERR(ctxt->dent)) {
281 debug_create("log", 0444, ctxt->dent,
282 ctxt, &debug_ops);
283 debug_create("log_cont", 0444, ctxt->dent,
284 ctxt, &debug_ops_cont);
Dhoat Harpalf76b2362018-03-22 20:37:38 +0530285 debug_create("log_disable", 0444, ctxt->dent,
286 ctxt, &debug_ops_ctrl);
Karthikeyan Ramasubramanian44dc7702016-09-16 15:39:37 -0600287 }
288 }
289 add_deserialization_func((void *)ctxt,
290 TSV_TYPE_STRING, dfunc_string);
291}
292EXPORT_SYMBOL(create_ctx_debugfs);