at v3.2 359 lines 8.5 kB view raw
1/* 2 * Copyright (C) 2010-2011 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 originators_open(struct inode *inode, struct file *file) 225{ 226 struct net_device *net_dev = (struct net_device *)inode->i_private; 227 return single_open(file, orig_seq_print_text, net_dev); 228} 229 230static int gateways_open(struct inode *inode, struct file *file) 231{ 232 struct net_device *net_dev = (struct net_device *)inode->i_private; 233 return single_open(file, gw_client_seq_print_text, net_dev); 234} 235 236static int softif_neigh_open(struct inode *inode, struct file *file) 237{ 238 struct net_device *net_dev = (struct net_device *)inode->i_private; 239 return single_open(file, softif_neigh_seq_print_text, net_dev); 240} 241 242static int transtable_global_open(struct inode *inode, struct file *file) 243{ 244 struct net_device *net_dev = (struct net_device *)inode->i_private; 245 return single_open(file, tt_global_seq_print_text, net_dev); 246} 247 248static int transtable_local_open(struct inode *inode, struct file *file) 249{ 250 struct net_device *net_dev = (struct net_device *)inode->i_private; 251 return single_open(file, tt_local_seq_print_text, net_dev); 252} 253 254static int vis_data_open(struct inode *inode, struct file *file) 255{ 256 struct net_device *net_dev = (struct net_device *)inode->i_private; 257 return single_open(file, vis_seq_print_text, net_dev); 258} 259 260struct bat_debuginfo { 261 struct attribute attr; 262 const struct file_operations fops; 263}; 264 265#define BAT_DEBUGINFO(_name, _mode, _open) \ 266struct bat_debuginfo bat_debuginfo_##_name = { \ 267 .attr = { .name = __stringify(_name), \ 268 .mode = _mode, }, \ 269 .fops = { .owner = THIS_MODULE, \ 270 .open = _open, \ 271 .read = seq_read, \ 272 .llseek = seq_lseek, \ 273 .release = single_release, \ 274 } \ 275}; 276 277static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); 278static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); 279static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); 280static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); 281static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); 282static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); 283 284static struct bat_debuginfo *mesh_debuginfos[] = { 285 &bat_debuginfo_originators, 286 &bat_debuginfo_gateways, 287 &bat_debuginfo_softif_neigh, 288 &bat_debuginfo_transtable_global, 289 &bat_debuginfo_transtable_local, 290 &bat_debuginfo_vis_data, 291 NULL, 292}; 293 294void debugfs_init(void) 295{ 296 bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL); 297 if (bat_debugfs == ERR_PTR(-ENODEV)) 298 bat_debugfs = NULL; 299} 300 301void debugfs_destroy(void) 302{ 303 if (bat_debugfs) { 304 debugfs_remove_recursive(bat_debugfs); 305 bat_debugfs = NULL; 306 } 307} 308 309int debugfs_add_meshif(struct net_device *dev) 310{ 311 struct bat_priv *bat_priv = netdev_priv(dev); 312 struct bat_debuginfo **bat_debug; 313 struct dentry *file; 314 315 if (!bat_debugfs) 316 goto out; 317 318 bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs); 319 if (!bat_priv->debug_dir) 320 goto out; 321 322 bat_socket_setup(bat_priv); 323 debug_log_setup(bat_priv); 324 325 for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) { 326 file = debugfs_create_file(((*bat_debug)->attr).name, 327 S_IFREG | ((*bat_debug)->attr).mode, 328 bat_priv->debug_dir, 329 dev, &(*bat_debug)->fops); 330 if (!file) { 331 bat_err(dev, "Can't add debugfs file: %s/%s\n", 332 dev->name, ((*bat_debug)->attr).name); 333 goto rem_attr; 334 } 335 } 336 337 return 0; 338rem_attr: 339 debugfs_remove_recursive(bat_priv->debug_dir); 340 bat_priv->debug_dir = NULL; 341out: 342#ifdef CONFIG_DEBUG_FS 343 return -ENOMEM; 344#else 345 return 0; 346#endif /* CONFIG_DEBUG_FS */ 347} 348 349void debugfs_del_meshif(struct net_device *dev) 350{ 351 struct bat_priv *bat_priv = netdev_priv(dev); 352 353 debug_log_cleanup(bat_priv); 354 355 if (bat_debugfs) { 356 debugfs_remove_recursive(bat_priv->debug_dir); 357 bat_priv->debug_dir = NULL; 358 } 359}