Commit 04e5b1fb authored by Johannes Berg's avatar Johannes Berg Committed by Richard Weinberger
Browse files

um: virtio: Remove device on disconnect



If the connection drops, just remove the device, we don't try
to recover from this right now.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 5c1f33e2
Loading
Loading
Loading
Loading
+45 −19
Original line number Diff line number Diff line
@@ -42,6 +42,13 @@
#define to_virtio_uml_device(_vdev) \
	container_of(_vdev, struct virtio_uml_device, vdev)

struct virtio_uml_platform_data {
	u32 virtio_device_id;
	const char *socket_path;
	struct work_struct conn_broken_wk;
	struct platform_device *pdev;
};

struct virtio_uml_device {
	struct virtio_device vdev;
	struct platform_device *pdev;
@@ -50,6 +57,7 @@ struct virtio_uml_device {
	u64 features;
	u64 protocol_features;
	u8 status;
	u8 registered:1;
};

struct virtio_uml_vq_info {
@@ -107,12 +115,21 @@ static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg)
	return full_read(fd, msg, sizeof(msg->header));
}

static int vhost_user_recv(int fd, struct vhost_user_msg *msg,
static int vhost_user_recv(struct virtio_uml_device *vu_dev,
			   int fd, struct vhost_user_msg *msg,
			   size_t max_payload_size)
{
	size_t size;
	int rc = vhost_user_recv_header(fd, msg);

	if (rc == -ECONNRESET && vu_dev->registered) {
		struct virtio_uml_platform_data *pdata;

		pdata = vu_dev->pdev->dev.platform_data;

		virtio_break_device(&vu_dev->vdev);
		schedule_work(&pdata->conn_broken_wk);
	}
	if (rc)
		return rc;
	size = msg->header.size;
@@ -125,7 +142,7 @@ static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev,
				struct vhost_user_msg *msg,
				size_t max_payload_size)
{
	int rc = vhost_user_recv(vu_dev->sock, msg, max_payload_size);
	int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg, max_payload_size);

	if (rc)
		return rc;
@@ -155,7 +172,7 @@ static int vhost_user_recv_req(struct virtio_uml_device *vu_dev,
			       struct vhost_user_msg *msg,
			       size_t max_payload_size)
{
	int rc = vhost_user_recv(vu_dev->req_fd, msg, max_payload_size);
	int rc = vhost_user_recv(vu_dev, vu_dev->req_fd, msg, max_payload_size);

	if (rc)
		return rc;
@@ -963,11 +980,6 @@ static void virtio_uml_release_dev(struct device *d)

/* Platform device */

struct virtio_uml_platform_data {
	u32 virtio_device_id;
	const char *socket_path;
};

static int virtio_uml_probe(struct platform_device *pdev)
{
	struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
@@ -1005,6 +1017,7 @@ static int virtio_uml_probe(struct platform_device *pdev)
	rc = register_virtio_device(&vu_dev->vdev);
	if (rc)
		put_device(&vu_dev->vdev.dev);
	vu_dev->registered = 1;
	return rc;

error_init:
@@ -1034,13 +1047,31 @@ static struct device vu_cmdline_parent = {
static bool vu_cmdline_parent_registered;
static int vu_cmdline_id;

static int vu_unregister_cmdline_device(struct device *dev, void *data)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;

	kfree(pdata->socket_path);
	platform_device_unregister(pdev);
	return 0;
}

static void vu_conn_broken(struct work_struct *wk)
{
	struct virtio_uml_platform_data *pdata;

	pdata = container_of(wk, struct virtio_uml_platform_data, conn_broken_wk);
	vu_unregister_cmdline_device(&pdata->pdev->dev, NULL);
}

static int vu_cmdline_set(const char *device, const struct kernel_param *kp)
{
	const char *ids = strchr(device, ':');
	unsigned int virtio_device_id;
	int processed, consumed, err;
	char *socket_path;
	struct virtio_uml_platform_data pdata;
	struct virtio_uml_platform_data pdata, *ppdata;
	struct platform_device *pdev;

	if (!ids || ids == device)
@@ -1079,6 +1110,11 @@ static int vu_cmdline_set(const char *device, const struct kernel_param *kp)
	err = PTR_ERR_OR_ZERO(pdev);
	if (err)
		goto free;

	ppdata = pdev->dev.platform_data;
	ppdata->pdev = pdev;
	INIT_WORK(&ppdata->conn_broken_wk, vu_conn_broken);

	return 0;

free:
@@ -1121,16 +1157,6 @@ __uml_help(vu_cmdline_param_ops,
);


static int vu_unregister_cmdline_device(struct device *dev, void *data)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;

	kfree(pdata->socket_path);
	platform_device_unregister(pdev);
	return 0;
}

static void vu_unregister_cmdline_devices(void)
{
	if (vu_cmdline_parent_registered) {