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

Commit 0644f186 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull virtio fixups from Michael Tsirkin:

 - Latest header update will break QEMU (if it's rebuilt with the new
   header) - and it seems that the code there is so fragile that any
   change in this header will break it. Add a better interface so users
   do not need to change their code every time that header changes.

 - Fix virtio console for spec compliance.

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost:
  virtio_console: reset on out of memory
  virtio_console: move removal code
  virtio_console: drop custom control queue cleanup
  virtio_console: free buffers after reset
  virtio: add ability to iterate over vqs
  virtio_console: don't tie bufs to a vq
  virtio_balloon: add array of stat names
parents 0871062b 5c60300d
Loading
Loading
Loading
Loading
+71 −86
Original line number Diff line number Diff line
@@ -422,7 +422,7 @@ static void reclaim_dma_bufs(void)
	}
}

static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
static struct port_buffer *alloc_buf(struct virtio_device *vdev, size_t buf_size,
				     int pages)
{
	struct port_buffer *buf;
@@ -445,16 +445,16 @@ static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
		return buf;
	}

	if (is_rproc_serial(vq->vdev)) {
	if (is_rproc_serial(vdev)) {
		/*
		 * Allocate DMA memory from ancestor. When a virtio
		 * device is created by remoteproc, the DMA memory is
		 * associated with the grandparent device:
		 * vdev => rproc => platform-dev.
		 */
		if (!vq->vdev->dev.parent || !vq->vdev->dev.parent->parent)
		if (!vdev->dev.parent || !vdev->dev.parent->parent)
			goto free_buf;
		buf->dev = vq->vdev->dev.parent->parent;
		buf->dev = vdev->dev.parent->parent;

		/* Increase device refcnt to avoid freeing it */
		get_device(buf->dev);
@@ -838,7 +838,7 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,

	count = min((size_t)(32 * 1024), count);

	buf = alloc_buf(port->out_vq, count, 0);
	buf = alloc_buf(port->portdev->vdev, count, 0);
	if (!buf)
		return -ENOMEM;

@@ -957,7 +957,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
	if (ret < 0)
		goto error_out;

	buf = alloc_buf(port->out_vq, 0, pipe->nrbufs);
	buf = alloc_buf(port->portdev->vdev, 0, pipe->nrbufs);
	if (!buf) {
		ret = -ENOMEM;
		goto error_out;
@@ -1374,7 +1374,7 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)

	nr_added_bufs = 0;
	do {
		buf = alloc_buf(vq, PAGE_SIZE, 0);
		buf = alloc_buf(vq->vdev, PAGE_SIZE, 0);
		if (!buf)
			break;

@@ -1402,7 +1402,6 @@ static int add_port(struct ports_device *portdev, u32 id)
{
	char debugfs_name[16];
	struct port *port;
	struct port_buffer *buf;
	dev_t devt;
	unsigned int nr_added_bufs;
	int err;
@@ -1513,8 +1512,6 @@ static int add_port(struct ports_device *portdev, u32 id)
	return 0;

free_inbufs:
	while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
		free_buf(buf, true);
free_device:
	device_destroy(pdrvdata.class, port->dev->devt);
free_cdev:
@@ -1539,34 +1536,14 @@ static void remove_port(struct kref *kref)

static void remove_port_data(struct port *port)
{
	struct port_buffer *buf;

	spin_lock_irq(&port->inbuf_lock);
	/* Remove unused data this port might have received. */
	discard_port_data(port);
	spin_unlock_irq(&port->inbuf_lock);

	/* Remove buffers we queued up for the Host to send us data in. */
	do {
		spin_lock_irq(&port->inbuf_lock);
		buf = virtqueue_detach_unused_buf(port->in_vq);
		spin_unlock_irq(&port->inbuf_lock);
		if (buf)
			free_buf(buf, true);
	} while (buf);

	spin_lock_irq(&port->outvq_lock);
	reclaim_consumed_buffers(port);
	spin_unlock_irq(&port->outvq_lock);

	/* Free pending buffers from the out-queue. */
	do {
		spin_lock_irq(&port->outvq_lock);
		buf = virtqueue_detach_unused_buf(port->out_vq);
		spin_unlock_irq(&port->outvq_lock);
		if (buf)
			free_buf(buf, true);
	} while (buf);
}

/*
@@ -1791,13 +1768,24 @@ static void control_work_handler(struct work_struct *work)
	spin_unlock(&portdev->c_ivq_lock);
}

static void flush_bufs(struct virtqueue *vq, bool can_sleep)
{
	struct port_buffer *buf;
	unsigned int len;

	while ((buf = virtqueue_get_buf(vq, &len)))
		free_buf(buf, can_sleep);
}

static void out_intr(struct virtqueue *vq)
{
	struct port *port;

	port = find_port_by_vq(vq->vdev->priv, vq);
	if (!port)
	if (!port) {
		flush_bufs(vq, false);
		return;
	}

	wake_up_interruptible(&port->waitqueue);
}
@@ -1808,8 +1796,10 @@ static void in_intr(struct virtqueue *vq)
	unsigned long flags;

	port = find_port_by_vq(vq->vdev->priv, vq);
	if (!port)
	if (!port) {
		flush_bufs(vq, false);
		return;
	}

	spin_lock_irqsave(&port->inbuf_lock, flags);
	port->inbuf = get_inbuf(port);
@@ -1984,24 +1974,54 @@ static const struct file_operations portdev_fops = {

static void remove_vqs(struct ports_device *portdev)
{
	struct virtqueue *vq;

	virtio_device_for_each_vq(portdev->vdev, vq) {
		struct port_buffer *buf;

		flush_bufs(vq, true);
		while ((buf = virtqueue_detach_unused_buf(vq)))
			free_buf(buf, true);
	}
	portdev->vdev->config->del_vqs(portdev->vdev);
	kfree(portdev->in_vqs);
	kfree(portdev->out_vqs);
}

static void remove_controlq_data(struct ports_device *portdev)
static void virtcons_remove(struct virtio_device *vdev)
{
	struct port_buffer *buf;
	unsigned int len;
	struct ports_device *portdev;
	struct port *port, *port2;

	if (!use_multiport(portdev))
		return;
	portdev = vdev->priv;

	while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
		free_buf(buf, true);
	spin_lock_irq(&pdrvdata_lock);
	list_del(&portdev->list);
	spin_unlock_irq(&pdrvdata_lock);

	while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
		free_buf(buf, true);
	/* Disable interrupts for vqs */
	vdev->config->reset(vdev);
	/* Finish up work that's lined up */
	if (use_multiport(portdev))
		cancel_work_sync(&portdev->control_work);
	else
		cancel_work_sync(&portdev->config_work);

	list_for_each_entry_safe(port, port2, &portdev->ports, list)
		unplug_port(port);

	unregister_chrdev(portdev->chr_major, "virtio-portsdev");

	/*
	 * When yanking out a device, we immediately lose the
	 * (device-side) queues.  So there's no point in keeping the
	 * guest side around till we drop our final reference.  This
	 * also means that any ports which are in an open state will
	 * have to just stop using the port, as the vqs are going
	 * away.
	 */
	remove_vqs(portdev);
	kfree(portdev);
}

/*
@@ -2070,6 +2090,7 @@ static int virtcons_probe(struct virtio_device *vdev)

	spin_lock_init(&portdev->ports_lock);
	INIT_LIST_HEAD(&portdev->ports);
	INIT_LIST_HEAD(&portdev->list);

	virtio_device_ready(portdev->vdev);

@@ -2087,8 +2108,15 @@ static int virtcons_probe(struct virtio_device *vdev)
		if (!nr_added_bufs) {
			dev_err(&vdev->dev,
				"Error allocating buffers for control queue\n");
			err = -ENOMEM;
			goto free_vqs;
			/*
			 * The host might want to notify mgmt sw about device
			 * add failure.
			 */
			__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
					   VIRTIO_CONSOLE_DEVICE_READY, 0);
			/* Device was functional: we need full cleanup. */
			virtcons_remove(vdev);
			return -ENOMEM;
		}
	} else {
		/*
@@ -2119,11 +2147,6 @@ static int virtcons_probe(struct virtio_device *vdev)

	return 0;

free_vqs:
	/* The host might want to notify mgmt sw about device add failure */
	__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
			   VIRTIO_CONSOLE_DEVICE_READY, 0);
	remove_vqs(portdev);
free_chrdev:
	unregister_chrdev(portdev->chr_major, "virtio-portsdev");
free:
@@ -2132,43 +2155,6 @@ static int virtcons_probe(struct virtio_device *vdev)
	return err;
}

static void virtcons_remove(struct virtio_device *vdev)
{
	struct ports_device *portdev;
	struct port *port, *port2;

	portdev = vdev->priv;

	spin_lock_irq(&pdrvdata_lock);
	list_del(&portdev->list);
	spin_unlock_irq(&pdrvdata_lock);

	/* Disable interrupts for vqs */
	vdev->config->reset(vdev);
	/* Finish up work that's lined up */
	if (use_multiport(portdev))
		cancel_work_sync(&portdev->control_work);
	else
		cancel_work_sync(&portdev->config_work);

	list_for_each_entry_safe(port, port2, &portdev->ports, list)
		unplug_port(port);

	unregister_chrdev(portdev->chr_major, "virtio-portsdev");

	/*
	 * When yanking out a device, we immediately lose the
	 * (device-side) queues.  So there's no point in keeping the
	 * guest side around till we drop our final reference.  This
	 * also means that any ports which are in an open state will
	 * have to just stop using the port, as the vqs are going
	 * away.
	 */
	remove_controlq_data(portdev);
	remove_vqs(portdev);
	kfree(portdev);
}

static struct virtio_device_id id_table[] = {
	{ VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
	{ 0 },
@@ -2209,7 +2195,6 @@ static int virtcons_freeze(struct virtio_device *vdev)
	 */
	if (use_multiport(portdev))
		virtqueue_disable_cb(portdev->c_ivq);
	remove_controlq_data(portdev);

	list_for_each_entry(port, &portdev->ports, list) {
		virtqueue_disable_cb(port->in_vq);
+3 −0
Original line number Diff line number Diff line
@@ -157,6 +157,9 @@ int virtio_device_freeze(struct virtio_device *dev);
int virtio_device_restore(struct virtio_device *dev);
#endif

#define virtio_device_for_each_vq(vdev, vq) \
	list_for_each_entry(vq, &vdev->vqs, list)

/**
 * virtio_driver - operations for a virtio I/O driver
 * @driver: underlying device driver (populate name and owner).
+15 −0
Original line number Diff line number Diff line
@@ -57,6 +57,21 @@ struct virtio_balloon_config {
#define VIRTIO_BALLOON_S_HTLB_PGFAIL   9  /* Hugetlb page allocation failures */
#define VIRTIO_BALLOON_S_NR       10

#define VIRTIO_BALLOON_S_NAMES_WITH_PREFIX(VIRTIO_BALLOON_S_NAMES_prefix) { \
	VIRTIO_BALLOON_S_NAMES_prefix "swap-in", \
	VIRTIO_BALLOON_S_NAMES_prefix "swap-out", \
	VIRTIO_BALLOON_S_NAMES_prefix "major-faults", \
	VIRTIO_BALLOON_S_NAMES_prefix "minor-faults", \
	VIRTIO_BALLOON_S_NAMES_prefix "free-memory", \
	VIRTIO_BALLOON_S_NAMES_prefix "total-memory", \
	VIRTIO_BALLOON_S_NAMES_prefix "available-memory", \
	VIRTIO_BALLOON_S_NAMES_prefix "disk-caches", \
	VIRTIO_BALLOON_S_NAMES_prefix "hugetlb-allocations", \
	VIRTIO_BALLOON_S_NAMES_prefix "hugetlb-failures" \
}

#define VIRTIO_BALLOON_S_NAMES VIRTIO_BALLOON_S_NAMES_WITH_PREFIX("")

/*
 * Memory statistics structure.
 * Driver fills an array of these structures and passes to device.