Hey Rusty, These are the patches that rework a few bits to make hot-unplug while ports are open not crash apps (or kernels). The problem is when hot-unplug is performed when a port is open, the cdev struct is kept around by the file pointers and when the app later does a 'close', things go boom-boom. This patch series makes sure port as well as device hot-unplug is now safe to perform at any time: when ports are open, not open, hvc consoles are active, inactive, module removal, applications doing blocking read/write/poll calls while port / devices are going away... Ideally this patchset would be applicable for 2.6.36 as well as 2.6.35, but I'll let you decide as it's quite big. Amit Shah (14): virtio: console: Reset vdev before removing device virtio: console: Remove control vq data only if using multiport support virtio: console: Check if portdev is valid in send_control_msg() virtio: console: Unblock reads on chardev close virtio: console: Unblock poll on port hot-unplug virtio: console: Make read() return -ENODEV on hot-unplug virtio: console: Make write() return -ENODEV on hot-unplug virtio: console: remove_port() should return void virtio: console: open: Use a common path for error handling virtio: console: Add a list of portdevs that are active virtio: console: Add a find_port_by_devt() function virtio: console: Use cdev_alloc() instead of cdev_init() virtio: console: Add reference counting for port struct virtio: console: Reference counting portdev structs is not needed drivers/char/virtio_console.c | 206 ++++++++++++++++++++++++++++++++++------- 1 files changed, 173 insertions(+), 33 deletions(-) -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 01/14] virtio: console: Reset vdev before removing device
The virtqueues should be disabled before attempting to remove the device. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 942a982..32267d4 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1590,6 +1590,9 @@ static void virtcons_remove(struct virtio_device *vdev) portdev = vdev->priv; + /* Disable interrupts for vqs */ + vdev->config->reset(vdev); + /* Finish up work that's lined up */ cancel_work_sync(&portdev->control_work); list_for_each_entry_safe(port, port2, &portdev->ports, list) -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 02/14] virtio: console: Remove control vq data only if using multiport support
If a portdev isn't using multiport support, it won't have any control vq data to remove. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 32267d4..0f115b4 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1585,8 +1585,6 @@ static void virtcons_remove(struct virtio_device *vdev) { struct ports_device *portdev; struct port *port, *port2; - struct port_buffer *buf; - unsigned int len; portdev = vdev->priv; @@ -1600,11 +1598,16 @@ static void virtcons_remove(struct virtio_device *vdev) unregister_chrdev(portdev->chr_major, "virtio-portsdev"); - while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) - free_buf(buf); + if (use_multiport(portdev)) { + struct port_buffer *buf; + unsigned int len; - while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) - free_buf(buf); + while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) + free_buf(buf); + + while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) + free_buf(buf); + } vdev->config->del_vqs(vdev); kfree(portdev->in_vqs); -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 03/14] virtio: console: Check if portdev is valid in send_control_msg()
A portdev may have been hot-unplugged while a port was open()ed. Skip sending control messages when the portdev isn't valid. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 0f115b4..5cd5374 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -410,7 +410,10 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, static ssize_t send_control_msg(struct port *port, unsigned int event, unsigned int value) { - return __send_control_msg(port->portdev, port->id, event, value); + /* Did the port get unplugged before userspace closed it? */ + if (port->portdev) + return __send_control_msg(port->portdev, port->id, event, value); + return 0; } /* Callers must take the port->outvq_lock */ -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 04/14] virtio: console: Un-block reads on chardev close
If a chardev is closed, any blocked read / poll calls should just return and not attempt to use other state. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 5cd5374..488d250 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -525,6 +525,10 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count, /* The condition that must be true for polling to end */ static bool will_read_block(struct port *port) { + if (!port->guest_connected) { + /* Port got hot-unplugged. Let's exit. */ + return false; + } return !port_has_data(port) && port->host_connected; } -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 05/14] virtio: console: Unblock poll on port hot-unplug
When a port is hot-unplugged while an app is blocked on poll(), unblock the poll() and return. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 488d250..c8a5678 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -648,6 +648,10 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait) port = filp->private_data; poll_wait(filp, &port->waitqueue, wait); + if (!port->guest_connected) { + /* Port got unplugged */ + return POLLHUP; + } ret = 0; if (port->inbuf) ret |= POLLIN | POLLRDNORM; -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 06/14] virtio: console: Make read() return -ENODEV on hot-unplug
When a port is hot-unplugged while an app was blocked on a read() call, the call was unblocked but would not get an error returned. Return -ENODEV to ensure the app knows the port has gone away. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index c8a5678..7fa3c26 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -579,6 +579,9 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf, if (ret < 0) return ret; } + /* Port got hot-unplugged. */ + if (!port->guest_connected) + return -ENODEV; /* * We could've received a disconnection message while we were * waiting for more data. -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 07/14] virtio: console: Make write() return -ENODEV on hot-unplug
When a port is hot-unplugged while an app was blocked on a write() call, the call was unblocked but would not get an error returned. Return -ENODEV to ensure the app knows the port has gone away. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 7fa3c26..ecadfa2 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -619,6 +619,9 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, if (ret < 0) return ret; } + /* Port got hot-unplugged. */ + if (!port->guest_connected) + return -ENODEV; count = min((size_t)(32 * 1024), count); -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 08/14] virtio: console: remove_port() should return void
When a port is removed, we have to assume the port is gone. So a success/failure return value doesn't make sense. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index ecadfa2..0c4ee9b1 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1116,7 +1116,7 @@ fail: } /* Remove all port-specific data. */ -static int remove_port(struct port *port) +static void remove_port(struct port *port) { struct port_buffer *buf; @@ -1166,7 +1166,6 @@ static int remove_port(struct port *port) debugfs_remove(port->debugfs_file); kfree(port); - return 0; } /* Any private messages that the Host and Guest want to share */ -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 09/14] virtio: console: open: Use a common path for error handling
Just re-arrange code for future patches. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 0c4ee9b1..d689c76 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -696,6 +696,7 @@ static int port_fops_open(struct inode *inode, struct file *filp) { struct cdev *cdev = inode->i_cdev; struct port *port; + int ret; port = container_of(cdev, struct port, cdev); filp->private_data = port; @@ -704,14 +705,17 @@ static int port_fops_open(struct inode *inode, struct file *filp) * Don't allow opening of console port devices -- that's done * via /dev/hvc */ - if (is_console_port(port)) - return -ENXIO; + if (is_console_port(port)) { + ret = -ENXIO; + goto out; + } /* Allow only one process to open a particular port at a time */ spin_lock_irq(&port->inbuf_lock); if (port->guest_connected) { spin_unlock_irq(&port->inbuf_lock); - return -EMFILE; + ret = -EMFILE; + goto out; } port->guest_connected = true; @@ -730,6 +734,8 @@ static int port_fops_open(struct inode *inode, struct file *filp) send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1); return 0; +out: + return ret; } /* -- 1.7.2.2
Amit Shah
2010-Sep-02 12:41 UTC
[PATCH 10/14] virtio: console: Add a list of portdevs that are active
The virtio_console.c driver is capable of handling multiple devices at a time. Maintain a list of devices for future traversal. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index d689c76..a37a868 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -48,6 +48,9 @@ struct ports_driver_data { /* Used for exporting per-port information to debugfs */ struct dentry *debugfs_dir; + /* List of all the devices we're handling */ + struct list_head portdevs; + /* Number of devices this driver is handling */ unsigned int index; @@ -108,6 +111,9 @@ struct port_buffer { * ports for that device (vdev->priv). */ struct ports_device { + /* Next portdev in the list, head is in the pdrvdata struct */ + struct list_head list; + /* * Workqueue handlers where we process deferred work after * notification @@ -1584,6 +1590,10 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) add_port(portdev, 0); } + spin_lock_irq(&pdrvdata_lock); + list_add_tail(&portdev->list, &pdrvdata.portdevs); + spin_unlock_irq(&pdrvdata_lock); + __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, VIRTIO_CONSOLE_DEVICE_READY, 1); return 0; @@ -1610,6 +1620,10 @@ static void virtcons_remove(struct virtio_device *vdev) portdev = vdev->priv; + spin_lock_irq(&pdrvdata_lock); + list_del(&portdev->list); + spin_unlock_irq(&pdrvdata_lock); + /* Disable interrupts for vqs */ vdev->config->reset(vdev); /* Finish up work that's lined up */ @@ -1676,6 +1690,7 @@ static int __init init(void) PTR_ERR(pdrvdata.debugfs_dir)); } INIT_LIST_HEAD(&pdrvdata.consoles); + INIT_LIST_HEAD(&pdrvdata.portdevs); return register_virtio_driver(&virtio_console); } -- 1.7.2.2
Amit Shah
2010-Sep-02 12:50 UTC
[PATCH 11/14] virtio: console: Add a find_port_by_devt() function
To convert to using cdev as a pointer to avoid kref troubles, we have to use a different method to get to a port from an inode than the current container_of method. Add find_port_by_devt() that looks up all portdevs and ports with those portdevs to find the right port. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 37 ++++++++++++++++++++++++++++++++++++- 1 files changed, 36 insertions(+), 1 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index a37a868..af44332 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -227,6 +227,41 @@ out: return port; } +static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev, + dev_t dev) +{ + struct port *port; + unsigned long flags; + + spin_lock_irqsave(&portdev->ports_lock, flags); + list_for_each_entry(port, &portdev->ports, list) + if (port->cdev.dev == dev) + goto out; + port = NULL; +out: + spin_unlock_irqrestore(&portdev->ports_lock, flags); + + return port; +} + +static struct port *find_port_by_devt(dev_t dev) +{ + struct ports_device *portdev; + struct port *port; + unsigned long flags; + + spin_lock_irqsave(&pdrvdata_lock, flags); + list_for_each_entry(portdev, &pdrvdata.portdevs, list) { + port = find_port_by_devt_in_portdev(portdev, dev); + if (port) + goto out; + } + port = NULL; +out: + spin_unlock_irqrestore(&pdrvdata_lock, flags); + return port; +} + static struct port *find_port_by_id(struct ports_device *portdev, u32 id) { struct port *port; @@ -704,7 +739,7 @@ static int port_fops_open(struct inode *inode, struct file *filp) struct port *port; int ret; - port = container_of(cdev, struct port, cdev); + port = find_port_by_devt(cdev->dev); filp->private_data = port; /* -- 1.7.2.2
Amit Shah
2010-Sep-02 12:50 UTC
[PATCH 12/14] virtio: console: Use cdev_alloc() instead of cdev_init()
This moves to using cdev on the heap instead of it being embedded in the ports struct. This helps individual refcounting and will allow us to properly remove cdev structs after hot-unplugs and close operations. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 20 +++++++++++++------- 1 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index af44332..0c4dc26 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -184,7 +184,7 @@ struct port { struct console cons; /* Each port associates with a separate char device */ - struct cdev cdev; + struct cdev *cdev; struct device *dev; /* A waitqueue for poll() or blocking read operations */ @@ -235,7 +235,7 @@ static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev, spin_lock_irqsave(&portdev->ports_lock, flags); list_for_each_entry(port, &portdev->ports, list) - if (port->cdev.dev == dev) + if (port->cdev->dev == dev) goto out; port = NULL; out: @@ -1081,14 +1081,20 @@ static int add_port(struct ports_device *portdev, u32 id) port->in_vq = portdev->in_vqs[port->id]; port->out_vq = portdev->out_vqs[port->id]; - cdev_init(&port->cdev, &port_fops); + port->cdev = cdev_alloc(); + if (!port->cdev) { + dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n"); + err = -ENOMEM; + goto free_port; + } + port->cdev->ops = &port_fops; devt = MKDEV(portdev->chr_major, id); - err = cdev_add(&port->cdev, devt, 1); + err = cdev_add(port->cdev, devt, 1); if (err < 0) { dev_err(&port->portdev->vdev->dev, "Error %d adding cdev for port %u\n", err, id); - goto free_port; + goto free_cdev; } port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, devt, port, "vport%up%u", @@ -1153,7 +1159,7 @@ free_inbufs: free_device: device_destroy(pdrvdata.class, port->dev->devt); free_cdev: - cdev_del(&port->cdev); + cdev_del(port->cdev); free_port: kfree(port); fail: @@ -1197,7 +1203,7 @@ static void remove_port(struct port *port) } sysfs_remove_group(&port->dev->kobj, &port_attribute_group); device_destroy(pdrvdata.class, port->dev->devt); - cdev_del(&port->cdev); + cdev_del(port->cdev); /* Remove unused data this port might have received. */ discard_port_data(port); -- 1.7.2.2
Amit Shah
2010-Sep-02 13:08 UTC
[PATCH 13/14] virtio: console: Add reference counting for port struct
When a port got hot-unplugged, when a port was open, any file operation after the unplugging resulted in a crash. This is fixed by ref-counting the port structure, and releasing it only when the file is closed. This splits the unplug operation in two parts: first marks the port as unavailable, removes all the buffers in the vqs and removes the port from the per-device list of ports. The second stage, invoked when all references drop to zero, releases the chardev and frees all other memory. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 80 ++++++++++++++++++++++++++++++++-------- 1 files changed, 64 insertions(+), 16 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 0c4dc26..1e00221 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -187,6 +187,9 @@ struct port { struct cdev *cdev; struct device *dev; + /* Reference-counting to handle port hot-unplugs and file operations */ + struct kref kref; + /* A waitqueue for poll() or blocking read operations */ wait_queue_head_t waitqueue; @@ -710,6 +713,8 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait) return ret; } +static void remove_port(struct kref *kref); + static int port_fops_release(struct inode *inode, struct file *filp) { struct port *port; @@ -730,6 +735,16 @@ static int port_fops_release(struct inode *inode, struct file *filp) reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); + /* + * Locks aren't necessary here as a port can't be opened after + * unplug, and if a port isn't unplugged, a kref would already + * exist for the port. Plus, taking ports_lock here would + * create a dependency on other locks taken by functions + * inside remove_port if we're the last holder of the port, + * creating many problems. + */ + kref_put(&port->kref, remove_port); + return 0; } @@ -742,6 +757,11 @@ static int port_fops_open(struct inode *inode, struct file *filp) port = find_port_by_devt(cdev->dev); filp->private_data = port; + /* Prevent against a port getting hot-unplugged at the same time */ + spin_lock_irq(&port->portdev->ports_lock); + kref_get(&port->kref); + spin_unlock_irq(&port->portdev->ports_lock); + /* * Don't allow opening of console port devices -- that's done * via /dev/hvc @@ -776,6 +796,7 @@ static int port_fops_open(struct inode *inode, struct file *filp) return 0; out: + kref_put(&port->kref, remove_port); return ret; } @@ -1064,6 +1085,7 @@ static int add_port(struct ports_device *portdev, u32 id) err = -ENOMEM; goto fail; } + kref_init(&port->kref); port->portdev = portdev; port->id = id; @@ -1168,22 +1190,43 @@ fail: return err; } -/* Remove all port-specific data. */ -static void remove_port(struct port *port) +/* No users remain, remove all port-specific data. */ +static void remove_port(struct kref *kref) +{ + struct port *port; + + port = container_of(kref, struct port, kref); + + sysfs_remove_group(&port->dev->kobj, &port_attribute_group); + device_destroy(pdrvdata.class, port->dev->devt); + cdev_del(port->cdev); + + kfree(port->name); + + debugfs_remove(port->debugfs_file); + + kfree(port); +} + +/* + * Port got unplugged. Remove port from portdev's list and drop the + * kref reference. If no userspace has this port opened, it will + * result in immediate removal the port. + */ +static void unplug_port(struct port *port) { struct port_buffer *buf; + spin_lock_irq(&port->portdev->ports_lock); + list_del(&port->list); + spin_unlock_irq(&port->portdev->ports_lock); + if (port->guest_connected) { port->guest_connected = false; port->host_connected = false; wake_up_interruptible(&port->waitqueue); - send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); } - spin_lock_irq(&port->portdev->ports_lock); - list_del(&port->list); - spin_unlock_irq(&port->portdev->ports_lock); - if (is_console_port(port)) { spin_lock_irq(&pdrvdata_lock); list_del(&port->cons.list); @@ -1201,9 +1244,6 @@ static void remove_port(struct port *port) hvc_remove(port->cons.hvc); #endif } - sysfs_remove_group(&port->dev->kobj, &port_attribute_group); - device_destroy(pdrvdata.class, port->dev->devt); - cdev_del(port->cdev); /* Remove unused data this port might have received. */ discard_port_data(port); @@ -1214,11 +1254,19 @@ static void remove_port(struct port *port) while ((buf = virtqueue_detach_unused_buf(port->in_vq))) free_buf(buf); - kfree(port->name); - - debugfs_remove(port->debugfs_file); + /* + * We should just assume the device itself has gone off -- + * else a close on an open port later will try to send out a + * control message. + */ + port->portdev = NULL; - kfree(port); + /* + * Locks around here are not necessary - a port can't be + * opened after we removed the port struct from ports_list + * above. + */ + kref_put(&port->kref, remove_port); } /* Any private messages that the Host and Guest want to share */ @@ -1257,7 +1305,7 @@ static void handle_control_message(struct ports_device *portdev, add_port(portdev, cpkt->id); break; case VIRTIO_CONSOLE_PORT_REMOVE: - remove_port(port); + unplug_port(port); break; case VIRTIO_CONSOLE_CONSOLE_PORT: if (!cpkt->value) @@ -1671,7 +1719,7 @@ static void virtcons_remove(struct virtio_device *vdev) cancel_work_sync(&portdev->control_work); list_for_each_entry_safe(port, port2, &portdev->ports, list) - remove_port(port); + unplug_port(port); unregister_chrdev(portdev->chr_major, "virtio-portsdev"); -- 1.7.2.2
Amit Shah
2010-Sep-02 13:08 UTC
[PATCH 14/14] virtio: console: Reference counting portdev structs is not needed
Explain in a comment why there's no need to reference-count the portdev struct: when a device is yanked out, we can't do anything more with it anyway so just give up doing anything more with the data or the vqs and exit cleanly. Signed-off-by: Amit Shah <amit.shah at redhat.com> --- drivers/char/virtio_console.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 1e00221..793817b 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1723,6 +1723,14 @@ static void virtcons_remove(struct virtio_device *vdev) unregister_chrdev(portdev->chr_major, "virtio-portsdev"); + /* + * When yanking out a device, we immediately lose the + * (device-side) queues. So there's no point in keeping the + * guest side around till we drop our final reference. This + * also means that any ports which are in an open state will + * have to just stop using the port, as the vqs are going + * away. + */ if (use_multiport(portdev)) { struct port_buffer *buf; unsigned int len; -- 1.7.2.2
Possibly Parallel Threads
- [PATCH 00/14] virtio: console: Hot-unplug fixes
- [PATCH v3 0/9] virtio: console: fixes for bugs and races with unplug
- [PATCH v3 0/9] virtio: console: fixes for bugs and races with unplug
- [PATCH v2 00/11] virtio: console: fixes for port unplug
- [PATCH v2 00/11] virtio: console: fixes for port unplug