Commit c98d3683 authored by Cornelia Huck's avatar Cornelia Huck Committed by Gleb Natapov

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: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
parent 15bc8d84
...@@ -244,9 +244,9 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, ...@@ -244,9 +244,9 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
int err; int err;
struct virtqueue *vq; struct virtqueue *vq = NULL;
struct virtio_ccw_vq_info *info; struct virtio_ccw_vq_info *info;
unsigned long size; unsigned long size = 0; /* silence the compiler */
unsigned long flags; unsigned long flags;
/* Allocate queue. */ /* Allocate queue. */
...@@ -279,11 +279,8 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, ...@@ -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. */ /* For now, we fail if we can't get the requested size. */
dev_warn(&vcdev->cdev->dev, "no vq\n"); dev_warn(&vcdev->cdev->dev, "no vq\n");
err = -ENOMEM; err = -ENOMEM;
free_pages_exact(info->queue, size);
goto out_err; goto out_err;
} }
info->vq = vq;
vq->priv = info;
/* Register it with the host. */ /* Register it with the host. */
info->info_block->queue = (__u64)info->queue; info->info_block->queue = (__u64)info->queue;
...@@ -297,12 +294,12 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, ...@@ -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); err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i);
if (err) { if (err) {
dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n"); dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n");
free_pages_exact(info->queue, size);
info->vq = NULL;
vq->priv = NULL;
goto out_err; goto out_err;
} }
info->vq = vq;
vq->priv = info;
/* Save it to our list. */ /* Save it to our list. */
spin_lock_irqsave(&vcdev->lock, flags); spin_lock_irqsave(&vcdev->lock, flags);
list_add(&info->node, &vcdev->virtqueues); list_add(&info->node, &vcdev->virtqueues);
...@@ -311,8 +308,13 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, ...@@ -311,8 +308,13 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
return vq; return vq;
out_err: 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->info_block);
}
kfree(info); kfree(info);
return ERR_PTR(err); return ERR_PTR(err);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment