From: Sasha Levin Date: Wed, 27 Nov 2019 14:27:47 +0000 (-0500) Subject: fixes for 4.9 X-Git-Tag: v4.4.204~17 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9afcf784cfcefbca37b8efda1aa143d9aead57de;p=thirdparty%2Fkernel%2Fstable-queue.git fixes for 4.9 Signed-off-by: Sasha Levin --- diff --git a/queue-4.9/series b/queue-4.9/series index 81639f1e696..55d5c5c625f 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -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 index 00000000000..d3a9f92240e --- /dev/null +++ b/queue-4.9/virtio_console-allocate-inbufs-in-add_port-only-if-i.patch @@ -0,0 +1,134 @@ +From b2a3754130c80ae9cfd62de52f4a95789c85226b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..3d98342a6c0 --- /dev/null +++ b/queue-4.9/virtio_console-don-t-tie-bufs-to-a-vq.patch @@ -0,0 +1,84 @@ +From d70fa69e576d57ed72fe5f8ac02d521c9eea2fb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Apr 2018 19:54:23 +0300 +Subject: virtio_console: don't tie bufs to a vq + +From: Michael S. Tsirkin + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..9f43548b0dd --- /dev/null +++ b/queue-4.9/virtio_console-drop-custom-control-queue-cleanup.patch @@ -0,0 +1,64 @@ +From 0b56b71d274a803d1e71c64f8d332835b9d8417c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Apr 2018 20:49:04 +0300 +Subject: virtio_console: drop custom control queue cleanup + +From: Michael S. Tsirkin + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..10b3739ad92 --- /dev/null +++ b/queue-4.9/virtio_console-fix-uninitialized-variable-use.patch @@ -0,0 +1,46 @@ +From 09e842f520117a693714a7d3eac8becc1ff77cdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Mar 2017 23:22:04 +0300 +Subject: virtio_console: fix uninitialized variable use + +From: Michael S. Tsirkin + +[ 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 +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..b7b76ddd745 --- /dev/null +++ b/queue-4.9/virtio_console-move-removal-code.patch @@ -0,0 +1,111 @@ +From 7ea4ae4a552dfdc0bef56ecdba7af2a0f1194546 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Apr 2018 20:51:18 +0300 +Subject: virtio_console: move removal code + +From: Michael S. Tsirkin + +[ Upstream commit aa44ec867030a72e8aa127977e37dec551d8df19 ] + +Will make it reusable for error handling. + +Cc: stable@vger.kernel.org +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..8c70ac91526 --- /dev/null +++ b/queue-4.9/virtio_console-reset-on-out-of-memory.patch @@ -0,0 +1,68 @@ +From 24f3db13ca87f53ca4c5fca4b50d49fb2b0f9c8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Apr 2018 21:00:13 +0300 +Subject: virtio_console: reset on out of memory + +From: Michael S. Tsirkin + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..67628adb3e4 --- /dev/null +++ b/queue-4.9/virtio_ring-fix-return-code-on-dma-mapping-fails.patch @@ -0,0 +1,48 @@ +From b905cff5988a7998d7e3b14ddaf776d5dff3577a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Nov 2019 13:46:46 +0100 +Subject: virtio_ring: fix return code on DMA mapping fails + +From: Halil Pasic + +[ 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 +Tested-by: Michael Mueller +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Sasha Levin +--- + 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 +