|
@@ -56,6 +56,7 @@ struct virtio_ccw_device {
|
|
|
unsigned int revision; /* Transport revision */
|
|
|
wait_queue_head_t wait_q;
|
|
|
spinlock_t lock;
|
|
|
+ struct mutex io_lock; /* Serializes I/O requests */
|
|
|
struct list_head virtqueues;
|
|
|
unsigned long indicators;
|
|
|
unsigned long indicators2;
|
|
@@ -296,6 +297,7 @@ static int ccw_io_helper(struct virtio_ccw_device *vcdev,
|
|
|
unsigned long flags;
|
|
|
int flag = intparm & VIRTIO_CCW_INTPARM_MASK;
|
|
|
|
|
|
+ mutex_lock(&vcdev->io_lock);
|
|
|
do {
|
|
|
spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags);
|
|
|
ret = ccw_device_start(vcdev->cdev, ccw, intparm, 0, 0);
|
|
@@ -308,7 +310,9 @@ static int ccw_io_helper(struct virtio_ccw_device *vcdev,
|
|
|
cpu_relax();
|
|
|
} while (ret == -EBUSY);
|
|
|
wait_event(vcdev->wait_q, doing_io(vcdev, flag) == 0);
|
|
|
- return ret ? ret : vcdev->err;
|
|
|
+ ret = ret ? ret : vcdev->err;
|
|
|
+ mutex_unlock(&vcdev->io_lock);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
|
|
@@ -1253,6 +1257,7 @@ static int virtio_ccw_online(struct ccw_device *cdev)
|
|
|
init_waitqueue_head(&vcdev->wait_q);
|
|
|
INIT_LIST_HEAD(&vcdev->virtqueues);
|
|
|
spin_lock_init(&vcdev->lock);
|
|
|
+ mutex_init(&vcdev->io_lock);
|
|
|
|
|
|
spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
|
|
|
dev_set_drvdata(&cdev->dev, vcdev);
|