linux/net/batman-adv/debugfs.c
<<
>>
Prefs
   1/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
   2 *
   3 * Marek Lindner
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of version 2 of the GNU General Public
   7 * License as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but
  10 * WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12 * General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17 * 02110-1301, USA
  18 */
  19
  20#include "main.h"
  21
  22#include <linux/debugfs.h>
  23
  24#include "debugfs.h"
  25#include "translation-table.h"
  26#include "originator.h"
  27#include "hard-interface.h"
  28#include "gateway_common.h"
  29#include "gateway_client.h"
  30#include "soft-interface.h"
  31#include "vis.h"
  32#include "icmp_socket.h"
  33#include "bridge_loop_avoidance.h"
  34
  35static struct dentry *batadv_debugfs;
  36
  37#ifdef CONFIG_BATMAN_ADV_DEBUG
  38#define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1)
  39
  40static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN;
  41
  42static char *batadv_log_char_addr(struct batadv_debug_log *debug_log,
  43                                  size_t idx)
  44{
  45        return &debug_log->log_buff[idx & BATADV_LOG_BUFF_MASK];
  46}
  47
  48static void batadv_emit_log_char(struct batadv_debug_log *debug_log, char c)
  49{
  50        char *char_addr;
  51
  52        char_addr = batadv_log_char_addr(debug_log, debug_log->log_end);
  53        *char_addr = c;
  54        debug_log->log_end++;
  55
  56        if (debug_log->log_end - debug_log->log_start > batadv_log_buff_len)
  57                debug_log->log_start = debug_log->log_end - batadv_log_buff_len;
  58}
  59
  60__printf(2, 3)
  61static int batadv_fdebug_log(struct batadv_debug_log *debug_log,
  62                             const char *fmt, ...)
  63{
  64        va_list args;
  65        static char debug_log_buf[256];
  66        char *p;
  67
  68        if (!debug_log)
  69                return 0;
  70
  71        spin_lock_bh(&debug_log->lock);
  72        va_start(args, fmt);
  73        vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args);
  74        va_end(args);
  75
  76        for (p = debug_log_buf; *p != 0; p++)
  77                batadv_emit_log_char(debug_log, *p);
  78
  79        spin_unlock_bh(&debug_log->lock);
  80
  81        wake_up(&debug_log->queue_wait);
  82
  83        return 0;
  84}
  85
  86int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
  87{
  88        va_list args;
  89        char tmp_log_buf[256];
  90
  91        va_start(args, fmt);
  92        vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
  93        batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s",
  94                          jiffies_to_msecs(jiffies), tmp_log_buf);
  95        va_end(args);
  96
  97        return 0;
  98}
  99
 100static int batadv_log_open(struct inode *inode, struct file *file)
 101{
 102        nonseekable_open(inode, file);
 103        file->private_data = inode->i_private;
 104        batadv_inc_module_count();
 105        return 0;
 106}
 107
 108static int batadv_log_release(struct inode *inode, struct file *file)
 109{
 110        batadv_dec_module_count();
 111        return 0;
 112}
 113
 114static int batadv_log_empty(struct batadv_debug_log *debug_log)
 115{
 116        return !(debug_log->log_start - debug_log->log_end);
 117}
 118
 119static ssize_t batadv_log_read(struct file *file, char __user *buf,
 120                               size_t count, loff_t *ppos)
 121{
 122        struct batadv_priv *bat_priv = file->private_data;
 123        struct batadv_debug_log *debug_log = bat_priv->debug_log;
 124        int error, i = 0;
 125        char *char_addr;
 126        char c;
 127
 128        if ((file->f_flags & O_NONBLOCK) && batadv_log_empty(debug_log))
 129                return -EAGAIN;
 130
 131        if (!buf)
 132                return -EINVAL;
 133
 134        if (count == 0)
 135                return 0;
 136
 137        if (!access_ok(VERIFY_WRITE, buf, count))
 138                return -EFAULT;
 139
 140        error = wait_event_interruptible(debug_log->queue_wait,
 141                                         (!batadv_log_empty(debug_log)));
 142
 143        if (error)
 144                return error;
 145
 146        spin_lock_bh(&debug_log->lock);
 147
 148        while ((!error) && (i < count) &&
 149               (debug_log->log_start != debug_log->log_end)) {
 150                char_addr = batadv_log_char_addr(debug_log,
 151                                                 debug_log->log_start);
 152                c = *char_addr;
 153
 154                debug_log->log_start++;
 155
 156                spin_unlock_bh(&debug_log->lock);
 157
 158                error = __put_user(c, buf);
 159
 160                spin_lock_bh(&debug_log->lock);
 161
 162                buf++;
 163                i++;
 164
 165        }
 166
 167        spin_unlock_bh(&debug_log->lock);
 168
 169        if (!error)
 170                return i;
 171
 172        return error;
 173}
 174
 175static unsigned int batadv_log_poll(struct file *file, poll_table *wait)
 176{
 177        struct batadv_priv *bat_priv = file->private_data;
 178        struct batadv_debug_log *debug_log = bat_priv->debug_log;
 179
 180        poll_wait(file, &debug_log->queue_wait, wait);
 181
 182        if (!batadv_log_empty(debug_log))
 183                return POLLIN | POLLRDNORM;
 184
 185        return 0;
 186}
 187
 188static const struct file_operations batadv_log_fops = {
 189        .open           = batadv_log_open,
 190        .release        = batadv_log_release,
 191        .read           = batadv_log_read,
 192        .poll           = batadv_log_poll,
 193        .llseek         = no_llseek,
 194};
 195
 196static int batadv_debug_log_setup(struct batadv_priv *bat_priv)
 197{
 198        struct dentry *d;
 199
 200        if (!bat_priv->debug_dir)
 201                goto err;
 202
 203        bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC);
 204        if (!bat_priv->debug_log)
 205                goto err;
 206
 207        spin_lock_init(&bat_priv->debug_log->lock);
 208        init_waitqueue_head(&bat_priv->debug_log->queue_wait);
 209
 210        d = debugfs_create_file("log", S_IFREG | S_IRUSR,
 211                                bat_priv->debug_dir, bat_priv,
 212                                &batadv_log_fops);
 213        if (!d)
 214                goto err;
 215
 216        return 0;
 217
 218err:
 219        return -ENOMEM;
 220}
 221
 222static void batadv_debug_log_cleanup(struct batadv_priv *bat_priv)
 223{
 224        kfree(bat_priv->debug_log);
 225        bat_priv->debug_log = NULL;
 226}
 227#else /* CONFIG_BATMAN_ADV_DEBUG */
 228static int batadv_debug_log_setup(struct batadv_priv *bat_priv)
 229{
 230        bat_priv->debug_log = NULL;
 231        return 0;
 232}
 233
 234static void batadv_debug_log_cleanup(struct batadv_priv *bat_priv)
 235{
 236        return;
 237}
 238#endif
 239
 240static int batadv_algorithms_open(struct inode *inode, struct file *file)
 241{
 242        return single_open(file, batadv_algo_seq_print_text, NULL);
 243}
 244
 245static int batadv_originators_open(struct inode *inode, struct file *file)
 246{
 247        struct net_device *net_dev = (struct net_device *)inode->i_private;
 248        return single_open(file, batadv_orig_seq_print_text, net_dev);
 249}
 250
 251static int batadv_gateways_open(struct inode *inode, struct file *file)
 252{
 253        struct net_device *net_dev = (struct net_device *)inode->i_private;
 254        return single_open(file, batadv_gw_client_seq_print_text, net_dev);
 255}
 256
 257static int batadv_transtable_global_open(struct inode *inode, struct file *file)
 258{
 259        struct net_device *net_dev = (struct net_device *)inode->i_private;
 260        return single_open(file, batadv_tt_global_seq_print_text, net_dev);
 261}
 262
 263#ifdef CONFIG_BATMAN_ADV_BLA
 264static int batadv_bla_claim_table_open(struct inode *inode, struct file *file)
 265{
 266        struct net_device *net_dev = (struct net_device *)inode->i_private;
 267        return single_open(file, batadv_bla_claim_table_seq_print_text,
 268                           net_dev);
 269}
 270#endif
 271
 272static int batadv_transtable_local_open(struct inode *inode, struct file *file)
 273{
 274        struct net_device *net_dev = (struct net_device *)inode->i_private;
 275        return single_open(file, batadv_tt_local_seq_print_text, net_dev);
 276}
 277
 278static int batadv_vis_data_open(struct inode *inode, struct file *file)
 279{
 280        struct net_device *net_dev = (struct net_device *)inode->i_private;
 281        return single_open(file, batadv_vis_seq_print_text, net_dev);
 282}
 283
 284struct batadv_debuginfo {
 285        struct attribute attr;
 286        const struct file_operations fops;
 287};
 288
 289#define BATADV_DEBUGINFO(_name, _mode, _open)           \
 290struct batadv_debuginfo batadv_debuginfo_##_name = {    \
 291        .attr = { .name = __stringify(_name),           \
 292                  .mode = _mode, },                     \
 293        .fops = { .owner = THIS_MODULE,                 \
 294                  .open = _open,                        \
 295                  .read = seq_read,                     \
 296                  .llseek = seq_lseek,                  \
 297                  .release = single_release,            \
 298                }                                       \
 299};
 300
 301static BATADV_DEBUGINFO(routing_algos, S_IRUGO, batadv_algorithms_open);
 302static BATADV_DEBUGINFO(originators, S_IRUGO, batadv_originators_open);
 303static BATADV_DEBUGINFO(gateways, S_IRUGO, batadv_gateways_open);
 304static BATADV_DEBUGINFO(transtable_global, S_IRUGO,
 305                        batadv_transtable_global_open);
 306#ifdef CONFIG_BATMAN_ADV_BLA
 307static BATADV_DEBUGINFO(bla_claim_table, S_IRUGO, batadv_bla_claim_table_open);
 308#endif
 309static BATADV_DEBUGINFO(transtable_local, S_IRUGO,
 310                        batadv_transtable_local_open);
 311static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open);
 312
 313static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
 314        &batadv_debuginfo_originators,
 315        &batadv_debuginfo_gateways,
 316        &batadv_debuginfo_transtable_global,
 317#ifdef CONFIG_BATMAN_ADV_BLA
 318        &batadv_debuginfo_bla_claim_table,
 319#endif
 320        &batadv_debuginfo_transtable_local,
 321        &batadv_debuginfo_vis_data,
 322        NULL,
 323};
 324
 325void batadv_debugfs_init(void)
 326{
 327        struct batadv_debuginfo *bat_debug;
 328        struct dentry *file;
 329
 330        batadv_debugfs = debugfs_create_dir(BATADV_DEBUGFS_SUBDIR, NULL);
 331        if (batadv_debugfs == ERR_PTR(-ENODEV))
 332                batadv_debugfs = NULL;
 333
 334        if (!batadv_debugfs)
 335                goto out;
 336
 337        bat_debug = &batadv_debuginfo_routing_algos;
 338        file = debugfs_create_file(bat_debug->attr.name,
 339                                   S_IFREG | bat_debug->attr.mode,
 340                                   batadv_debugfs, NULL, &bat_debug->fops);
 341        if (!file)
 342                pr_err("Can't add debugfs file: %s\n", bat_debug->attr.name);
 343
 344out:
 345        return;
 346}
 347
 348void batadv_debugfs_destroy(void)
 349{
 350        if (batadv_debugfs) {
 351                debugfs_remove_recursive(batadv_debugfs);
 352                batadv_debugfs = NULL;
 353        }
 354}
 355
 356int batadv_debugfs_add_meshif(struct net_device *dev)
 357{
 358        struct batadv_priv *bat_priv = netdev_priv(dev);
 359        struct batadv_debuginfo **bat_debug;
 360        struct dentry *file;
 361
 362        if (!batadv_debugfs)
 363                goto out;
 364
 365        bat_priv->debug_dir = debugfs_create_dir(dev->name, batadv_debugfs);
 366        if (!bat_priv->debug_dir)
 367                goto out;
 368
 369        if (batadv_socket_setup(bat_priv) < 0)
 370                goto rem_attr;
 371
 372        if (batadv_debug_log_setup(bat_priv) < 0)
 373                goto rem_attr;
 374
 375        for (bat_debug = batadv_mesh_debuginfos; *bat_debug; ++bat_debug) {
 376                file = debugfs_create_file(((*bat_debug)->attr).name,
 377                                           S_IFREG | ((*bat_debug)->attr).mode,
 378                                           bat_priv->debug_dir,
 379                                           dev, &(*bat_debug)->fops);
 380                if (!file) {
 381                        batadv_err(dev, "Can't add debugfs file: %s/%s\n",
 382                                   dev->name, ((*bat_debug)->attr).name);
 383                        goto rem_attr;
 384                }
 385        }
 386
 387        return 0;
 388rem_attr:
 389        debugfs_remove_recursive(bat_priv->debug_dir);
 390        bat_priv->debug_dir = NULL;
 391out:
 392#ifdef CONFIG_DEBUG_FS
 393        return -ENOMEM;
 394#else
 395        return 0;
 396#endif /* CONFIG_DEBUG_FS */
 397}
 398
 399void batadv_debugfs_del_meshif(struct net_device *dev)
 400{
 401        struct batadv_priv *bat_priv = netdev_priv(dev);
 402
 403        batadv_debug_log_cleanup(bat_priv);
 404
 405        if (batadv_debugfs) {
 406                debugfs_remove_recursive(bat_priv->debug_dir);
 407                bat_priv->debug_dir = NULL;
 408        }
 409}
 410
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.