18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (C) 2010-2020 B.A.T.M.A.N. contributors: 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Marek Lindner 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "log.h" 88c2ecf20Sopenharmony_ci#include "main.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/compiler.h> 118c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/eventpoll.h> 148c2ecf20Sopenharmony_ci#include <linux/export.h> 158c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 168c2ecf20Sopenharmony_ci#include <linux/fs.h> 178c2ecf20Sopenharmony_ci#include <linux/gfp.h> 188c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/poll.h> 228c2ecf20Sopenharmony_ci#include <linux/sched.h> /* for linux/wait.h */ 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 258c2ecf20Sopenharmony_ci#include <linux/stddef.h> 268c2ecf20Sopenharmony_ci#include <linux/types.h> 278c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 288c2ecf20Sopenharmony_ci#include <linux/wait.h> 298c2ecf20Sopenharmony_ci#include <stdarg.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "debugfs.h" 328c2ecf20Sopenharmony_ci#include "trace.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic const int batadv_log_buff_len = BATADV_LOG_BUF_LEN; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic char *batadv_log_char_addr(struct batadv_priv_debug_log *debug_log, 418c2ecf20Sopenharmony_ci size_t idx) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci return &debug_log->log_buff[idx & BATADV_LOG_BUFF_MASK]; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void batadv_emit_log_char(struct batadv_priv_debug_log *debug_log, 478c2ecf20Sopenharmony_ci char c) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci char *char_addr; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci char_addr = batadv_log_char_addr(debug_log, debug_log->log_end); 528c2ecf20Sopenharmony_ci *char_addr = c; 538c2ecf20Sopenharmony_ci debug_log->log_end++; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (debug_log->log_end - debug_log->log_start > batadv_log_buff_len) 568c2ecf20Sopenharmony_ci debug_log->log_start = debug_log->log_end - batadv_log_buff_len; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci__printf(2, 3) 608c2ecf20Sopenharmony_cistatic int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log, 618c2ecf20Sopenharmony_ci const char *fmt, ...) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci va_list args; 648c2ecf20Sopenharmony_ci static char debug_log_buf[256]; 658c2ecf20Sopenharmony_ci char *p; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (!debug_log) 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci spin_lock_bh(&debug_log->lock); 718c2ecf20Sopenharmony_ci va_start(args, fmt); 728c2ecf20Sopenharmony_ci vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args); 738c2ecf20Sopenharmony_ci va_end(args); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci for (p = debug_log_buf; *p != 0; p++) 768c2ecf20Sopenharmony_ci batadv_emit_log_char(debug_log, *p); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci spin_unlock_bh(&debug_log->lock); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci wake_up(&debug_log->queue_wait); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int batadv_log_open(struct inode *inode, struct file *file) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 888c2ecf20Sopenharmony_ci return -EBUSY; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci batadv_debugfs_deprecated(file, 918c2ecf20Sopenharmony_ci "Use tracepoint batadv:batadv_dbg instead\n"); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci stream_open(inode, file); 948c2ecf20Sopenharmony_ci file->private_data = inode->i_private; 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int batadv_log_release(struct inode *inode, struct file *file) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic bool batadv_log_empty(struct batadv_priv_debug_log *debug_log) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci return !(debug_log->log_start - debug_log->log_end); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic ssize_t batadv_log_read(struct file *file, char __user *buf, 1108c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = file->private_data; 1138c2ecf20Sopenharmony_ci struct batadv_priv_debug_log *debug_log = bat_priv->debug_log; 1148c2ecf20Sopenharmony_ci int error, i = 0; 1158c2ecf20Sopenharmony_ci char *char_addr; 1168c2ecf20Sopenharmony_ci char c; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if ((file->f_flags & O_NONBLOCK) && batadv_log_empty(debug_log)) 1198c2ecf20Sopenharmony_ci return -EAGAIN; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (!buf) 1228c2ecf20Sopenharmony_ci return -EINVAL; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (count == 0) 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (!access_ok(buf, count)) 1288c2ecf20Sopenharmony_ci return -EFAULT; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci error = wait_event_interruptible(debug_log->queue_wait, 1318c2ecf20Sopenharmony_ci (!batadv_log_empty(debug_log))); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (error) 1348c2ecf20Sopenharmony_ci return error; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci spin_lock_bh(&debug_log->lock); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci while ((!error) && (i < count) && 1398c2ecf20Sopenharmony_ci (debug_log->log_start != debug_log->log_end)) { 1408c2ecf20Sopenharmony_ci char_addr = batadv_log_char_addr(debug_log, 1418c2ecf20Sopenharmony_ci debug_log->log_start); 1428c2ecf20Sopenharmony_ci c = *char_addr; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci debug_log->log_start++; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci spin_unlock_bh(&debug_log->lock); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci error = __put_user(c, buf); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci spin_lock_bh(&debug_log->lock); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci buf++; 1538c2ecf20Sopenharmony_ci i++; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci spin_unlock_bh(&debug_log->lock); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (!error) 1598c2ecf20Sopenharmony_ci return i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return error; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic __poll_t batadv_log_poll(struct file *file, poll_table *wait) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct batadv_priv *bat_priv = file->private_data; 1678c2ecf20Sopenharmony_ci struct batadv_priv_debug_log *debug_log = bat_priv->debug_log; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci poll_wait(file, &debug_log->queue_wait, wait); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (!batadv_log_empty(debug_log)) 1728c2ecf20Sopenharmony_ci return EPOLLIN | EPOLLRDNORM; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const struct file_operations batadv_log_fops = { 1788c2ecf20Sopenharmony_ci .open = batadv_log_open, 1798c2ecf20Sopenharmony_ci .release = batadv_log_release, 1808c2ecf20Sopenharmony_ci .read = batadv_log_read, 1818c2ecf20Sopenharmony_ci .poll = batadv_log_poll, 1828c2ecf20Sopenharmony_ci .llseek = no_llseek, 1838c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/** 1878c2ecf20Sopenharmony_ci * batadv_debug_log_setup() - Initialize debug log 1888c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 1898c2ecf20Sopenharmony_ci * 1908c2ecf20Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ciint batadv_debug_log_setup(struct batadv_priv *bat_priv) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC); 1958c2ecf20Sopenharmony_ci if (!bat_priv->debug_log) 1968c2ecf20Sopenharmony_ci return -ENOMEM; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci spin_lock_init(&bat_priv->debug_log->lock); 1998c2ecf20Sopenharmony_ci init_waitqueue_head(&bat_priv->debug_log->queue_wait); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci debugfs_create_file("log", 0400, bat_priv->debug_dir, bat_priv, 2028c2ecf20Sopenharmony_ci &batadv_log_fops); 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/** 2078c2ecf20Sopenharmony_ci * batadv_debug_log_cleanup() - Destroy debug log 2088c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_civoid batadv_debug_log_cleanup(struct batadv_priv *bat_priv) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci kfree(bat_priv->debug_log); 2138c2ecf20Sopenharmony_ci bat_priv->debug_log = NULL; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#endif /* CONFIG_BATMAN_ADV_DEBUGFS */ 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/** 2198c2ecf20Sopenharmony_ci * batadv_debug_log() - Add debug log entry 2208c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information 2218c2ecf20Sopenharmony_ci * @fmt: format string 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * Return: 0 on success or negative error number in case of failure 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ciint batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct va_format vaf; 2288c2ecf20Sopenharmony_ci va_list args; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci va_start(args, fmt); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci vaf.fmt = fmt; 2338c2ecf20Sopenharmony_ci vaf.va = &args; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS 2368c2ecf20Sopenharmony_ci batadv_fdebug_log(bat_priv->debug_log, "[%10u] %pV", 2378c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies), &vaf); 2388c2ecf20Sopenharmony_ci#endif 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci trace_batadv_dbg(bat_priv, &vaf); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci va_end(args); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 246