Remove port data; deregister from the hvc core if it's a console port.
Signed-off-by: Amit Shah <[email protected]>
---
drivers/char/virtio_console.c | 69 +++++++++++++++++++++++++++++++++++++--
include/linux/virtio_console.h | 1 +
2 files changed, 66 insertions(+), 4 deletions(-)
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 47d84d7..8ed57c2 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -795,6 +795,43 @@ static void fill_receive_queue(struct ports_device
*portdev)
static struct attribute_group port_attribute_group;
+/* Remove port-specific data. */
+static int remove_port_data(struct port *port)
+{
+ struct port_buffer *buf, *buf2;
+
+ spin_lock_irq(&port->portdev->ports_list_lock);
+ list_del(&port->list);
+ spin_unlock_irq(&port->portdev->ports_list_lock);
+
+ if (port->guest_connected)
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+ if (is_console_port(port)) {
+ spin_lock_irq(&pdrvdata_lock);
+ list_del(&port->cons.list);
+ spin_unlock_irq(&pdrvdata_lock);
+ hvc_remove(port->cons.hvc);
+ }
+ sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+ device_destroy(pdrvdata.class, port->dev->devt);
+ cdev_del(&port->cdev);
+
+ kfree(port->name);
+
+ /* Remove the buffers in which we have unconsumed data */
+ spin_lock_irq(&port->readbuf_list_lock);
+ list_for_each_entry_safe(buf, buf2, &port->readbuf_head, list) {
+ list_del(&buf->list);
+ kfree(buf->buf);
+ kfree(buf);
+ }
+ spin_unlock_irq(&port->readbuf_list_lock);
+
+ kfree(port);
+ return 0;
+}
+
/* Any private messages that the Host and Guest want to share */
static void handle_control_message(struct port *port, struct port_buffer *buf)
{
@@ -888,6 +925,30 @@ static void handle_control_message(struct port *port,
struct port_buffer *buf)
case VIRTIO_CONSOLE_CACHE_BUFFERS:
port->cache_buffers = cpkt->value;
break;
+ case VIRTIO_CONSOLE_PORT_REMOVE:
+ /*
+ * Hot unplug the port. We don't decrement nr_ports
+ * since we don't want to deal with extra complexities
+ * of using the lowest-available port id: We can just
+ * pick up the nr_ports number as the id and not have
+ * userspace send it to us. This helps us in two ways:
+ *
+ * - We don't need to have a 'port_id' field in the
+ * config space when a port is hot-added. This is a
+ * good thing as we might queue up multiple hotplug
+ * requests issued in our workqueue.
+ *
+ * - Another way to deal with this would have been to
+ * use a bitmap of the active ports and select the
+ * lowest non-active port from that map. That bloats
+ * the already tight config space and we would end
+ * up artificially limiting the max. number of ports
+ * to sizeof(bitmap). Right now we can support 2^32
+ * ports (as the port id is stored in a u32 type).
+ *
+ */
+ remove_port_data(port);
+ break;
}
}
@@ -1152,10 +1213,6 @@ fail:
return err;
}
-static struct file_operations portdev_fops = {
- .owner = THIS_MODULE,
-};
-
/*
* The workhandler for config-space updates
*
@@ -1200,6 +1257,10 @@ static void config_work_handler(struct work_struct *work)
}
}
+static struct file_operations portdev_fops = {
+ .owner = THIS_MODULE,
+};
+
/*
* Once we're further in boot, we get probed like any other virtio
* device.
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index 70924a1..4941c91 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -41,6 +41,7 @@ struct virtio_console_control {
#define VIRTIO_CONSOLE_THROTTLE_PORT 5
#define VIRTIO_CONSOLE_BUFFER_LIMIT 6
#define VIRTIO_CONSOLE_CACHE_BUFFERS 7
+#define VIRTIO_CONSOLE_PORT_REMOVE 8
/*
* This struct is put at the start of each buffer that gets passed to
--
1.6.2.5
_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization