xref: /linux/net/batman-adv/log.c (revision 48881ed56b395bdf2cff6c102039016223ca4da6)
17db7d9f3SSven 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>
25*48881ed5SSven Eckelmann #include <linux/eventpoll.h>
26ba412080SSven Eckelmann #include <linux/export.h>
27ba412080SSven Eckelmann #include <linux/fcntl.h>
28ba412080SSven Eckelmann #include <linux/fs.h>
29b92b94acSSven Eckelmann #include <linux/gfp.h>
30ba412080SSven Eckelmann #include <linux/jiffies.h>
31ba412080SSven Eckelmann #include <linux/kernel.h>
32ba412080SSven Eckelmann #include <linux/module.h>
33ba412080SSven Eckelmann #include <linux/poll.h>
34ba412080SSven Eckelmann #include <linux/sched.h> /* for linux/wait.h */
35ba412080SSven Eckelmann #include <linux/slab.h>
36ba412080SSven Eckelmann #include <linux/spinlock.h>
37ba412080SSven Eckelmann #include <linux/stddef.h>
38ba412080SSven Eckelmann #include <linux/types.h>
39ba412080SSven Eckelmann #include <linux/uaccess.h>
40ba412080SSven Eckelmann #include <linux/wait.h>
41ba412080SSven Eckelmann #include <stdarg.h>
42ba412080SSven Eckelmann 
43ba412080SSven Eckelmann #define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1)
44ba412080SSven Eckelmann 
45ba412080SSven Eckelmann static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN;
46ba412080SSven Eckelmann 
47ba412080SSven Eckelmann static char *batadv_log_char_addr(struct batadv_priv_debug_log *debug_log,
48ba412080SSven Eckelmann 				  size_t idx)
49ba412080SSven Eckelmann {
50ba412080SSven Eckelmann 	return &debug_log->log_buff[idx & BATADV_LOG_BUFF_MASK];
51ba412080SSven Eckelmann }
52ba412080SSven Eckelmann 
53ba412080SSven Eckelmann static void batadv_emit_log_char(struct batadv_priv_debug_log *debug_log,
54ba412080SSven Eckelmann 				 char c)
55ba412080SSven Eckelmann {
56ba412080SSven Eckelmann 	char *char_addr;
57ba412080SSven Eckelmann 
58ba412080SSven Eckelmann 	char_addr = batadv_log_char_addr(debug_log, debug_log->log_end);
59ba412080SSven Eckelmann 	*char_addr = c;
60ba412080SSven Eckelmann 	debug_log->log_end++;
61ba412080SSven Eckelmann 
62ba412080SSven Eckelmann 	if (debug_log->log_end - debug_log->log_start > batadv_log_buff_len)
63ba412080SSven Eckelmann 		debug_log->log_start = debug_log->log_end - batadv_log_buff_len;
64ba412080SSven Eckelmann }
65ba412080SSven Eckelmann 
66ba412080SSven Eckelmann __printf(2, 3)
67ba412080SSven Eckelmann static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log,
68ba412080SSven Eckelmann 			     const char *fmt, ...)
69ba412080SSven Eckelmann {
70ba412080SSven Eckelmann 	va_list args;
71ba412080SSven Eckelmann 	static char debug_log_buf[256];
72ba412080SSven Eckelmann 	char *p;
73ba412080SSven Eckelmann 
74ba412080SSven Eckelmann 	if (!debug_log)
75ba412080SSven Eckelmann 		return 0;
76ba412080SSven Eckelmann 
77ba412080SSven Eckelmann 	spin_lock_bh(&debug_log->lock);
78ba412080SSven Eckelmann 	va_start(args, fmt);
79ba412080SSven Eckelmann 	vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args);
80ba412080SSven Eckelmann 	va_end(args);
81ba412080SSven Eckelmann 
82ba412080SSven Eckelmann 	for (p = debug_log_buf; *p != 0; p++)
83ba412080SSven Eckelmann 		batadv_emit_log_char(debug_log, *p);
84ba412080SSven Eckelmann 
85ba412080SSven Eckelmann 	spin_unlock_bh(&debug_log->lock);
86ba412080SSven Eckelmann 
87ba412080SSven Eckelmann 	wake_up(&debug_log->queue_wait);
88ba412080SSven Eckelmann 
89ba412080SSven Eckelmann 	return 0;
90ba412080SSven Eckelmann }
91ba412080SSven Eckelmann 
92ff15c27cSSven Eckelmann /**
93ff15c27cSSven Eckelmann  * batadv_debug_log() - Add debug log entry
94ff15c27cSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
95ff15c27cSSven Eckelmann  * @fmt: format string
96ff15c27cSSven Eckelmann  *
97ff15c27cSSven Eckelmann  * Return: 0 on success or negative error number in case of failure
98ff15c27cSSven Eckelmann  */
99ba412080SSven Eckelmann int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
100ba412080SSven Eckelmann {
101ba412080SSven Eckelmann 	va_list args;
102ba412080SSven Eckelmann 	char tmp_log_buf[256];
103ba412080SSven Eckelmann 
104ba412080SSven Eckelmann 	va_start(args, fmt);
105ba412080SSven Eckelmann 	vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
106ba412080SSven Eckelmann 	batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s",
107ba412080SSven Eckelmann 			  jiffies_to_msecs(jiffies), tmp_log_buf);
108ba412080SSven Eckelmann 	va_end(args);
109ba412080SSven Eckelmann 
110ba412080SSven Eckelmann 	return 0;
111ba412080SSven Eckelmann }
112ba412080SSven Eckelmann 
113ba412080SSven Eckelmann static int batadv_log_open(struct inode *inode, struct file *file)
114ba412080SSven Eckelmann {
115ba412080SSven Eckelmann 	if (!try_module_get(THIS_MODULE))
116ba412080SSven Eckelmann 		return -EBUSY;
117ba412080SSven Eckelmann 
118ba412080SSven Eckelmann 	nonseekable_open(inode, file);
119ba412080SSven Eckelmann 	file->private_data = inode->i_private;
120ba412080SSven Eckelmann 	return 0;
121ba412080SSven Eckelmann }
122ba412080SSven Eckelmann 
123ba412080SSven Eckelmann static int batadv_log_release(struct inode *inode, struct file *file)
124ba412080SSven Eckelmann {
125ba412080SSven Eckelmann 	module_put(THIS_MODULE);
126ba412080SSven Eckelmann 	return 0;
127ba412080SSven Eckelmann }
128ba412080SSven Eckelmann 
129ba412080SSven Eckelmann static bool batadv_log_empty(struct batadv_priv_debug_log *debug_log)
130ba412080SSven Eckelmann {
131ba412080SSven Eckelmann 	return !(debug_log->log_start - debug_log->log_end);
132ba412080SSven Eckelmann }
133ba412080SSven Eckelmann 
134ba412080SSven Eckelmann static ssize_t batadv_log_read(struct file *file, char __user *buf,
135ba412080SSven Eckelmann 			       size_t count, loff_t *ppos)
136ba412080SSven Eckelmann {
137ba412080SSven Eckelmann 	struct batadv_priv *bat_priv = file->private_data;
138ba412080SSven Eckelmann 	struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
139ba412080SSven Eckelmann 	int error, i = 0;
140ba412080SSven Eckelmann 	char *char_addr;
141ba412080SSven Eckelmann 	char c;
142ba412080SSven Eckelmann 
143ba412080SSven Eckelmann 	if ((file->f_flags & O_NONBLOCK) && batadv_log_empty(debug_log))
144ba412080SSven Eckelmann 		return -EAGAIN;
145ba412080SSven Eckelmann 
146ba412080SSven Eckelmann 	if (!buf)
147ba412080SSven Eckelmann 		return -EINVAL;
148ba412080SSven Eckelmann 
149ba412080SSven Eckelmann 	if (count == 0)
150ba412080SSven Eckelmann 		return 0;
151ba412080SSven Eckelmann 
152ba412080SSven Eckelmann 	if (!access_ok(VERIFY_WRITE, buf, count))
153ba412080SSven Eckelmann 		return -EFAULT;
154ba412080SSven Eckelmann 
155ba412080SSven Eckelmann 	error = wait_event_interruptible(debug_log->queue_wait,
156ba412080SSven Eckelmann 					 (!batadv_log_empty(debug_log)));
157ba412080SSven Eckelmann 
158ba412080SSven Eckelmann 	if (error)
159ba412080SSven Eckelmann 		return error;
160ba412080SSven Eckelmann 
161ba412080SSven Eckelmann 	spin_lock_bh(&debug_log->lock);
162ba412080SSven Eckelmann 
163ba412080SSven Eckelmann 	while ((!error) && (i < count) &&
164ba412080SSven Eckelmann 	       (debug_log->log_start != debug_log->log_end)) {
165ba412080SSven Eckelmann 		char_addr = batadv_log_char_addr(debug_log,
166ba412080SSven Eckelmann 						 debug_log->log_start);
167ba412080SSven Eckelmann 		c = *char_addr;
168ba412080SSven Eckelmann 
169ba412080SSven Eckelmann 		debug_log->log_start++;
170ba412080SSven Eckelmann 
171ba412080SSven Eckelmann 		spin_unlock_bh(&debug_log->lock);
172ba412080SSven Eckelmann 
173ba412080SSven Eckelmann 		error = __put_user(c, buf);
174ba412080SSven Eckelmann 
175ba412080SSven Eckelmann 		spin_lock_bh(&debug_log->lock);
176ba412080SSven Eckelmann 
177ba412080SSven Eckelmann 		buf++;
178ba412080SSven Eckelmann 		i++;
179ba412080SSven Eckelmann 	}
180ba412080SSven Eckelmann 
181ba412080SSven Eckelmann 	spin_unlock_bh(&debug_log->lock);
182ba412080SSven Eckelmann 
183ba412080SSven Eckelmann 	if (!error)
184ba412080SSven Eckelmann 		return i;
185ba412080SSven Eckelmann 
186ba412080SSven Eckelmann 	return error;
187ba412080SSven Eckelmann }
188ba412080SSven Eckelmann 
189ade994f4SAl Viro static __poll_t batadv_log_poll(struct file *file, poll_table *wait)
190ba412080SSven Eckelmann {
191ba412080SSven Eckelmann 	struct batadv_priv *bat_priv = file->private_data;
192ba412080SSven Eckelmann 	struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
193ba412080SSven Eckelmann 
194ba412080SSven Eckelmann 	poll_wait(file, &debug_log->queue_wait, wait);
195ba412080SSven Eckelmann 
196ba412080SSven Eckelmann 	if (!batadv_log_empty(debug_log))
197a9a08845SLinus Torvalds 		return EPOLLIN | EPOLLRDNORM;
198ba412080SSven Eckelmann 
199ba412080SSven Eckelmann 	return 0;
200ba412080SSven Eckelmann }
201ba412080SSven Eckelmann 
202ba412080SSven Eckelmann static const struct file_operations batadv_log_fops = {
203ba412080SSven Eckelmann 	.open           = batadv_log_open,
204ba412080SSven Eckelmann 	.release        = batadv_log_release,
205ba412080SSven Eckelmann 	.read           = batadv_log_read,
206ba412080SSven Eckelmann 	.poll           = batadv_log_poll,
207ba412080SSven Eckelmann 	.llseek         = no_llseek,
208ba412080SSven Eckelmann };
209ba412080SSven Eckelmann 
210ff15c27cSSven Eckelmann /**
211ff15c27cSSven Eckelmann  * batadv_debug_log_setup() - Initialize debug log
212ff15c27cSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
213ff15c27cSSven Eckelmann  *
214ff15c27cSSven Eckelmann  * Return: 0 on success or negative error number in case of failure
215ff15c27cSSven Eckelmann  */
216ba412080SSven Eckelmann int batadv_debug_log_setup(struct batadv_priv *bat_priv)
217ba412080SSven Eckelmann {
218ba412080SSven Eckelmann 	struct dentry *d;
219ba412080SSven Eckelmann 
220ba412080SSven Eckelmann 	if (!bat_priv->debug_dir)
221ba412080SSven Eckelmann 		goto err;
222ba412080SSven Eckelmann 
223ba412080SSven Eckelmann 	bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC);
224ba412080SSven Eckelmann 	if (!bat_priv->debug_log)
225ba412080SSven Eckelmann 		goto err;
226ba412080SSven Eckelmann 
227ba412080SSven Eckelmann 	spin_lock_init(&bat_priv->debug_log->lock);
228ba412080SSven Eckelmann 	init_waitqueue_head(&bat_priv->debug_log->queue_wait);
229ba412080SSven Eckelmann 
230507b37cfSSven Eckelmann 	d = debugfs_create_file("log", 0400, bat_priv->debug_dir, bat_priv,
231ba412080SSven Eckelmann 				&batadv_log_fops);
232ba412080SSven Eckelmann 	if (!d)
233ba412080SSven Eckelmann 		goto err;
234ba412080SSven Eckelmann 
235ba412080SSven Eckelmann 	return 0;
236ba412080SSven Eckelmann 
237ba412080SSven Eckelmann err:
238ba412080SSven Eckelmann 	return -ENOMEM;
239ba412080SSven Eckelmann }
240ba412080SSven Eckelmann 
241ff15c27cSSven Eckelmann /**
242ff15c27cSSven Eckelmann  * batadv_debug_log_cleanup() - Destroy debug log
243ff15c27cSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
244ff15c27cSSven Eckelmann  */
245ba412080SSven Eckelmann void batadv_debug_log_cleanup(struct batadv_priv *bat_priv)
246ba412080SSven Eckelmann {
247ba412080SSven Eckelmann 	kfree(bat_priv->debug_log);
248ba412080SSven Eckelmann 	bat_priv->debug_log = NULL;
249ba412080SSven Eckelmann }
250