Remove port data; deregister from the hvc core if it's a console port. Signed-off-by: Amit Shah <amit.shah@xxxxxxxxxx> --- 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 Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/virtualization