diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2013-01-25 15:34:16 +0100 |
---|---|---|
committer | Gleb Natapov <gleb@redhat.com> | 2013-01-30 11:35:55 +0100 |
commit | c98d3683ce675d689121147ed00e7c4af4737518 (patch) | |
tree | ccb2b54c7befb859908b30c1653cae2774314bea /drivers/s390 | |
parent | s390/kvm: Fix store status for ACRS/FPRS (diff) | |
download | linux-c98d3683ce675d689121147ed00e7c4af4737518.tar.xz linux-c98d3683ce675d689121147ed00e7c4af4737518.zip |
s390/virtio-ccw: Fix setup_vq error handling.
virtio_ccw_setup_vq() failed to unwind correctly on errors. In
particular, it failed to delete the virtqueue on errors, leading to
list corruption when virtio_ccw_del_vqs() iterated over a virtqueue
that had not been added to the vcdev's list.
Fix this with redoing the error unwinding in virtio_ccw_setup_vq(),
using a single path for all errors.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/kvm/virtio_ccw.c | 20 |
1 files changed, 11 insertions, 9 deletions
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c index 2edd94af131c..3217dfe5cb8b 100644 --- a/drivers/s390/kvm/virtio_ccw.c +++ b/drivers/s390/kvm/virtio_ccw.c @@ -244,9 +244,9 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, { struct virtio_ccw_device *vcdev = to_vc_device(vdev); int err; - struct virtqueue *vq; + struct virtqueue *vq = NULL; struct virtio_ccw_vq_info *info; - unsigned long size; + unsigned long size = 0; /* silence the compiler */ unsigned long flags; /* Allocate queue. */ @@ -279,11 +279,8 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, /* For now, we fail if we can't get the requested size. */ dev_warn(&vcdev->cdev->dev, "no vq\n"); err = -ENOMEM; - free_pages_exact(info->queue, size); goto out_err; } - info->vq = vq; - vq->priv = info; /* Register it with the host. */ info->info_block->queue = (__u64)info->queue; @@ -297,12 +294,12 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i); if (err) { dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n"); - free_pages_exact(info->queue, size); - info->vq = NULL; - vq->priv = NULL; goto out_err; } + info->vq = vq; + vq->priv = info; + /* Save it to our list. */ spin_lock_irqsave(&vcdev->lock, flags); list_add(&info->node, &vcdev->virtqueues); @@ -311,8 +308,13 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, return vq; out_err: - if (info) + if (vq) + vring_del_virtqueue(vq); + if (info) { + if (info->queue) + free_pages_exact(info->queue, size); kfree(info->info_block); + } kfree(info); return ERR_PTR(err); } |