]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
fixes for 4.9
authorSasha Levin <sashal@kernel.org>
Wed, 27 Nov 2019 14:27:47 +0000 (09:27 -0500)
committerSasha Levin <sashal@kernel.org>
Wed, 27 Nov 2019 14:27:47 +0000 (09:27 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.9/series
queue-4.9/virtio_console-allocate-inbufs-in-add_port-only-if-i.patch [new file with mode: 0644]
queue-4.9/virtio_console-don-t-tie-bufs-to-a-vq.patch [new file with mode: 0644]
queue-4.9/virtio_console-drop-custom-control-queue-cleanup.patch [new file with mode: 0644]
queue-4.9/virtio_console-fix-uninitialized-variable-use.patch [new file with mode: 0644]
queue-4.9/virtio_console-move-removal-code.patch [new file with mode: 0644]
queue-4.9/virtio_console-reset-on-out-of-memory.patch [new file with mode: 0644]
queue-4.9/virtio_ring-fix-return-code-on-dma-mapping-fails.patch [new file with mode: 0644]

index 81639f1e696b4a71dcde78c31fac281281f5b0e8..55d5c5c625fe21fca1dc2fc67be66a524cc84e28 100644 (file)
@@ -129,3 +129,10 @@ media-uvcvideo-fix-error-path-in-control-parsing-failure.patch
 media-b2c2-flexcop-usb-add-sanity-checking.patch
 media-cxusb-detect-cxusb_ctrl_msg-error-in-query.patch
 media-imon-invalid-dereference-in-imon_touch_event.patch
+virtio_console-reset-on-out-of-memory.patch
+virtio_console-don-t-tie-bufs-to-a-vq.patch
+virtio_console-allocate-inbufs-in-add_port-only-if-i.patch
+virtio_ring-fix-return-code-on-dma-mapping-fails.patch
+virtio_console-fix-uninitialized-variable-use.patch
+virtio_console-drop-custom-control-queue-cleanup.patch
+virtio_console-move-removal-code.patch
diff --git a/queue-4.9/virtio_console-allocate-inbufs-in-add_port-only-if-i.patch b/queue-4.9/virtio_console-allocate-inbufs-in-add_port-only-if-i.patch
new file mode 100644 (file)
index 0000000..d3a9f92
--- /dev/null
@@ -0,0 +1,134 @@
+From b2a3754130c80ae9cfd62de52f4a95789c85226b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Nov 2019 13:25:48 +0100
+Subject: virtio_console: allocate inbufs in add_port() only if it is needed
+
+From: Laurent Vivier <lvivier@redhat.com>
+
+[ Upstream commit d791cfcbf98191122af70b053a21075cb450d119 ]
+
+When we hot unplug a virtserialport and then try to hot plug again,
+it fails:
+
+(qemu) chardev-add socket,id=serial0,path=/tmp/serial0,server,nowait
+(qemu) device_add virtserialport,bus=virtio-serial0.0,nr=2,\
+                  chardev=serial0,id=serial0,name=serial0
+(qemu) device_del serial0
+(qemu) device_add virtserialport,bus=virtio-serial0.0,nr=2,\
+                  chardev=serial0,id=serial0,name=serial0
+kernel error:
+  virtio-ports vport2p2: Error allocating inbufs
+qemu error:
+  virtio-serial-bus: Guest failure in adding port 2 for device \
+                     virtio-serial0.0
+
+This happens because buffers for the in_vq are allocated when the port is
+added but are not released when the port is unplugged.
+
+They are only released when virtconsole is removed (see a7a69ec0d8e4)
+
+To avoid the problem and to be symmetric, we could allocate all the buffers
+in init_vqs() as they are released in remove_vqs(), but it sounds like
+a waste of memory.
+
+Rather than that, this patch changes add_port() logic to ignore ENOSPC
+error in fill_queue(), which means queue has already been filled.
+
+Fixes: a7a69ec0d8e4 ("virtio_console: free buffers after reset")
+Cc: mst@redhat.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Laurent Vivier <lvivier@redhat.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/virtio_console.c | 28 +++++++++++++---------------
+ 1 file changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
+index b09fc4553dc81..d7ee031d776d8 100644
+--- a/drivers/char/virtio_console.c
++++ b/drivers/char/virtio_console.c
+@@ -1369,24 +1369,24 @@ static void set_console_size(struct port *port, u16 rows, u16 cols)
+       port->cons.ws.ws_col = cols;
+ }
+-static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
++static int fill_queue(struct virtqueue *vq, spinlock_t *lock)
+ {
+       struct port_buffer *buf;
+-      unsigned int nr_added_bufs;
++      int nr_added_bufs;
+       int ret;
+       nr_added_bufs = 0;
+       do {
+               buf = alloc_buf(vq->vdev, PAGE_SIZE, 0);
+               if (!buf)
+-                      break;
++                      return -ENOMEM;
+               spin_lock_irq(lock);
+               ret = add_inbuf(vq, buf);
+               if (ret < 0) {
+                       spin_unlock_irq(lock);
+                       free_buf(buf, true);
+-                      break;
++                      return ret;
+               }
+               nr_added_bufs++;
+               spin_unlock_irq(lock);
+@@ -1406,7 +1406,6 @@ static int add_port(struct ports_device *portdev, u32 id)
+       char debugfs_name[16];
+       struct port *port;
+       dev_t devt;
+-      unsigned int nr_added_bufs;
+       int err;
+       port = kmalloc(sizeof(*port), GFP_KERNEL);
+@@ -1465,11 +1464,13 @@ static int add_port(struct ports_device *portdev, u32 id)
+       spin_lock_init(&port->outvq_lock);
+       init_waitqueue_head(&port->waitqueue);
+-      /* Fill the in_vq with buffers so the host can send us data. */
+-      nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
+-      if (!nr_added_bufs) {
++      /* We can safely ignore ENOSPC because it means
++       * the queue already has buffers. Buffers are removed
++       * only by virtcons_remove(), not by unplug_port()
++       */
++      err = fill_queue(port->in_vq, &port->inbuf_lock);
++      if (err < 0 && err != -ENOSPC) {
+               dev_err(port->dev, "Error allocating inbufs\n");
+-              err = -ENOMEM;
+               goto free_device;
+       }
+@@ -2081,14 +2082,11 @@ static int virtcons_probe(struct virtio_device *vdev)
+       INIT_WORK(&portdev->control_work, &control_work_handler);
+       if (multiport) {
+-              unsigned int nr_added_bufs;
+-
+               spin_lock_init(&portdev->c_ivq_lock);
+               spin_lock_init(&portdev->c_ovq_lock);
+-              nr_added_bufs = fill_queue(portdev->c_ivq,
+-                                         &portdev->c_ivq_lock);
+-              if (!nr_added_bufs) {
++              err = fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
++              if (err < 0) {
+                       dev_err(&vdev->dev,
+                               "Error allocating buffers for control queue\n");
+                       /*
+@@ -2099,7 +2097,7 @@ static int virtcons_probe(struct virtio_device *vdev)
+                                          VIRTIO_CONSOLE_DEVICE_READY, 0);
+                       /* Device was functional: we need full cleanup. */
+                       virtcons_remove(vdev);
+-                      return -ENOMEM;
++                      return err;
+               }
+       } else {
+               /*
+-- 
+2.20.1
+
diff --git a/queue-4.9/virtio_console-don-t-tie-bufs-to-a-vq.patch b/queue-4.9/virtio_console-don-t-tie-bufs-to-a-vq.patch
new file mode 100644 (file)
index 0000000..3d98342
--- /dev/null
@@ -0,0 +1,84 @@
+From d70fa69e576d57ed72fe5f8ac02d521c9eea2fb9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Apr 2018 19:54:23 +0300
+Subject: virtio_console: don't tie bufs to a vq
+
+From: Michael S. Tsirkin <mst@redhat.com>
+
+[ Upstream commit 2855b33514d290c51d52d94e25d3ef942cd4d578 ]
+
+an allocated buffer doesn't need to be tied to a vq -
+only vq->vdev is ever used. Pass the function the
+just what it needs - the vdev.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/virtio_console.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
+index 43724bd8a0c0a..b09fc4553dc81 100644
+--- a/drivers/char/virtio_console.c
++++ b/drivers/char/virtio_console.c
+@@ -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,7 +445,7 @@ 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
+@@ -455,9 +455,9 @@ static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
+                * DMA_MEMORY_INCLUDES_CHILDREN had been supported
+                * in dma-coherent.c
+                */
+-              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);
+@@ -841,7 +841,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;
+@@ -960,7 +960,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;
+@@ -1377,7 +1377,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;
+-- 
+2.20.1
+
diff --git a/queue-4.9/virtio_console-drop-custom-control-queue-cleanup.patch b/queue-4.9/virtio_console-drop-custom-control-queue-cleanup.patch
new file mode 100644 (file)
index 0000000..9f43548
--- /dev/null
@@ -0,0 +1,64 @@
+From 0b56b71d274a803d1e71c64f8d332835b9d8417c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Apr 2018 20:49:04 +0300
+Subject: virtio_console: drop custom control queue cleanup
+
+From: Michael S. Tsirkin <mst@redhat.com>
+
+[ Upstream commit 61a8950c5c5708cf2068b29ffde94e454e528208 ]
+
+We now cleanup all VQs on device removal - no need
+to handle the control VQ specially.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/virtio_console.c | 17 -----------------
+ 1 file changed, 17 deletions(-)
+
+diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
+index 7de24040f39c1..8975ea08d6c01 100644
+--- a/drivers/char/virtio_console.c
++++ b/drivers/char/virtio_console.c
+@@ -1993,21 +1993,6 @@ static void remove_vqs(struct ports_device *portdev)
+       kfree(portdev->out_vqs);
+ }
+-static void remove_controlq_data(struct ports_device *portdev)
+-{
+-      struct port_buffer *buf;
+-      unsigned int len;
+-
+-      if (!use_multiport(portdev))
+-              return;
+-
+-      while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
+-              free_buf(buf, true);
+-
+-      while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
+-              free_buf(buf, true);
+-}
+-
+ /*
+  * Once we're further in boot, we get probed like any other virtio
+  * device.
+@@ -2168,7 +2153,6 @@ static void virtcons_remove(struct virtio_device *vdev)
+        * have to just stop using the port, as the vqs are going
+        * away.
+        */
+-      remove_controlq_data(portdev);
+       remove_vqs(portdev);
+       kfree(portdev);
+ }
+@@ -2213,7 +2197,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);
+-- 
+2.20.1
+
diff --git a/queue-4.9/virtio_console-fix-uninitialized-variable-use.patch b/queue-4.9/virtio_console-fix-uninitialized-variable-use.patch
new file mode 100644 (file)
index 0000000..10b3739
--- /dev/null
@@ -0,0 +1,46 @@
+From 09e842f520117a693714a7d3eac8becc1ff77cdf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Mar 2017 23:22:04 +0300
+Subject: virtio_console: fix uninitialized variable use
+
+From: Michael S. Tsirkin <mst@redhat.com>
+
+[ Upstream commit 2055997f983c6db7b5c3940ce5f8f822657d5bc3 ]
+
+We try to disable callbacks on c_ivq even without multiport
+even though that vq is not initialized in this configuration.
+
+Fixes: c743d09dbd01 ("virtio: console: Disable callbacks for virtqueues at start of S4 freeze")
+Suggested-by: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/virtio_console.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
+index d7ee031d776d8..7de24040f39c1 100644
+--- a/drivers/char/virtio_console.c
++++ b/drivers/char/virtio_console.c
+@@ -2203,14 +2203,16 @@ static int virtcons_freeze(struct virtio_device *vdev)
+       vdev->config->reset(vdev);
+-      virtqueue_disable_cb(portdev->c_ivq);
++      if (use_multiport(portdev))
++              virtqueue_disable_cb(portdev->c_ivq);
+       cancel_work_sync(&portdev->control_work);
+       cancel_work_sync(&portdev->config_work);
+       /*
+        * Once more: if control_work_handler() was running, it would
+        * enable the cb as the last step.
+        */
+-      virtqueue_disable_cb(portdev->c_ivq);
++      if (use_multiport(portdev))
++              virtqueue_disable_cb(portdev->c_ivq);
+       remove_controlq_data(portdev);
+       list_for_each_entry(port, &portdev->ports, list) {
+-- 
+2.20.1
+
diff --git a/queue-4.9/virtio_console-move-removal-code.patch b/queue-4.9/virtio_console-move-removal-code.patch
new file mode 100644 (file)
index 0000000..b7b76dd
--- /dev/null
@@ -0,0 +1,111 @@
+From 7ea4ae4a552dfdc0bef56ecdba7af2a0f1194546 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Apr 2018 20:51:18 +0300
+Subject: virtio_console: move removal code
+
+From: Michael S. Tsirkin <mst@redhat.com>
+
+[ Upstream commit aa44ec867030a72e8aa127977e37dec551d8df19 ]
+
+Will make it reusable for error handling.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/virtio_console.c | 72 +++++++++++++++++------------------
+ 1 file changed, 36 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
+index 8975ea08d6c01..34548d3b4d13c 100644
+--- a/drivers/char/virtio_console.c
++++ b/drivers/char/virtio_console.c
+@@ -1993,6 +1993,42 @@ static void remove_vqs(struct ports_device *portdev)
+       kfree(portdev->out_vqs);
+ }
++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_vqs(portdev);
++      kfree(portdev);
++}
++
+ /*
+  * Once we're further in boot, we get probed like any other virtio
+  * device.
+@@ -2121,42 +2157,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_vqs(portdev);
+-      kfree(portdev);
+-}
+-
+ static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
+       { 0 },
+-- 
+2.20.1
+
diff --git a/queue-4.9/virtio_console-reset-on-out-of-memory.patch b/queue-4.9/virtio_console-reset-on-out-of-memory.patch
new file mode 100644 (file)
index 0000000..8c70ac9
--- /dev/null
@@ -0,0 +1,68 @@
+From 24f3db13ca87f53ca4c5fca4b50d49fb2b0f9c8d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Apr 2018 21:00:13 +0300
+Subject: virtio_console: reset on out of memory
+
+From: Michael S. Tsirkin <mst@redhat.com>
+
+[ Upstream commit 5c60300d68da32ca77f7f978039dc72bfc78b06b ]
+
+When out of memory and we can't add ctrl vq buffers,
+probe fails. Unfortunately the error handling is
+out of spec: it calls del_vqs without bothering
+to reset the device first.
+
+To fix, call the full cleanup function in this case.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/virtio_console.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
+index 800ced0a5a247..43724bd8a0c0a 100644
+--- a/drivers/char/virtio_console.c
++++ b/drivers/char/virtio_console.c
+@@ -2073,6 +2073,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);
+@@ -2090,8 +2091,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 {
+               /*
+@@ -2122,11 +2130,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:
+-- 
+2.20.1
+
diff --git a/queue-4.9/virtio_ring-fix-return-code-on-dma-mapping-fails.patch b/queue-4.9/virtio_ring-fix-return-code-on-dma-mapping-fails.patch
new file mode 100644 (file)
index 0000000..67628ad
--- /dev/null
@@ -0,0 +1,48 @@
+From b905cff5988a7998d7e3b14ddaf776d5dff3577a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Nov 2019 13:46:46 +0100
+Subject: virtio_ring: fix return code on DMA mapping fails
+
+From: Halil Pasic <pasic@linux.ibm.com>
+
+[ Upstream commit f7728002c1c7bfa787b276a31c3ef458739b8e7c ]
+
+Commit 780bc7903a32 ("virtio_ring: Support DMA APIs")  makes
+virtqueue_add() return -EIO when we fail to map our I/O buffers. This is
+a very realistic scenario for guests with encrypted memory, as swiotlb
+may run out of space, depending on it's size and the I/O load.
+
+The virtio-blk driver interprets -EIO form virtqueue_add() as an IO
+error, despite the fact that swiotlb full is in absence of bugs a
+recoverable condition.
+
+Let us change the return code to -ENOMEM, and make the block layer
+recover form these failures when virtio-blk encounters the condition
+described above.
+
+Cc: stable@vger.kernel.org
+Fixes: 780bc7903a32 ("virtio_ring: Support DMA APIs")
+Signed-off-by: Halil Pasic <pasic@linux.ibm.com>
+Tested-by: Michael Mueller <mimu@linux.ibm.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/virtio/virtio_ring.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
+index 2f09294c59460..e459cd7302e27 100644
+--- a/drivers/virtio/virtio_ring.c
++++ b/drivers/virtio/virtio_ring.c
+@@ -427,7 +427,7 @@ unmap_release:
+               kfree(desc);
+       END_USE(vq);
+-      return -EIO;
++      return -ENOMEM;
+ }
+ /**
+-- 
+2.20.1
+