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

Commit e75279c4 authored by Heinz Graalfs's avatar Heinz Graalfs Committed by Rusty Russell
Browse files

virtio_ccw: introduce device_lost in virtio_ccw_device



When a device is lost, the common I/O layer calls the notification
handler with CIO_GONE: In that event, flag device_lost as true.

In case the device had been flagged as lost when the remove/offline callbacks
are called, call the new virtio_break_device() function prior to invoking
device_unregister(). This avoids hangs of I/O triggered via the device
unregistration callbacks.

Signed-off-by: default avatarHeinz Graalfs <graalfs@linux.vnet.ibm.com>
Reviewed-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent e2dcdfe9
Loading
Loading
Loading
Loading
+37 −12
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/kvm_para.h>
#include <linux/notifier.h>
#include <asm/setup.h>
#include <asm/irq.h>
#include <asm/cio.h>
@@ -62,6 +63,7 @@ struct virtio_ccw_device {
	struct vq_config_block *config_block;
	bool is_thinint;
	bool going_away;
	bool device_lost;
	void *airq_info;
};

@@ -1010,11 +1012,14 @@ static void virtio_ccw_remove(struct ccw_device *cdev)
	unsigned long flags;
	struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);

	if (vcdev && cdev->online)
	if (vcdev && cdev->online) {
		if (vcdev->device_lost)
			virtio_break_device(&vcdev->vdev);
		unregister_virtio_device(&vcdev->vdev);
		spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
		dev_set_drvdata(&cdev->dev, NULL);
		spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
	}
	cdev->handler = NULL;
}

@@ -1023,12 +1028,14 @@ static int virtio_ccw_offline(struct ccw_device *cdev)
	unsigned long flags;
	struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);

	if (vcdev) {
	if (!vcdev)
		return 0;
	if (vcdev->device_lost)
		virtio_break_device(&vcdev->vdev);
	unregister_virtio_device(&vcdev->vdev);
	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
	dev_set_drvdata(&cdev->dev, NULL);
	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
	}
	return 0;
}

@@ -1096,8 +1103,26 @@ static int virtio_ccw_online(struct ccw_device *cdev)

static int virtio_ccw_cio_notify(struct ccw_device *cdev, int event)
{
	/* TODO: Check whether we need special handling here. */
	return 0;
	int rc;
	struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);

	/*
	 * Make sure vcdev is set
	 * i.e. set_offline/remove callback not already running
	 */
	if (!vcdev)
		return NOTIFY_DONE;

	switch (event) {
	case CIO_GONE:
		vcdev->device_lost = true;
		rc = NOTIFY_DONE;
		break;
	default:
		rc = NOTIFY_DONE;
		break;
	}
	return rc;
}

static struct ccw_device_id virtio_ids[] = {