linux/net/batman-adv/log.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (C) 2010-2019  B.A.T.M.A.N. contributors:
   3 *
   4 * Marek Lindner
   5 */
   6
   7#include "log.h"
   8#include "main.h"
   9
  10#include <linux/compiler.h>
  11#include <linux/debugfs.h>
  12#include <linux/errno.h>
  13#include <linux/eventpoll.h>
  14#include <linux/export.h>
  15#include <linux/fcntl.h>
  16#include <linux/fs.h>
  17#include <linux/gfp.h>
  18#include <linux/jiffies.h>
  19#include <linux/kernel.h>
  20#include <linux/module.h>
  21#include <linux/poll.h>
  22#include <linux/sched.h> /* for linux/wait.h */
  23#include <linux/slab.h>
  24#include <linux/spinlock.h>
  25#include <linux/stddef.h>
  26#include <linux/types.h>
  27#include <linux/uaccess.h>
  28#include <linux/wait.h>
  29#include <stdarg.h>
  30
  31#include "debugfs.h"
  32#include "trace.h"
  33
  34#ifdef CONFIG_BATMAN_ADV_DEBUGFS
  35
  36#define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1)
  37
  38static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN;
  39
  40static char *batadv_log_char_addr(struct batadv_priv_debug_log *debug_log,
  41                                  size_t idx)
  42{
  43        return &debug_log->log_buff[idx & BATADV_LOG_BUFF_MASK];
  44}
  45
  46static void batadv_emit_log_char(struct batadv_priv_debug_log *debug_log,
  47                                 char c)
  48{
  49        char *char_addr;
  50
  51        char_addr = batadv_log_char_addr(debug_log, debug_log->log_end);
  52        *char_addr = c;
  53        debug_log->log_end++;
  54
  55        if (debug_log->log_end - debug_log->log_start > batadv_log_buff_len)
  56                debug_log->log_start = debug_log->log_end - batadv_log_buff_len;
  57}
  58
  59__printf(2, 3)
  60static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log,
  61                             const char *fmt, ...)
  62{
  63        va_list args;
  64        static char debug_log_buf[256];
  65        char *p;
  66
  67        if (!debug_log)
  68                return 0;
  69
  70        spin_lock_bh(&debug_log->lock);
  71        va_start(args, fmt);
  72        vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args);
  73        va_end(args);
  74
  75        for (p = debug_log_buf; *p != 0; p++)
  76                batadv_emit_log_char(debug_log, *p);
  77
  78        spin_unlock_bh(&debug_log->lock);
  79
  80        wake_up(&debug_log->queue_wait);
  81
  82        return 0;
  83}
  84
  85static int batadv_log_open(struct inode *inode, struct file *file)
  86{
  87        if (!try_module_get(THIS_MODULE))
  88                return -EBUSY;
  89
  90        batadv_debugfs_deprecated(file,
  91                                  "Use tracepoint batadv:batadv_dbg instead\n");
  92
  93        stream_open(inode, file);
  94        file->private_data = inode->i_private;
  95        return 0;
  96}
  97
  98static int batadv_log_release(struct inode *inode, struct file *file)
  99{
 100        module_put(THIS_MODULE);
 101        return 0;
 102}
 103
 104static bool batadv_log_empty(struct batadv_priv_debug_log *debug_log)
 105{
 106        return !(debug_log->log_start - debug_log->log_end);
 107}
 108
 109static ssize_t batadv_log_read(struct file *file, char __user *buf,
 110                               size_t count, loff_t *ppos)
 111{
 112        struct batadv_priv *bat_priv = file->private_data;
 113        struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
 114        int error, i = 0;
 115        char *char_addr;
 116        char c;
 117
 118        if ((file->f_flags & O_NONBLOCK) && batadv_log_empty(debug_log))
 119                return -EAGAIN;
 120
 121        if (!buf)
 122                return -EINVAL;
 123
 124        if (count == 0)
 125                return 0;
 126
 127        if (!access_ok(buf, count))
 128                return -EFAULT;
 129
 130        error = wait_event_interruptible(debug_log->queue_wait,
 131                                         (!batadv_log_empty(debug_log)));
 132
 133        if (error)
 134                return error;
 135
 136        spin_lock_bh(&debug_log->lock);
 137
 138        while ((!error) && (i < count) &&
 139               (debug_log->log_start != debug_log->log_end)) {
 140                char_addr = batadv_log_char_addr(debug_log,
 141                                                 debug_log->log_start);
 142                c = *char_addr;
 143
 144                debug_log->log_start++;
 145
 146                spin_unlock_bh(&debug_log->lock);
 147
 148                error = __put_user(c, buf);
 149
 150                spin_lock_bh(&debug_log->lock);
 151
 152                buf++;
 153                i++;
 154        }
 155
 156        spin_unlock_bh(&debug_log->lock);
 157
 158        if (!error)
 159                return i;
 160
 161        return error;
 162}
 163
 164static __poll_t batadv_log_poll(struct file *file, poll_table *wait)
 165{
 166        struct batadv_priv *bat_priv = file->private_data;
 167        struct batadv_priv_debug_log *debug_log = bat_priv->debug_log;
 168
 169        poll_wait(file, &debug_log->queue_wait, wait);
 170
 171        if (!batadv_log_empty(debug_log))
 172                return EPOLLIN | EPOLLRDNORM;
 173
 174        return 0;
 175}
 176
 177static const struct file_operations batadv_log_fops = {
 178        .open           = batadv_log_open,
 179        .release        = batadv_log_release,
 180        .read           = batadv_log_read,
 181        .poll           = batadv_log_poll,
 182        .llseek         = no_llseek,
 183};
 184
 185/**
 186 * batadv_debug_log_setup() - Initialize debug log
 187 * @bat_priv: the bat priv with all the soft interface information
 188 *
 189 * Return: 0 on success or negative error number in case of failure
 190 */
 191int batadv_debug_log_setup(struct batadv_priv *bat_priv)
 192{
 193        bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC);
 194        if (!bat_priv->debug_log)
 195                return -ENOMEM;
 196
 197        spin_lock_init(&bat_priv->debug_log->lock);
 198        init_waitqueue_head(&bat_priv->debug_log->queue_wait);
 199
 200        debugfs_create_file("log", 0400, bat_priv->debug_dir, bat_priv,
 201                            &batadv_log_fops);
 202        return 0;
 203}
 204
 205/**
 206 * batadv_debug_log_cleanup() - Destroy debug log
 207 * @bat_priv: the bat priv with all the soft interface information
 208 */
 209void batadv_debug_log_cleanup(struct batadv_priv *bat_priv)
 210{
 211        kfree(bat_priv->debug_log);
 212        bat_priv->debug_log = NULL;
 213}
 214
 215#endif /* CONFIG_BATMAN_ADV_DEBUGFS */
 216
 217/**
 218 * batadv_debug_log() - Add debug log entry
 219 * @bat_priv: the bat priv with all the soft interface information
 220 * @fmt: format string
 221 *
 222 * Return: 0 on success or negative error number in case of failure
 223 */
 224int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
 225{
 226        struct va_format vaf;
 227        va_list args;
 228
 229        va_start(args, fmt);
 230
 231        vaf.fmt = fmt;
 232        vaf.va = &args;
 233
 234#ifdef CONFIG_BATMAN_ADV_DEBUGFS
 235        batadv_fdebug_log(bat_priv->debug_log, "[%10u] %pV",
 236                          jiffies_to_msecs(jiffies), &vaf);
 237#endif
 238
 239        trace_batadv_dbg(bat_priv, &vaf);
 240
 241        va_end(args);
 242
 243        return 0;
 244}
 245