aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeinz Graalfs <graalfs@linux.vnet.ibm.com>2014-02-27 08:34:35 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-03-04 04:41:03 -0500
commit2e0210432d34bc7f01644905c2bb2d5d9be5b6ac (patch)
treeecc95786e82a53aeff50efb50913aeb4bb9b9f32
parent1ee0bc559dc34fe36a29494faf7b7c91533bd31c (diff)
virtio_ccw: fix vcdev pointer handling issues
The interrupt handler virtio_ccw_int_handler() using the vcdev pointer is protected by the ccw_device lock. Resetting the pointer within the ccw_device structure should be done when holding this lock. Also resetting the vcdev pointer (under the ccw_device lock) prior to freeing the vcdev pointer memory removes a critical path. Signed-off-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com> Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r--drivers/s390/kvm/virtio_ccw.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c
index 0fc584832001..413c6304d511 100644
--- a/drivers/s390/kvm/virtio_ccw.c
+++ b/drivers/s390/kvm/virtio_ccw.c
@@ -636,6 +636,8 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
636 struct virtqueue *vq; 636 struct virtqueue *vq;
637 struct virtio_driver *drv; 637 struct virtio_driver *drv;
638 638
639 if (!vcdev)
640 return;
639 /* Check if it's a notification from the host. */ 641 /* Check if it's a notification from the host. */
640 if ((intparm == 0) && 642 if ((intparm == 0) &&
641 (scsw_stctl(&irb->scsw) == 643 (scsw_stctl(&irb->scsw) ==
@@ -734,23 +736,37 @@ static int virtio_ccw_probe(struct ccw_device *cdev)
734 return 0; 736 return 0;
735} 737}
736 738
739static struct virtio_ccw_device *virtio_grab_drvdata(struct ccw_device *cdev)
740{
741 unsigned long flags;
742 struct virtio_ccw_device *vcdev;
743
744 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
745 vcdev = dev_get_drvdata(&cdev->dev);
746 if (!vcdev) {
747 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
748 return NULL;
749 }
750 dev_set_drvdata(&cdev->dev, NULL);
751 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
752 return vcdev;
753}
754
737static void virtio_ccw_remove(struct ccw_device *cdev) 755static void virtio_ccw_remove(struct ccw_device *cdev)
738{ 756{
739 struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); 757 struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
740 758
741 if (cdev->online) { 759 if (vcdev && cdev->online)
742 unregister_virtio_device(&vcdev->vdev); 760 unregister_virtio_device(&vcdev->vdev);
743 dev_set_drvdata(&cdev->dev, NULL);
744 }
745 cdev->handler = NULL; 761 cdev->handler = NULL;
746} 762}
747 763
748static int virtio_ccw_offline(struct ccw_device *cdev) 764static int virtio_ccw_offline(struct ccw_device *cdev)
749{ 765{
750 struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); 766 struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
751 767
752 unregister_virtio_device(&vcdev->vdev); 768 if (vcdev)
753 dev_set_drvdata(&cdev->dev, NULL); 769 unregister_virtio_device(&vcdev->vdev);
754 return 0; 770 return 0;
755} 771}
756 772
@@ -759,6 +775,7 @@ static int virtio_ccw_online(struct ccw_device *cdev)
759{ 775{
760 int ret; 776 int ret;
761 struct virtio_ccw_device *vcdev; 777 struct virtio_ccw_device *vcdev;
778 unsigned long flags;
762 779
763 vcdev = kzalloc(sizeof(*vcdev), GFP_KERNEL); 780 vcdev = kzalloc(sizeof(*vcdev), GFP_KERNEL);
764 if (!vcdev) { 781 if (!vcdev) {
@@ -786,7 +803,9 @@ static int virtio_ccw_online(struct ccw_device *cdev)
786 INIT_LIST_HEAD(&vcdev->virtqueues); 803 INIT_LIST_HEAD(&vcdev->virtqueues);
787 spin_lock_init(&vcdev->lock); 804 spin_lock_init(&vcdev->lock);
788 805
806 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
789 dev_set_drvdata(&cdev->dev, vcdev); 807 dev_set_drvdata(&cdev->dev, vcdev);
808 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
790 vcdev->vdev.id.vendor = cdev->id.cu_type; 809 vcdev->vdev.id.vendor = cdev->id.cu_type;
791 vcdev->vdev.id.device = cdev->id.cu_model; 810 vcdev->vdev.id.device = cdev->id.cu_model;
792 ret = register_virtio_device(&vcdev->vdev); 811 ret = register_virtio_device(&vcdev->vdev);
@@ -797,7 +816,9 @@ static int virtio_ccw_online(struct ccw_device *cdev)
797 } 816 }
798 return 0; 817 return 0;
799out_put: 818out_put:
819 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
800 dev_set_drvdata(&cdev->dev, NULL); 820 dev_set_drvdata(&cdev->dev, NULL);
821 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
801 put_device(&vcdev->vdev.dev); 822 put_device(&vcdev->vdev.dev);
802 return ret; 823 return ret;
803out_free: 824out_free: