aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-26 19:36:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-26 19:36:11 -0400
commit0644f186fc9d77bb5bd198369e59fb28927a3692 (patch)
tree7e0f70b944e564686167e3ec9ad00e47cec4b80f
parent0871062bf9c6e6f0cc91247b3e743a37b87a970f (diff)
parent5c60300d68da32ca77f7f978039dc72bfc78b06b (diff)
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
-rw-r--r--drivers/char/virtio_console.c157
-rw-r--r--include/linux/virtio.h3
-rw-r--r--include/uapi/linux/virtio_balloon.h15
3 files changed, 89 insertions, 86 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 468f06134012..21085515814f 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -422,7 +422,7 @@ static void reclaim_dma_bufs(void)
422 } 422 }
423} 423}
424 424
425static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, 425static struct port_buffer *alloc_buf(struct virtio_device *vdev, size_t buf_size,
426 int pages) 426 int pages)
427{ 427{
428 struct port_buffer *buf; 428 struct port_buffer *buf;
@@ -445,16 +445,16 @@ static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
445 return buf; 445 return buf;
446 } 446 }
447 447
448 if (is_rproc_serial(vq->vdev)) { 448 if (is_rproc_serial(vdev)) {
449 /* 449 /*
450 * Allocate DMA memory from ancestor. When a virtio 450 * Allocate DMA memory from ancestor. When a virtio
451 * device is created by remoteproc, the DMA memory is 451 * device is created by remoteproc, the DMA memory is
452 * associated with the grandparent device: 452 * associated with the grandparent device:
453 * vdev => rproc => platform-dev. 453 * vdev => rproc => platform-dev.
454 */ 454 */
455 if (!vq->vdev->dev.parent || !vq->vdev->dev.parent->parent) 455 if (!vdev->dev.parent || !vdev->dev.parent->parent)
456 goto free_buf; 456 goto free_buf;
457 buf->dev = vq->vdev->dev.parent->parent; 457 buf->dev = vdev->dev.parent->parent;
458 458
459 /* Increase device refcnt to avoid freeing it */ 459 /* Increase device refcnt to avoid freeing it */
460 get_device(buf->dev); 460 get_device(buf->dev);
@@ -838,7 +838,7 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
838 838
839 count = min((size_t)(32 * 1024), count); 839 count = min((size_t)(32 * 1024), count);
840 840
841 buf = alloc_buf(port->out_vq, count, 0); 841 buf = alloc_buf(port->portdev->vdev, count, 0);
842 if (!buf) 842 if (!buf)
843 return -ENOMEM; 843 return -ENOMEM;
844 844
@@ -957,7 +957,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
957 if (ret < 0) 957 if (ret < 0)
958 goto error_out; 958 goto error_out;
959 959
960 buf = alloc_buf(port->out_vq, 0, pipe->nrbufs); 960 buf = alloc_buf(port->portdev->vdev, 0, pipe->nrbufs);
961 if (!buf) { 961 if (!buf) {
962 ret = -ENOMEM; 962 ret = -ENOMEM;
963 goto error_out; 963 goto error_out;
@@ -1374,7 +1374,7 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
1374 1374
1375 nr_added_bufs = 0; 1375 nr_added_bufs = 0;
1376 do { 1376 do {
1377 buf = alloc_buf(vq, PAGE_SIZE, 0); 1377 buf = alloc_buf(vq->vdev, PAGE_SIZE, 0);
1378 if (!buf) 1378 if (!buf)
1379 break; 1379 break;
1380 1380
@@ -1402,7 +1402,6 @@ static int add_port(struct ports_device *portdev, u32 id)
1402{ 1402{
1403 char debugfs_name[16]; 1403 char debugfs_name[16];
1404 struct port *port; 1404 struct port *port;
1405 struct port_buffer *buf;
1406 dev_t devt; 1405 dev_t devt;
1407 unsigned int nr_added_bufs; 1406 unsigned int nr_added_bufs;
1408 int err; 1407 int err;
@@ -1513,8 +1512,6 @@ static int add_port(struct ports_device *portdev, u32 id)
1513 return 0; 1512 return 0;
1514 1513
1515free_inbufs: 1514free_inbufs:
1516 while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
1517 free_buf(buf, true);
1518free_device: 1515free_device:
1519 device_destroy(pdrvdata.class, port->dev->devt); 1516 device_destroy(pdrvdata.class, port->dev->devt);
1520free_cdev: 1517free_cdev:
@@ -1539,34 +1536,14 @@ static void remove_port(struct kref *kref)
1539 1536
1540static void remove_port_data(struct port *port) 1537static void remove_port_data(struct port *port)
1541{ 1538{
1542 struct port_buffer *buf;
1543
1544 spin_lock_irq(&port->inbuf_lock); 1539 spin_lock_irq(&port->inbuf_lock);
1545 /* Remove unused data this port might have received. */ 1540 /* Remove unused data this port might have received. */
1546 discard_port_data(port); 1541 discard_port_data(port);
1547 spin_unlock_irq(&port->inbuf_lock); 1542 spin_unlock_irq(&port->inbuf_lock);
1548 1543
1549 /* Remove buffers we queued up for the Host to send us data in. */
1550 do {
1551 spin_lock_irq(&port->inbuf_lock);
1552 buf = virtqueue_detach_unused_buf(port->in_vq);
1553 spin_unlock_irq(&port->inbuf_lock);
1554 if (buf)
1555 free_buf(buf, true);
1556 } while (buf);
1557
1558 spin_lock_irq(&port->outvq_lock); 1544 spin_lock_irq(&port->outvq_lock);
1559 reclaim_consumed_buffers(port); 1545 reclaim_consumed_buffers(port);
1560 spin_unlock_irq(&port->outvq_lock); 1546 spin_unlock_irq(&port->outvq_lock);
1561
1562 /* Free pending buffers from the out-queue. */
1563 do {
1564 spin_lock_irq(&port->outvq_lock);
1565 buf = virtqueue_detach_unused_buf(port->out_vq);
1566 spin_unlock_irq(&port->outvq_lock);
1567 if (buf)
1568 free_buf(buf, true);
1569 } while (buf);
1570} 1547}
1571 1548
1572/* 1549/*
@@ -1791,13 +1768,24 @@ static void control_work_handler(struct work_struct *work)
1791 spin_unlock(&portdev->c_ivq_lock); 1768 spin_unlock(&portdev->c_ivq_lock);
1792} 1769}
1793 1770
1771static void flush_bufs(struct virtqueue *vq, bool can_sleep)
1772{
1773 struct port_buffer *buf;
1774 unsigned int len;
1775
1776 while ((buf = virtqueue_get_buf(vq, &len)))
1777 free_buf(buf, can_sleep);
1778}
1779
1794static void out_intr(struct virtqueue *vq) 1780static void out_intr(struct virtqueue *vq)
1795{ 1781{
1796 struct port *port; 1782 struct port *port;
1797 1783
1798 port = find_port_by_vq(vq->vdev->priv, vq); 1784 port = find_port_by_vq(vq->vdev->priv, vq);
1799 if (!port) 1785 if (!port) {
1786 flush_bufs(vq, false);
1800 return; 1787 return;
1788 }
1801 1789
1802 wake_up_interruptible(&port->waitqueue); 1790 wake_up_interruptible(&port->waitqueue);
1803} 1791}
@@ -1808,8 +1796,10 @@ static void in_intr(struct virtqueue *vq)
1808 unsigned long flags; 1796 unsigned long flags;
1809 1797
1810 port = find_port_by_vq(vq->vdev->priv, vq); 1798 port = find_port_by_vq(vq->vdev->priv, vq);
1811 if (!port) 1799 if (!port) {
1800 flush_bufs(vq, false);
1812 return; 1801 return;
1802 }
1813 1803
1814 spin_lock_irqsave(&port->inbuf_lock, flags); 1804 spin_lock_irqsave(&port->inbuf_lock, flags);
1815 port->inbuf = get_inbuf(port); 1805 port->inbuf = get_inbuf(port);
@@ -1984,24 +1974,54 @@ static const struct file_operations portdev_fops = {
1984 1974
1985static void remove_vqs(struct ports_device *portdev) 1975static void remove_vqs(struct ports_device *portdev)
1986{ 1976{
1977 struct virtqueue *vq;
1978
1979 virtio_device_for_each_vq(portdev->vdev, vq) {
1980 struct port_buffer *buf;
1981
1982 flush_bufs(vq, true);
1983 while ((buf = virtqueue_detach_unused_buf(vq)))
1984 free_buf(buf, true);
1985 }
1987 portdev->vdev->config->del_vqs(portdev->vdev); 1986 portdev->vdev->config->del_vqs(portdev->vdev);
1988 kfree(portdev->in_vqs); 1987 kfree(portdev->in_vqs);<