diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2013-01-25 09:34:16 -0500 |
---|---|---|
committer | Gleb Natapov <gleb@redhat.com> | 2013-01-30 05:35:55 -0500 |
commit | c98d3683ce675d689121147ed00e7c4af4737518 (patch) | |
tree | ccb2b54c7befb859908b30c1653cae2774314bea /drivers/s390/kvm | |
parent | 15bc8d8457875f495c59d933b05770ba88d1eacb (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.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, | |||
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 | ||
313 | out_err: | 310 | out_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 | } |