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