1/* 2 * Copyright (C) 2010 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, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 * 02110-1301, USA 19 * 20 */ 21 22#include "main.h" 23 24#include <linux/debugfs.h> 25 26#include "bat_debugfs.h" 27#include "translation-table.h" 28#include "originator.h" 29#include "hard-interface.h" 30#include "vis.h" 31#include "icmp_socket.h" 32 33static struct dentry *bat_debugfs; 34 35#ifdef CONFIG_BATMAN_ADV_DEBUG 36#define LOG_BUFF_MASK (log_buff_len-1) 37#define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK]) 38 39static int log_buff_len = LOG_BUF_LEN; 40 41static void emit_log_char(struct debug_log *debug_log, char c) 42{ 43 LOG_BUFF(debug_log->log_end) = c; 44 debug_log->log_end++; 45 46 if (debug_log->log_end - debug_log->log_start > log_buff_len) 47 debug_log->log_start = debug_log->log_end - log_buff_len; 48} 49 50static int fdebug_log(struct debug_log *debug_log, char *fmt, ...) 51{ 52 int printed_len; 53 va_list args; 54 static char debug_log_buf[256]; 55 char *p; 56 unsigned long flags; 57 58 if (!debug_log) 59 return 0; 60 61 spin_lock_irqsave(&debug_log->lock, flags); 62 va_start(args, fmt); 63 printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), 64 fmt, args); 65 va_end(args); 66 67 for (p = debug_log_buf; *p != 0; p++) 68 emit_log_char(debug_log, *p); 69 70 spin_unlock_irqrestore(&debug_log->lock, flags); 71 72 wake_up(&debug_log->queue_wait); 73 74 return 0; 75} 76 77int debug_log(struct bat_priv *bat_priv, char *fmt, ...) 78{ 79 va_list args; 80 char tmp_log_buf[256]; 81 82 va_start(args, fmt); 83 vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); 84 fdebug_log(bat_priv->debug_log, "[%10u] %s", 85 (jiffies / HZ), tmp_log_buf); 86 va_end(args); 87 88 return 0; 89} 90 91static int log_open(struct inode *inode, struct file *file) 92{ 93 file->private_data = inode->i_private; 94 inc_module_count(); 95 return 0; 96} 97 98static int log_release(struct inode *inode, struct file *file) 99{ 100 dec_module_count(); 101 return 0; 102} 103 104static ssize_t log_read(struct file *file, char __user *buf, 105 size_t count, loff_t *ppos) 106{ 107 struct bat_priv *bat_priv = file->private_data; 108 struct debug_log *debug_log = bat_priv->debug_log; 109 int error, i = 0; 110 char c; 111 unsigned long flags; 112 113 if ((file->f_flags & O_NONBLOCK) && 114 !(debug_log->log_end - debug_log->log_start)) 115 return -EAGAIN; 116 117 if ((!buf) || (count < 0)) 118 return -EINVAL; 119 120 if (count == 0) 121 return 0; 122 123 if (!access_ok(VERIFY_WRITE, buf, count)) 124 return -EFAULT; 125 126 error = wait_event_interruptible(debug_log->queue_wait, 127 (debug_log->log_start - debug_log->log_end)); 128 129 if (error) 130 return error; 131 132 spin_lock_irqsave(&debug_log->lock, flags); 133 134 while ((!error) && (i < count) && 135 (debug_log->log_start != debug_log->log_end)) { 136 c = LOG_BUFF(debug_log->log_start); 137 138 debug_log->log_start++; 139 140 spin_unlock_irqrestore(&debug_log->lock, flags); 141 142 error = __put_user(c, buf); 143 144 spin_lock_irqsave(&debug_log->lock, flags); 145 146 buf++; 147 i++; 148 149 } 150 151 spin_unlock_irqrestore(&debug_log->lock, flags); 152 153 if (!error) 154 return i; 155 156 return error; 157} 158 159static unsigned int log_poll(struct file *file, poll_table *wait) 160{ 161 struct bat_priv *bat_priv = file->private_data; 162 struct debug_log *debug_log = bat_priv->debug_log; 163 164 poll_wait(file, &debug_log->queue_wait, wait); 165 166 if (debug_log->log_end - debug_log->log_start) 167 return POLLIN | POLLRDNORM; 168 169 return 0; 170} 171 172static const struct file_operations log_fops = { 173 .open = log_open, 174 .release = log_release, 175 .read = log_read, 176 .poll = log_poll, 177}; 178 179static int debug_log_setup(struct bat_priv *bat_priv) 180{ 181 struct dentry *d; 182 183 if (!bat_priv->debug_dir) 184 goto err; 185 186 bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC); 187 if (!bat_priv->debug_log) 188 goto err; 189 190 spin_lock_init(&bat_priv->debug_log->lock); 191 init_waitqueue_head(&bat_priv->debug_log->queue_wait); 192 193 d = debugfs_create_file("log", S_IFREG | S_IRUSR, 194 bat_priv->debug_dir, bat_priv, &log_fops); 195 if (d) 196 goto err; 197 198 return 0; 199 200err: 201 return 1; 202} 203 204static void debug_log_cleanup(struct bat_priv *bat_priv) 205{ 206 kfree(bat_priv->debug_log); 207 bat_priv->debug_log = NULL; 208} 209#else /* CONFIG_BATMAN_ADV_DEBUG */ 210static int debug_log_setup(struct bat_priv *bat_priv) 211{ 212 bat_priv->debug_log = NULL; 213 return 0; 214} 215 216static void debug_log_cleanup(struct bat_priv *bat_priv) 217{ 218 return; 219} 220#endif 221 222static int originators_open(struct inode *inode, struct file *file) 223{ 224 struct net_device *net_dev = (struct net_device *)inode->i_private; 225 return single_open(file, orig_seq_print_text, net_dev); 226} 227 228static int transtable_global_open(struct inode *inode, struct file *file) 229{ 230 struct net_device *net_dev = (struct net_device *)inode->i_private; 231 return single_open(file, hna_global_seq_print_text, net_dev); 232} 233 234static int transtable_local_open(struct inode *inode, struct file *file) 235{ 236 struct net_device *net_dev = (struct net_device *)inode->i_private; 237 return single_open(file, hna_local_seq_print_text, net_dev); 238} 239 240static int vis_data_open(struct inode *inode, struct file *file) 241{ 242 struct net_device *net_dev = (struct net_device *)inode->i_private; 243 return single_open(file, vis_seq_print_text, net_dev); 244} 245 246struct bat_debuginfo { 247 struct attribute attr; 248 const struct file_operations fops; 249}; 250 251#define BAT_DEBUGINFO(_name, _mode, _open) \ 252struct bat_debuginfo bat_debuginfo_##_name = { \ 253 .attr = { .name = __stringify(_name), \ 254 .mode = _mode, }, \ 255 .fops = { .owner = THIS_MODULE, \ 256 .open = _open, \ 257 .read = seq_read, \ 258 .llseek = seq_lseek, \ 259 .release = single_release, \ 260 } \ 261}; 262 263static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); 264static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); 265static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); 266static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); 267 268static struct bat_debuginfo *mesh_debuginfos[] = { 269 &bat_debuginfo_originators, 270 &bat_debuginfo_transtable_global, 271 &bat_debuginfo_transtable_local, 272 &bat_debuginfo_vis_data, 273 NULL, 274}; 275 276void debugfs_init(void) 277{ 278 bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL); 279 if (bat_debugfs == ERR_PTR(-ENODEV)) 280 bat_debugfs = NULL; 281} 282 283void debugfs_destroy(void) 284{ 285 if (bat_debugfs) { 286 debugfs_remove_recursive(bat_debugfs); 287 bat_debugfs = NULL; 288 } 289} 290 291int debugfs_add_meshif(struct net_device *dev) 292{ 293 struct bat_priv *bat_priv = netdev_priv(dev); 294 struct bat_debuginfo **bat_debug; 295 struct dentry *file; 296 297 if (!bat_debugfs) 298 goto out; 299 300 bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs); 301 if (!bat_priv->debug_dir) 302 goto out; 303 304 bat_socket_setup(bat_priv); 305 debug_log_setup(bat_priv); 306 307 for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) { 308 file = debugfs_create_file(((*bat_debug)->attr).name, 309 S_IFREG | ((*bat_debug)->attr).mode, 310 bat_priv->debug_dir, 311 dev, &(*bat_debug)->fops); 312 if (!file) { 313 bat_err(dev, "Can't add debugfs file: %s/%s\n", 314 dev->name, ((*bat_debug)->attr).name); 315 goto rem_attr; 316 } 317 } 318 319 return 0; 320rem_attr: 321 debugfs_remove_recursive(bat_priv->debug_dir); 322 bat_priv->debug_dir = NULL; 323out: 324#ifdef CONFIG_DEBUG_FS 325 return -ENOMEM; 326#else 327 return 0; 328#endif /* CONFIG_DEBUG_FS */ 329} 330 331void debugfs_del_meshif(struct net_device *dev) 332{ 333 struct bat_priv *bat_priv = netdev_priv(dev); 334 335 debug_log_cleanup(bat_priv); 336 337 if (bat_debugfs) { 338 debugfs_remove_recursive(bat_priv->debug_dir); 339 bat_priv->debug_dir = NULL; 340 } 341} 342