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