Commit d99393ef authored by Amit Shah's avatar Amit Shah Committed by Rusty Russell

virtio: console: Add debugfs files for each port to expose debug info

This is helpful in examining ports' state.
Signed-off-by: default avatarAmit Shah <amit.shah@redhat.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 1f7aa42d
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/debugfs.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -43,6 +44,9 @@ struct ports_driver_data { ...@@ -43,6 +44,9 @@ struct ports_driver_data {
/* Used for registering chardevs */ /* Used for registering chardevs */
struct class *class; struct class *class;
/* Used for exporting per-port information to debugfs */
struct dentry *debugfs_dir;
/* Number of devices this driver is handling */ /* Number of devices this driver is handling */
unsigned int index; unsigned int index;
...@@ -158,6 +162,9 @@ struct port { ...@@ -158,6 +162,9 @@ struct port {
/* The IO vqs for this port */ /* The IO vqs for this port */
struct virtqueue *in_vq, *out_vq; struct virtqueue *in_vq, *out_vq;
/* File in the debugfs directory that exposes this port's information */
struct dentry *debugfs_file;
/* /*
* The entries in this struct will be valid if this port is * The entries in this struct will be valid if this port is
* hooked up to an hvc console * hooked up to an hvc console
...@@ -783,6 +790,49 @@ static struct attribute_group port_attribute_group = { ...@@ -783,6 +790,49 @@ static struct attribute_group port_attribute_group = {
.attrs = port_sysfs_entries, .attrs = port_sysfs_entries,
}; };
static int debugfs_open(struct inode *inode, struct file *filp)
{
filp->private_data = inode->i_private;
return 0;
}
static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *offp)
{
struct port *port;
char *buf;
ssize_t ret, out_offset, out_count;
out_count = 1024;
buf = kmalloc(out_count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
port = filp->private_data;
out_offset = 0;
out_offset += snprintf(buf + out_offset, out_count,
"name: %s\n", port->name ? port->name : "");
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"guest_connected: %d\n", port->guest_connected);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"host_connected: %d\n", port->host_connected);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"is_console: %s\n",
is_console_port(port) ? "yes" : "no");
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"console_vtermno: %u\n", port->cons.vtermno);
ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
kfree(buf);
return ret;
}
static const struct file_operations port_debugfs_ops = {
.owner = THIS_MODULE,
.open = debugfs_open,
.read = debugfs_read,
};
/* Remove all port-specific data. */ /* Remove all port-specific data. */
static int remove_port(struct port *port) static int remove_port(struct port *port)
{ {
...@@ -809,6 +859,8 @@ static int remove_port(struct port *port) ...@@ -809,6 +859,8 @@ static int remove_port(struct port *port)
discard_port_data(port); discard_port_data(port);
kfree(port->name); kfree(port->name);
debugfs_remove(port->debugfs_file);
kfree(port); kfree(port);
return 0; return 0;
} }
...@@ -1021,6 +1073,7 @@ static void fill_queue(struct virtqueue *vq, spinlock_t *lock) ...@@ -1021,6 +1073,7 @@ static void fill_queue(struct virtqueue *vq, spinlock_t *lock)
static int add_port(struct ports_device *portdev, u32 id) static int add_port(struct ports_device *portdev, u32 id)
{ {
char debugfs_name[16];
struct port *port; struct port *port;
struct port_buffer *inbuf; struct port_buffer *inbuf;
dev_t devt; dev_t devt;
...@@ -1096,6 +1149,18 @@ static int add_port(struct ports_device *portdev, u32 id) ...@@ -1096,6 +1149,18 @@ static int add_port(struct ports_device *portdev, u32 id)
*/ */
send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
if (pdrvdata.debugfs_dir) {
/*
* Finally, create the debugfs file that we can use to
* inspect a port's state at any time
*/
sprintf(debugfs_name, "vport%up%u",
port->portdev->drv_index, id);
port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
pdrvdata.debugfs_dir,
port,
&port_debugfs_ops);
}
return 0; return 0;
free_inbuf: free_inbuf:
...@@ -1406,6 +1471,12 @@ static int __init init(void) ...@@ -1406,6 +1471,12 @@ static int __init init(void)
pr_err("Error %d creating virtio-ports class\n", err); pr_err("Error %d creating virtio-ports class\n", err);
return err; return err;
} }
pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
if (!pdrvdata.debugfs_dir) {
pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
PTR_ERR(pdrvdata.debugfs_dir));
}
INIT_LIST_HEAD(&pdrvdata.consoles); INIT_LIST_HEAD(&pdrvdata.consoles);
return register_virtio_driver(&virtio_console); return register_virtio_driver(&virtio_console);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment