aboutsummaryrefslogtreecommitdiff
path: root/drivers/char
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2010-02-12 10:32:17 +0530
committerRusty Russell <rusty@rustcorp.com.au>2010-02-24 14:23:04 +1030
commit22a29eacd2a17f22c8260a8106a4e36bae7fb6ea (patch)
tree1b07a3c9eb02b696f686bb63e82dd740877187db /drivers/char
parent7177876fea8306a6f49400d11f5913bf9b3b5e5f (diff)
virtio: console: Error out if we can't allocate buffers for control queue
With MULTIPORT support, the control queue is an integral part of the functioning of the device. If we can't get any buffers allocated, the host won't be able to relay important information and the device may not function as intended. Ensure 'probe' doesn't succeed until the control queue has at least one buffer allocated for its ivq. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/virtio_console.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 0057bae2036f..c40703759e26 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1057,25 +1057,30 @@ static void config_intr(struct virtio_device *vdev)
resize_console(find_port_by_id(portdev, 0));
}
-static void fill_queue(struct virtqueue *vq, spinlock_t *lock)
+static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
{
struct port_buffer *buf;
- int ret;
+ unsigned int ret;
+ int err;
+ ret = 0;
do {
buf = alloc_buf(PAGE_SIZE);
if (!buf)
break;
spin_lock_irq(lock);
- ret = add_inbuf(vq, buf);
- if (ret < 0) {
+ err = add_inbuf(vq, buf);
+ if (err < 0) {
spin_unlock_irq(lock);
free_buf(buf);
break;
}
+ ret++;
spin_unlock_irq(lock);
- } while (ret > 0);
+ } while (err > 0);
+
+ return ret;
}
static int add_port(struct ports_device *portdev, u32 id)
@@ -1430,7 +1435,13 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
INIT_WORK(&portdev->control_work, &control_work_handler);
INIT_WORK(&portdev->config_work, &config_work_handler);
- fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+ err = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+ if (!err) {
+ dev_err(&vdev->dev,
+ "Error allocating buffers for control queue\n");
+ err = -ENOMEM;
+ goto free_vqs;
+ }
}
for (i = 0; i < portdev->config.nr_ports; i++)
@@ -1440,6 +1451,10 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
early_put_chars = NULL;
return 0;
+free_vqs:
+ vdev->config->del_vqs(vdev);
+ kfree(portdev->in_vqs);
+ kfree(portdev->out_vqs);
free_chrdev:
unregister_chrdev(portdev->chr_major, "virtio-portsdev");
free: