提交 0644f186 编写于 作者: L Linus Torvalds

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
...@@ -422,7 +422,7 @@ static void reclaim_dma_bufs(void) ...@@ -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) int pages)
{ {
struct port_buffer *buf; struct port_buffer *buf;
...@@ -445,16 +445,16 @@ static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, ...@@ -445,16 +445,16 @@ static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
return buf; return buf;
} }
if (is_rproc_serial(vq->vdev)) { if (is_rproc_serial(vdev)) {
/* /*
* Allocate DMA memory from ancestor. When a virtio * Allocate DMA memory from ancestor. When a virtio
* device is created by remoteproc, the DMA memory is * device is created by remoteproc, the DMA memory is
* associated with the grandparent device: * associated with the grandparent device:
* vdev => rproc => platform-dev. * 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; goto free_buf;
buf->dev = vq->vdev->dev.parent->parent; buf->dev = vdev->dev.parent->parent;
/* Increase device refcnt to avoid freeing it */ /* Increase device refcnt to avoid freeing it */
get_device(buf->dev); get_device(buf->dev);
...@@ -838,7 +838,7 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, ...@@ -838,7 +838,7 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
count = min((size_t)(32 * 1024), count); 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) if (!buf)
return -ENOMEM; return -ENOMEM;
...@@ -957,7 +957,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, ...@@ -957,7 +957,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
if (ret < 0) if (ret < 0)
goto error_out; goto error_out;
buf = alloc_buf(port->out_vq, 0, pipe->nrbufs); buf = alloc_buf(port->portdev->vdev, 0, pipe->nrbufs);
if (!buf) { if (!buf) {
ret = -ENOMEM; ret = -ENOMEM;
goto error_out; goto error_out;
...@@ -1374,7 +1374,7 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) ...@@ -1374,7 +1374,7 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
nr_added_bufs = 0; nr_added_bufs = 0;
do { do {
buf = alloc_buf(vq, PAGE_SIZE, 0); buf = alloc_buf(vq->vdev, PAGE_SIZE, 0);
if (!buf) if (!buf)
break; break;
...@@ -1402,7 +1402,6 @@ static int add_port(struct ports_device *portdev, u32 id) ...@@ -1402,7 +1402,6 @@ static int add_port(struct ports_device *portdev, u32 id)
{ {
char debugfs_name[16]; char debugfs_name[16];
struct port *port; struct port *port;
struct port_buffer *buf;
dev_t devt; dev_t devt;
unsigned int nr_added_bufs; unsigned int nr_added_bufs;
int err; int err;
...@@ -1513,8 +1512,6 @@ static int add_port(struct ports_device *portdev, u32 id) ...@@ -1513,8 +1512,6 @@ static int add_port(struct ports_device *portdev, u32 id)
return 0; return 0;
free_inbufs: free_inbufs:
while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
free_buf(buf, true);
free_device: free_device:
device_destroy(pdrvdata.class, port->dev->devt); device_destroy(pdrvdata.class, port->dev->devt);
free_cdev: free_cdev:
...@@ -1539,34 +1536,14 @@ static void remove_port(struct kref *kref) ...@@ -1539,34 +1536,14 @@ static void remove_port(struct kref *kref)
static void remove_port_data(struct port *port) static void remove_port_data(struct port *port)
{ {
struct port_buffer *buf;
spin_lock_irq(&port->inbuf_lock); spin_lock_irq(&port->inbuf_lock);
/* Remove unused data this port might have received. */ /* Remove unused data this port might have received. */
discard_port_data(port); discard_port_data(port);
spin_unlock_irq(&port->inbuf_lock); 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); spin_lock_irq(&port->outvq_lock);
reclaim_consumed_buffers(port); reclaim_consumed_buffers(port);
spin_unlock_irq(&port->outvq_lock); 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) ...@@ -1791,13 +1768,24 @@ static void control_work_handler(struct work_struct *work)
spin_unlock(&portdev->c_ivq_lock); 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) static void out_intr(struct virtqueue *vq)
{ {
struct port *port; struct port *port;
port = find_port_by_vq(vq->vdev->priv, vq); port = find_port_by_vq(vq->vdev->priv, vq);
if (!port) if (!port) {
flush_bufs(vq, false);
return; return;
}
wake_up_interruptible(&port->waitqueue); wake_up_interruptible(&port->waitqueue);
} }
...@@ -1808,8 +1796,10 @@ static void in_intr(struct virtqueue *vq) ...@@ -1808,8 +1796,10 @@ static void in_intr(struct virtqueue *vq)
unsigned long flags; unsigned long flags;
port = find_port_by_vq(vq->vdev->priv, vq); port = find_port_by_vq(vq->vdev->priv, vq);
if (!port) if (!port) {
flush_bufs(vq, false);
return; return;
}
spin_lock_irqsave(&port->inbuf_lock, flags); spin_lock_irqsave(&port->inbuf_lock, flags);
port->inbuf = get_inbuf(port); port->inbuf = get_inbuf(port);
...@@ -1984,24 +1974,54 @@ static const struct file_operations portdev_fops = { ...@@ -1984,24 +1974,54 @@ static const struct file_operations portdev_fops = {
static void remove_vqs(struct ports_device *portdev) 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); portdev->vdev->config->del_vqs(portdev->vdev);
kfree(portdev->in_vqs); kfree(portdev->in_vqs);
kfree(portdev->out_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; struct ports_device *portdev;
unsigned int len; struct port *port, *port2;
if (!use_multiport(portdev)) portdev = vdev->priv;
return;
while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) spin_lock_irq(&pdrvdata_lock);
free_buf(buf, true); list_del(&portdev->list);
spin_unlock_irq(&pdrvdata_lock);
while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) /* Disable interrupts for vqs */
free_buf(buf, true); 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) ...@@ -2070,6 +2090,7 @@ static int virtcons_probe(struct virtio_device *vdev)
spin_lock_init(&portdev->ports_lock); spin_lock_init(&portdev->ports_lock);
INIT_LIST_HEAD(&portdev->ports); INIT_LIST_HEAD(&portdev->ports);
INIT_LIST_HEAD(&portdev->list);
virtio_device_ready(portdev->vdev); virtio_device_ready(portdev->vdev);
...@@ -2087,8 +2108,15 @@ static int virtcons_probe(struct virtio_device *vdev) ...@@ -2087,8 +2108,15 @@ static int virtcons_probe(struct virtio_device *vdev)
if (!nr_added_bufs) { if (!nr_added_bufs) {
dev_err(&vdev->dev, dev_err(&vdev->dev,
"Error allocating buffers for control queue\n"); "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 { } else {
/* /*
...@@ -2119,11 +2147,6 @@ static int virtcons_probe(struct virtio_device *vdev) ...@@ -2119,11 +2147,6 @@ static int virtcons_probe(struct virtio_device *vdev)
return 0; 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: free_chrdev:
unregister_chrdev(portdev->chr_major, "virtio-portsdev"); unregister_chrdev(portdev->chr_major, "virtio-portsdev");
free: free:
...@@ -2132,43 +2155,6 @@ static int virtcons_probe(struct virtio_device *vdev) ...@@ -2132,43 +2155,6 @@ static int virtcons_probe(struct virtio_device *vdev)
return err; 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[] = { static struct virtio_device_id id_table[] = {
{ VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
{ 0 }, { 0 },
...@@ -2209,7 +2195,6 @@ static int virtcons_freeze(struct virtio_device *vdev) ...@@ -2209,7 +2195,6 @@ static int virtcons_freeze(struct virtio_device *vdev)
*/ */
if (use_multiport(portdev)) if (use_multiport(portdev))
virtqueue_disable_cb(portdev->c_ivq); virtqueue_disable_cb(portdev->c_ivq);
remove_controlq_data(portdev);
list_for_each_entry(port, &portdev->ports, list) { list_for_each_entry(port, &portdev->ports, list) {
virtqueue_disable_cb(port->in_vq); virtqueue_disable_cb(port->in_vq);
......
...@@ -157,6 +157,9 @@ int virtio_device_freeze(struct virtio_device *dev); ...@@ -157,6 +157,9 @@ int virtio_device_freeze(struct virtio_device *dev);
int virtio_device_restore(struct virtio_device *dev); int virtio_device_restore(struct virtio_device *dev);
#endif #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 * virtio_driver - operations for a virtio I/O driver
* @driver: underlying device driver (populate name and owner). * @driver: underlying device driver (populate name and owner).
......
...@@ -57,6 +57,21 @@ struct virtio_balloon_config { ...@@ -57,6 +57,21 @@ struct virtio_balloon_config {
#define VIRTIO_BALLOON_S_HTLB_PGFAIL 9 /* Hugetlb page allocation failures */ #define VIRTIO_BALLOON_S_HTLB_PGFAIL 9 /* Hugetlb page allocation failures */
#define VIRTIO_BALLOON_S_NR 10 #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. * Memory statistics structure.
* Driver fills an array of these structures and passes to device. * Driver fills an array of these structures and passes to device.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册