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