linux/net/batman-adv/log.c
<<
>>
Prefs
   1/* Copyright (C) 2010-2016  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, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18#include "log.h"
  19#include "main.h"
  20
  21#include <linux/compiler.h>
  22#include <linux/debugfs.h>
  23#include <linux/errno.h>
  24#include <linux/export.h>
  25#include <linux/fcntl.h>
  26#include <linux/fs.h>
  27#include <linux/jiffies.h>
  28#include <linux/kernel.h>
  29#include <linux/module.h>
  30#include <linux/poll.h>
  31#include <linux/sched.h> /* for linux/wait.h */
  32#include <linux/slab.h>
  33#include <linux/spinlock.h>
  34#include <linux/stat.h>
  35#include <linux/stddef.h>
  36#include <linux/types.h>
  37#include <linux/uaccess.h>
  38#include <linux/wait.h>
  39#include <stdarg.h>
  40
  41#define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1)
  42
  43static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN;
  44
  45static char *batadv_log_char_addr(struct batadv_priv_debug_log *debug_log,
  46                                  size_t idx)
  47{
  48        return &debug_log->log_buff[idx & BATADV_LOG_BUFF_MASK];
  49}
  50
  51static void batadv_emit_log_char(struct batadv_priv_debug_log *debug_log,
  52                                 char c)
  53{
  54        char *char_addr;
  55
  56        char_addr = batadv_log_char_addr(debug_log, debug_log->log_end);
  57        *char_addr = c;
  58        debug_log->log_end++;
  59
  60        if (debug_log->log_end - debug_log->log_start > batadv_log_buff_len)
  61                debug_log->log_start = debug_log->log_end - batadv_log_buff_len;
  62}
  63
  64__printf(2, 3)
  65static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log,
  66                             const char *fmt, ...)
  67{
  68        va_list args;
  69        static char debug_log_buf[256];
  70        char *p;
  71
  72        if (!debug_log)
  73                return 0;
  74
  75        spin_lock_bh(&debug_log->lock);
  76        va_start(args, fmt);
  77        vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args);
  78        va_end(args);
  79
  80        for (p = debug_log_buf; *p != 0; p++)
  81                batadv_emit_log_char(debug_log, *p);
  82
  83        spin_unlock_bh(&debug_log->lock);
  84
  85        wake_up(&debug_log->queue_wait);
  86
  87        return 0;
  88}
  89
  90int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
  91{
  92        va_list args;
  93        char tmp_log_buf[256];
  94
  95        va_start(args, fmt);
  96        vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
  97        batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s",
  98                          jiffies_to_msecs(jiffies), tmp_log_buf);
  99        va_end(args);
 100
 101        return 0;
 102}
 103
 104static int batadv_log_open(struct inode *inode, struct file *file)
 105{
 106        if (!try_module_get(THIS_MODULE))
 107                return -EBUSY;
 108
 109        nonseekable_open(inode, file);
 110        file->private_data = inode->i_private;
 111        return 0;
 112}
 113
 114static int batadv_log_release(struct inode *inode, struct file *file)
 115{
 116        module_put(THIS_MODULE);
 117        return 0;
 118}
 119
 120static bool batadv_log_empty(struct batadv_priv_debug_log *debug_log)
 121{
 122        return !(debug_log->log_start - debug_log->log_end);
 123}
 124
 125static ssize_t batadv_log_read(struct file *file, char __user *buf,
 126                               size_t count, loff_t *ppos)
 127{
 128        struct batadv_priv *bat_priv = file->private_data;
 129        struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
 130        int error, i = 0;
 131        char *char_addr;
 132        char c;
 133
 134        if ((file->f_flags & O_NONBLOCK) && batadv_log_empty(debug_log))
 135                return -EAGAIN;
 136
 137        if (!buf)
 138                return -EINVAL;
 139
 140        if (count == 0)
 141                return 0;
 142
 143        if (!access_ok(VERIFY_WRITE, buf, count))
 144                return -EFAULT;
 145
 146        error = wait_event_interruptible(debug_log->queue_wait,
 147                                         (!batadv_log_empty(debug_log)));
 148
 149        if (error)
 150                return error;
 151
 152        spin_lock_bh(&debug_log->lock);
 153
 154        while ((!error) && (i < count) &&
 155               (debug_log->log_start != debug_log->log_end)) {
 156                char_addr = batadv_log_char_addr(debug_log,
 157                                                 debug_log->log_start);
 158                c = *char_addr;
 159
 160                debug_log->log_start++;
 161
 162                spin_unlock_bh(&debug_log->lock);
 163
 164                error = __put_user(c, buf);
 165
 166                spin_lock_bh(&debug_log->lock);
 167
 168                buf++;
 169                i++;
 170        }
 171
 172        spin_unlock_bh(&debug_log->lock);
 173
 174        if (!error)
 175                return i;
 176
 177        return error;
 178}
 179
 180static unsigned int batadv_log_poll(struct file *file, poll_table *wait)
 181{
 182        struct batadv_priv *bat_priv = file->private_data;
 183        struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
 184
 185        poll_wait(file, &debug_log->queue_wait, wait);
 186
 187        if (!batadv_log_empty(debug_log))
 188                return POLLIN | POLLRDNORM;
 189
 190        return 0;
 191}
 192
 193static const struct file_operations batadv_log_fops = {
 194        .open           = batadv_log_open,
 195        .release        = batadv_log_release,
 196        .read           = batadv_log_read,
 197        .poll           = batadv_log_poll,
 198        .llseek         = no_llseek,
 199};
 200
 201int batadv_debug_log_setup(struct batadv_priv *bat_priv)
 202{
 203        struct dentry *d;
 204
 205        if (!bat_priv->debug_dir)
 206                goto err;
 207
 208        bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC);
 209        if (!bat_priv->debug_log)
 210                goto err;
 211
 212        spin_lock_init(&bat_priv->debug_log->lock);
 213        init_waitqueue_head(&bat_priv->debug_log->queue_wait);
 214
 215        d = debugfs_create_file("log", S_IFREG | S_IRUSR,
 216                                bat_priv->debug_dir, bat_priv,
 217                                &batadv_log_fops);
 218        if (!d)
 219                goto err;
 220
 221        return 0;
 222
 223err:
 224        return -ENOMEM;
 225}
 226
 227void batadv_debug_log_cleanup(struct batadv_priv *bat_priv)
 228{
 229        kfree(bat_priv->debug_log);
 230        bat_priv->debug_log = NULL;
 231}
 232