summaryrefslogtreecommitdiffstats
path: root/drivers/s390/kvm
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2013-01-25 09:34:16 -0500
committerGleb Natapov <gleb@redhat.com>2013-01-30 05:35:55 -0500
commitc98d3683ce675d689121147ed00e7c4af4737518 (patch)
treeccb2b54c7befb859908b30c1653cae2774314bea /drivers/s390/kvm
parent15bc8d8457875f495c59d933b05770ba88d1eacb (diff)
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/kvm')
-rw-r--r--drivers/s390/kvm/virtio_ccw.c20
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,
244{ 244{
245 struct virtio_ccw_device *vcdev = to_vc_device(vdev); 245 struct virtio_ccw_device *vcdev = to_vc_device(vdev);
246 int err; 246 int err;
247 struct virtqueue *vq; 247 struct virtqueue *vq = NULL;
248 struct virtio_ccw_vq_info *info; 248 struct virtio_ccw_vq_info *info;
249 unsigned long size; 249 unsigned long size = 0; /* silence the compiler */
250 unsigned long flags; 250 unsigned long flags;
251 251
252 /* Allocate queue. */ 252 /* Allocate queue. */
@@ -279,11 +279,8 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
279 /* For now, we fail if we can't get the requested size. */ 279 /* For now, we fail if we can't get the requested size. */
280 dev_warn(&vcdev->cdev->dev, "no vq\n"); 280 dev_warn(&vcdev->cdev->dev, "no vq\n");
281 err = -ENOMEM; 281 err = -ENOMEM;
282 free_pages_exact(info->queue, size);
283 goto out_err; 282 goto out_err;
284 } 283 }
285 info->vq = vq;
286 vq->priv = info;
287 284
288 /* Register it with the host. */ 285 /* Register it with the host. */
289 info->info_block->queue = (__u64)info->queue; 286 info->info_block->queue = (__u64)info->queue;
@@ -297,12 +294,12 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
297 err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i); 294 err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i);
298 if (err) { 295 if (err) {
299 dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n"); 296 dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n");
300 free_pages_exact(info->queue, size);
301 info->vq = NULL;
302 vq->priv = NULL;
303 goto out_err; 297 goto out_err;
304 } 298 }
305 299
300 info->vq = vq;
301 vq->priv = info;
302
306 /* Save it to our list. */ 303 /* Save it to our list. */
307 spin_lock_irqsave(&vcdev->lock, flags); 304 spin_lock_irqsave(&vcdev->lock, flags);
308 list_add(&info->node, &vcdev->virtqueues); 305 list_add(&info->node, &vcdev->virtqueues);
@@ -311,8 +308,13 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
311 return vq; 308 return vq;
312 309
313out_err: 310out_err:
314 if (info) 311 if (vq)
312 vring_del_virtqueue(vq);
313 if (info) {
314 if (info->queue)
315 free_pages_exact(info->queue, size);
315 kfree(info->info_block); 316 kfree(info->info_block);
317 }
316 kfree(info); 318 kfree(info);
317 return ERR_PTR(err); 319 return ERR_PTR(err);
318} 320}