virtio: console: Add debugfs files for each port to expose debug info
authorAmit Shah <amit.shah@redhat.com>
Mon, 21 Dec 2009 17:06:21 +0000 (22:36 +0530)
committerRusty Russell <rusty@rustcorp.com.au>
Wed, 24 Feb 2010 03:53:01 +0000 (14:23 +1030)
This is helpful in examining ports' state.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
drivers/char/virtio_console.c

index 9f20fda9c56f8733ffbebab638c49ceea11c0e98..2a04daa9189ed60001920cef1d305622937b3c4a 100644 (file)
@@ -17,6 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/cdev.h>
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/fs.h>
@@ -43,6 +44,9 @@ struct ports_driver_data {
        /* Used for registering chardevs */
        struct class *class;
 
+       /* Used for exporting per-port information to debugfs */
+       struct dentry *debugfs_dir;
+
        /* Number of devices this driver is handling */
        unsigned int index;
 
@@ -158,6 +162,9 @@ struct port {
        /* The IO vqs for this port */
        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
         * hooked up to an hvc console
@@ -783,6 +790,49 @@ static struct attribute_group port_attribute_group = {
        .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. */
 static int remove_port(struct port *port)
 {
@@ -809,6 +859,8 @@ static int remove_port(struct port *port)
        discard_port_data(port);
        kfree(port->name);
 
+       debugfs_remove(port->debugfs_file);
+
        kfree(port);
        return 0;
 }
@@ -1021,6 +1073,7 @@ static void fill_queue(struct virtqueue *vq, spinlock_t *lock)
 
 static int add_port(struct ports_device *portdev, u32 id)
 {
+       char debugfs_name[16];
        struct port *port;
        struct port_buffer *inbuf;
        dev_t devt;
@@ -1096,6 +1149,18 @@ static int add_port(struct ports_device *portdev, u32 id)
         */
        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;
 
 free_inbuf:
@@ -1406,6 +1471,12 @@ static int __init init(void)
                pr_err("Error %d creating virtio-ports class\n", 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);
 
        return register_virtio_driver(&virtio_console);