Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
@@ -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);
}