linux/net/batman-adv/bat_debugfs.c
<<
>>
Prefs
   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}
 382