mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	virtio: fixups
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. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJa4L3jAAoJECgfDbjSjVRpJiAIAMLVjPeMTsES6BX4duG/jhhc QmAflHg73Qmgvanbpqit/B1TRRsOsVnUGQ/4SubfQdEFZld8u/1ZNur9LKDika7h qhCM1HN9KN3O7E4IIF45i8jmsXoqBWOIb3BqBdAyeqNDWH4q48524IvYizPMgkDd ZnEZ/2pRi2HRstlwBD/JTcsfWRp/nUjarxnj8ZhUEUDFbJfjr7sPTeDwPSDShuIQ PrC9U8gliNRuxuq1v5Afn9F6mQptgvMxMLmtUqvYydlYgwu7cJUQ+Qxp8i7rNfM8 kCKkn/24UdUYHft4596bEEgDWR6nriMFCQAYKWlsCtwIvbZnURURl5TKT5ceI7Y= =N0il -----END PGP SIGNATURE----- Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost 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
This commit is contained in:
		
						commit
						0644f186fc
					
				
					 3 changed files with 89 additions and 86 deletions
				
			
		|  | @ -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 @@ fail: | |||
| 	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); | ||||
|  |  | |||
|  | @ -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). | ||||
|  |  | |||
|  | @ -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. | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Linus Torvalds
						Linus Torvalds