xref: /linux/net/batman-adv/log.c (revision 7db7d9f369a47e1a46f93c320b45cb89e81723e7)
1*7db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
2ac79cbb9SSven Eckelmann /* Copyright (C) 2010-2017  B.A.T.M.A.N. contributors:
3ba412080SSven Eckelmann  *
4ba412080SSven Eckelmann  * Marek Lindner
5ba412080SSven Eckelmann  *
6ba412080SSven Eckelmann  * This program is free software; you can redistribute it and/or
7ba412080SSven Eckelmann  * modify it under the terms of version 2 of the GNU General Public
8ba412080SSven Eckelmann  * License as published by the Free Software Foundation.
9ba412080SSven Eckelmann  *
10ba412080SSven Eckelmann  * This program is distributed in the hope that it will be useful, but
11ba412080SSven Eckelmann  * WITHOUT ANY WARRANTY; without even the implied warranty of
12ba412080SSven Eckelmann  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13ba412080SSven Eckelmann  * General Public License for more details.
14ba412080SSven Eckelmann  *
15ba412080SSven Eckelmann  * You should have received a copy of the GNU General Public License
16ba412080SSven Eckelmann  * along with this program; if not, see <http://www.gnu.org/licenses/>.
17ba412080SSven Eckelmann  */
18ba412080SSven Eckelmann 
19ba412080SSven Eckelmann #include "log.h"
20ba412080SSven Eckelmann #include "main.h"
21ba412080SSven Eckelmann 
22ba412080SSven Eckelmann #include <linux/compiler.h>
23ba412080SSven Eckelmann #include <linux/debugfs.h>
24ba412080SSven Eckelmann #include <linux/errno.h>
25ba412080SSven Eckelmann #include <linux/export.h>
26ba412080SSven Eckelmann #include <linux/fcntl.h>
27ba412080SSven Eckelmann #include <linux/fs.h>
28ba412080SSven Eckelmann #include <linux/jiffies.h>
29ba412080SSven Eckelmann #include <linux/kernel.h>
30ba412080SSven Eckelmann #include <linux/module.h>
31ba412080SSven Eckelmann #include <linux/poll.h>
32ba412080SSven Eckelmann #include <linux/sched.h> /* for linux/wait.h */
33ba412080SSven Eckelmann #include <linux/slab.h>
34ba412080SSven Eckelmann #include <linux/spinlock.h>
35ba412080SSven Eckelmann #include <linux/stddef.h>
36ba412080SSven Eckelmann #include <linux/types.h>
37ba412080SSven Eckelmann #include <linux/uaccess.h>
38ba412080SSven Eckelmann #include <linux/wait.h>
39ba412080SSven Eckelmann #include <stdarg.h>
40ba412080SSven Eckelmann 
41ba412080SSven Eckelmann #define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1)
42ba412080SSven Eckelmann 
43ba412080SSven Eckelmann static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN;
44ba412080SSven Eckelmann 
45ba412080SSven Eckelmann static char *batadv_log_char_addr(struct batadv_priv_debug_log *debug_log,
46ba412080SSven Eckelmann 				  size_t idx)
47ba412080SSven Eckelmann {
48ba412080SSven Eckelmann 	return &debug_log->log_buff[idx & BATADV_LOG_BUFF_MASK];
49ba412080SSven Eckelmann }
50ba412080SSven Eckelmann 
51ba412080SSven Eckelmann static void batadv_emit_log_char(struct batadv_priv_debug_log *debug_log,
52ba412080SSven Eckelmann 				 char c)
53ba412080SSven Eckelmann {
54ba412080SSven Eckelmann 	char *char_addr;
55ba412080SSven Eckelmann 
56ba412080SSven Eckelmann 	char_addr = batadv_log_char_addr(debug_log, debug_log->log_end);
57ba412080SSven Eckelmann 	*char_addr = c;
58ba412080SSven Eckelmann 	debug_log->log_end++;
59ba412080SSven Eckelmann 
60ba412080SSven Eckelmann 	if (debug_log->log_end - debug_log->log_start > batadv_log_buff_len)
61ba412080SSven Eckelmann 		debug_log->log_start = debug_log->log_end - batadv_log_buff_len;
62ba412080SSven Eckelmann }
63ba412080SSven Eckelmann 
64ba412080SSven Eckelmann __printf(2, 3)
65ba412080SSven Eckelmann static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log,
66ba412080SSven Eckelmann 			     const char *fmt, ...)
67ba412080SSven Eckelmann {
68ba412080SSven Eckelmann 	va_list args;
69ba412080SSven Eckelmann 	static char debug_log_buf[256];
70ba412080SSven Eckelmann 	char *p;
71ba412080SSven Eckelmann 
72ba412080SSven Eckelmann 	if (!debug_log)
73ba412080SSven Eckelmann 		return 0;
74ba412080SSven Eckelmann 
75ba412080SSven Eckelmann 	spin_lock_bh(&debug_log->lock);
76ba412080SSven Eckelmann 	va_start(args, fmt);
77ba412080SSven Eckelmann 	vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args);
78ba412080SSven Eckelmann 	va_end(args);
79ba412080SSven Eckelmann 
80ba412080SSven Eckelmann 	for (p = debug_log_buf; *p != 0; p++)
81ba412080SSven Eckelmann 		batadv_emit_log_char(debug_log, *p);
82ba412080SSven Eckelmann 
83ba412080SSven Eckelmann 	spin_unlock_bh(&debug_log->lock);
84ba412080SSven Eckelmann 
85ba412080SSven Eckelmann 	wake_up(&debug_log->queue_wait);
86ba412080SSven Eckelmann 
87ba412080SSven Eckelmann 	return 0;
88ba412080SSven Eckelmann }
89ba412080SSven Eckelmann 
90ba412080SSven Eckelmann int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
91ba412080SSven Eckelmann {
92ba412080SSven Eckelmann 	va_list args;
93ba412080SSven Eckelmann 	char tmp_log_buf[256];
94ba412080SSven Eckelmann 
95ba412080SSven Eckelmann 	va_start(args, fmt);
96ba412080SSven Eckelmann 	vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
97ba412080SSven Eckelmann 	batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s",
98ba412080SSven Eckelmann 			  jiffies_to_msecs(jiffies), tmp_log_buf);
99ba412080SSven Eckelmann 	va_end(args);
100ba412080SSven Eckelmann 
101ba412080SSven Eckelmann 	return 0;
102ba412080SSven Eckelmann }
103ba412080SSven Eckelmann 
104ba412080SSven Eckelmann static int batadv_log_open(struct inode *inode, struct file *file)
105ba412080SSven Eckelmann {
106ba412080SSven Eckelmann 	if (!try_module_get(THIS_MODULE))
107ba412080SSven Eckelmann 		return -EBUSY;
108ba412080SSven Eckelmann 
109ba412080SSven Eckelmann 	nonseekable_open(inode, file);
110ba412080SSven Eckelmann 	file->private_data = inode->i_private;
111ba412080SSven Eckelmann 	return 0;
112ba412080SSven Eckelmann }
113ba412080SSven Eckelmann 
114ba412080SSven Eckelmann static int batadv_log_release(struct inode *inode, struct file *file)
115ba412080SSven Eckelmann {
116ba412080SSven Eckelmann 	module_put(THIS_MODULE);
117ba412080SSven Eckelmann 	return 0;
118ba412080SSven Eckelmann }
119ba412080SSven Eckelmann 
120ba412080SSven Eckelmann static bool batadv_log_empty(struct batadv_priv_debug_log *debug_log)
121ba412080SSven Eckelmann {
122ba412080SSven Eckelmann 	return !(debug_log->log_start - debug_log->log_end);
123ba412080SSven Eckelmann }
124ba412080SSven Eckelmann 
125ba412080SSven Eckelmann static ssize_t batadv_log_read(struct file *file, char __user *buf,
126ba412080SSven Eckelmann 			       size_t count, loff_t *ppos)
127ba412080SSven Eckelmann {
128ba412080SSven Eckelmann 	struct batadv_priv *bat_priv = file->private_data;
129ba412080SSven Eckelmann 	struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
130ba412080SSven Eckelmann 	int error, i = 0;
131ba412080SSven Eckelmann 	char *char_addr;
132ba412080SSven Eckelmann 	char c;
133ba412080SSven Eckelmann 
134ba412080SSven Eckelmann 	if ((file->f_flags & O_NONBLOCK) && batadv_log_empty(debug_log))
135ba412080SSven Eckelmann 		return -EAGAIN;
136ba412080SSven Eckelmann 
137ba412080SSven Eckelmann 	if (!buf)
138ba412080SSven Eckelmann 		return -EINVAL;
139ba412080SSven Eckelmann 
140ba412080SSven Eckelmann 	if (count == 0)
141ba412080SSven Eckelmann 		return 0;
142ba412080SSven Eckelmann 
143ba412080SSven Eckelmann 	if (!access_ok(VERIFY_WRITE, buf, count))
144ba412080SSven Eckelmann 		return -EFAULT;
145ba412080SSven Eckelmann 
146ba412080SSven Eckelmann 	error = wait_event_interruptible(debug_log->queue_wait,
147ba412080SSven Eckelmann 					 (!batadv_log_empty(debug_log)));
148ba412080SSven Eckelmann 
149ba412080SSven Eckelmann 	if (error)
150ba412080SSven Eckelmann 		return error;
151ba412080SSven Eckelmann 
152ba412080SSven Eckelmann 	spin_lock_bh(&debug_log->lock);
153ba412080SSven Eckelmann 
154ba412080SSven Eckelmann 	while ((!error) && (i < count) &&
155ba412080SSven Eckelmann 	       (debug_log->log_start != debug_log->log_end)) {
156ba412080SSven Eckelmann 		char_addr = batadv_log_char_addr(debug_log,
157ba412080SSven Eckelmann 						 debug_log->log_start);
158ba412080SSven Eckelmann 		c = *char_addr;
159ba412080SSven Eckelmann 
160ba412080SSven Eckelmann 		debug_log->log_start++;
161ba412080SSven Eckelmann 
162ba412080SSven Eckelmann 		spin_unlock_bh(&debug_log->lock);
163ba412080SSven Eckelmann 
164ba412080SSven Eckelmann 		error = __put_user(c, buf);
165ba412080SSven Eckelmann 
166ba412080SSven Eckelmann 		spin_lock_bh(&debug_log->lock);
167ba412080SSven Eckelmann 
168ba412080SSven Eckelmann 		buf++;
169ba412080SSven Eckelmann 		i++;
170ba412080SSven Eckelmann 	}
171ba412080SSven Eckelmann 
172ba412080SSven Eckelmann 	spin_unlock_bh(&debug_log->lock);
173ba412080SSven Eckelmann 
174ba412080SSven Eckelmann 	if (!error)
175ba412080SSven Eckelmann 		return i;
176ba412080SSven Eckelmann 
177ba412080SSven Eckelmann 	return error;
178ba412080SSven Eckelmann }
179ba412080SSven Eckelmann 
180ba412080SSven Eckelmann static unsigned int batadv_log_poll(struct file *file, poll_table *wait)
181ba412080SSven Eckelmann {
182ba412080SSven Eckelmann 	struct batadv_priv *bat_priv = file->private_data;
183ba412080SSven Eckelmann 	struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
184ba412080SSven Eckelmann 
185ba412080SSven Eckelmann 	poll_wait(file, &debug_log->queue_wait, wait);
186ba412080SSven Eckelmann 
187ba412080SSven Eckelmann 	if (!batadv_log_empty(debug_log))
188ba412080SSven Eckelmann 		return POLLIN | POLLRDNORM;
189ba412080SSven Eckelmann 
190ba412080SSven Eckelmann 	return 0;
191ba412080SSven Eckelmann }
192ba412080SSven Eckelmann 
193ba412080SSven Eckelmann static const struct file_operations batadv_log_fops = {
194ba412080SSven Eckelmann 	.open           = batadv_log_open,
195ba412080SSven Eckelmann 	.release        = batadv_log_release,
196ba412080SSven Eckelmann 	.read           = batadv_log_read,
197ba412080SSven Eckelmann 	.poll           = batadv_log_poll,
198ba412080SSven Eckelmann 	.llseek         = no_llseek,
199ba412080SSven Eckelmann };
200ba412080SSven Eckelmann 
201ba412080SSven Eckelmann int batadv_debug_log_setup(struct batadv_priv *bat_priv)
202ba412080SSven Eckelmann {
203ba412080SSven Eckelmann 	struct dentry *d;
204ba412080SSven Eckelmann 
205ba412080SSven Eckelmann 	if (!bat_priv->debug_dir)
206ba412080SSven Eckelmann 		goto err;
207ba412080SSven Eckelmann 
208ba412080SSven Eckelmann 	bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC);
209ba412080SSven Eckelmann 	if (!bat_priv->debug_log)
210ba412080SSven Eckelmann 		goto err;
211ba412080SSven Eckelmann 
212ba412080SSven Eckelmann 	spin_lock_init(&bat_priv->debug_log->lock);
213ba412080SSven Eckelmann 	init_waitqueue_head(&bat_priv->debug_log->queue_wait);
214ba412080SSven Eckelmann 
215507b37cfSSven Eckelmann 	d = debugfs_create_file("log", 0400, bat_priv->debug_dir, bat_priv,
216ba412080SSven Eckelmann 				&batadv_log_fops);
217ba412080SSven Eckelmann 	if (!d)
218ba412080SSven Eckelmann 		goto err;
219ba412080SSven Eckelmann 
220ba412080SSven Eckelmann 	return 0;
221ba412080SSven Eckelmann 
222ba412080SSven Eckelmann err:
223ba412080SSven Eckelmann 	return -ENOMEM;
224ba412080SSven Eckelmann }
225ba412080SSven Eckelmann 
226ba412080SSven Eckelmann void batadv_debug_log_cleanup(struct batadv_priv *bat_priv)
227ba412080SSven Eckelmann {
228ba412080SSven Eckelmann 	kfree(bat_priv->debug_log);
229ba412080SSven Eckelmann 	bat_priv->debug_log = NULL;
230ba412080SSven Eckelmann }
231