diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2010-07-06 21:05:16 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-07-08 12:23:28 -0700 |
commit | 84ec08640786592a045b783fb28b542415521bf9 (patch) | |
tree | d19efb9050ab38c4c24239855acc1cb875e7c21d /drivers/staging/batman-adv/bat_debugfs.c | |
parent | e75fece2b893c0064b1c79136a60f30326c28eb3 (diff) | |
download | op-kernel-dev-84ec08640786592a045b783fb28b542415521bf9.zip op-kernel-dev-84ec08640786592a045b783fb28b542415521bf9.tar.gz |
Staging: batman-adv: add routing debug log accessible via debugfs
All routing debug messages are saved in a ring buffer that can be
read via the debugfs file "log".
Note that CONFIG_BATMAN_ADV_DEBUG must be activated to have the
debug logs compiled in.
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/batman-adv/bat_debugfs.c')
-rw-r--r-- | drivers/staging/batman-adv/bat_debugfs.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/drivers/staging/batman-adv/bat_debugfs.c b/drivers/staging/batman-adv/bat_debugfs.c index fafca9f..f818d5e 100644 --- a/drivers/staging/batman-adv/bat_debugfs.c +++ b/drivers/staging/batman-adv/bat_debugfs.c @@ -31,6 +31,193 @@ static struct dentry *bat_debugfs; +#ifdef CONFIG_BATMAN_ADV_DEBUG +#define LOG_BUFF_MASK (log_buff_len-1) +#define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK]) + +static int log_buff_len = LOG_BUF_LEN; + +static void emit_log_char(struct debug_log *debug_log, char c) +{ + LOG_BUFF(debug_log->log_end) = c; + debug_log->log_end++; + + if (debug_log->log_end - debug_log->log_start > log_buff_len) + debug_log->log_start = debug_log->log_end - log_buff_len; +} + +static int fdebug_log(struct debug_log *debug_log, char *fmt, ...) +{ + int printed_len; + va_list args; + static char debug_log_buf[256]; + char *p; + unsigned long flags; + + if (!debug_log) + return 0; + + spin_lock_irqsave(&debug_log->lock, flags); + va_start(args, fmt); + printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), + fmt, args); + va_end(args); + + for (p = debug_log_buf; *p != 0; p++) + emit_log_char(debug_log, *p); + + spin_unlock_irqrestore(&debug_log->lock, flags); + + wake_up(&debug_log->queue_wait); + + return 0; +} + +int debug_log(struct bat_priv *bat_priv, char *fmt, ...) +{ + va_list args; + char tmp_log_buf[256]; + + va_start(args, fmt); + vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); + fdebug_log(bat_priv->debug_log, "[%10u] %s", + (jiffies / HZ), tmp_log_buf); + va_end(args); + + return 0; +} + +static int log_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + inc_module_count(); + return 0; +} + +static int log_release(struct inode *inode, struct file *file) +{ + dec_module_count(); + return 0; +} + +static ssize_t log_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct bat_priv *bat_priv = (struct bat_priv *)file->private_data; + struct debug_log *debug_log = bat_priv->debug_log; + int error, i = 0; + char c; + unsigned long flags; + + if ((file->f_flags & O_NONBLOCK) && + !(debug_log->log_end - debug_log->log_start)) + return -EAGAIN; + + if ((!buf) || (count < 0)) + return -EINVAL; + + if (count == 0) + return 0; + + if (!access_ok(VERIFY_WRITE, buf, count)) + return -EFAULT; + + error = wait_event_interruptible(debug_log->queue_wait, + (debug_log->log_start - debug_log->log_end)); + + if (error) + return error; + + spin_lock_irqsave(&debug_log->lock, flags); + + while ((!error) && (i < count) && + (debug_log->log_start != debug_log->log_end)) { + c = LOG_BUFF(debug_log->log_start); + + debug_log->log_start++; + + spin_unlock_irqrestore(&debug_log->lock, flags); + + error = __put_user(c, buf); + + spin_lock_irqsave(&debug_log->lock, flags); + + buf++; + i++; + + } + + spin_unlock_irqrestore(&debug_log->lock, flags); + + if (!error) + return i; + + return error; +} + +static unsigned int log_poll(struct file *file, poll_table *wait) +{ + struct bat_priv *bat_priv = (struct bat_priv *)file->private_data; + struct debug_log *debug_log = bat_priv->debug_log; + + poll_wait(file, &debug_log->queue_wait, wait); + + if (debug_log->log_end - debug_log->log_start) + return POLLIN | POLLRDNORM; + + return 0; +} + +static const struct file_operations log_fops = { + .open = log_open, + .release = log_release, + .read = log_read, + .poll = log_poll, +}; + +static int debug_log_setup(struct bat_priv *bat_priv) +{ + struct dentry *d; + + if (!bat_priv->debug_dir) + goto err; + + bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC); + if (!bat_priv->debug_log) + goto err; + + spin_lock_init(&bat_priv->debug_log->lock); + init_waitqueue_head(&bat_priv->debug_log->queue_wait); + + d = debugfs_create_file("log", S_IFREG | S_IRUSR, + bat_priv->debug_dir, bat_priv, &log_fops); + if (d) + goto err; + + return 0; + +err: + return 1; +} + +static void debug_log_cleanup(struct bat_priv *bat_priv) +{ + kfree(bat_priv->debug_log); + bat_priv->debug_log = NULL; +} +#else /* CONFIG_BATMAN_ADV_DEBUG */ +static int debug_log_setup(struct bat_priv *bat_priv) +{ + bat_priv->debug_log = NULL; + return 0; +} + +static void debug_log_cleanup(struct bat_priv *bat_priv) +{ + return; +} +#endif + static int originators_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; @@ -114,6 +301,7 @@ int debugfs_add_meshif(struct net_device *dev) goto out; bat_socket_setup(bat_priv); + debug_log_setup(bat_priv); for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) { file = debugfs_create_file(((*bat_debug)->attr).name, @@ -143,6 +331,8 @@ void debugfs_del_meshif(struct net_device *dev) { struct bat_priv *bat_priv = netdev_priv(dev); + debug_log_cleanup(bat_priv); + if (bat_debugfs) { debugfs_remove_recursive(bat_priv->debug_dir); bat_priv->debug_dir = NULL; |