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