]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 27 Jan 2019 15:51:41 +0000 (16:51 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 27 Jan 2019 15:51:41 +0000 (16:51 +0100)
added patches:
drivers-hv-vmbus-check-for-ring-when-getting-debug-info.patch
hv_balloon-avoid-touching-uninitialized-struct-page-during-tail-onlining.patch
tty-handle-problem-if-line-discipline-does-not-have-receive_buf.patch
tty-n_hdlc-fix-__might_sleep-warning.patch
uart-fix-crash-in-uart_write-and-uart_put_char.patch
vgacon-unconfuse-vc_origin-when-using-soft-scrollback.patch

queue-4.19/drivers-hv-vmbus-check-for-ring-when-getting-debug-info.patch [new file with mode: 0644]
queue-4.19/hv_balloon-avoid-touching-uninitialized-struct-page-during-tail-onlining.patch [new file with mode: 0644]
queue-4.19/series
queue-4.19/tty-handle-problem-if-line-discipline-does-not-have-receive_buf.patch [new file with mode: 0644]
queue-4.19/tty-n_hdlc-fix-__might_sleep-warning.patch [new file with mode: 0644]
queue-4.19/uart-fix-crash-in-uart_write-and-uart_put_char.patch [new file with mode: 0644]
queue-4.19/vgacon-unconfuse-vc_origin-when-using-soft-scrollback.patch [new file with mode: 0644]

diff --git a/queue-4.19/drivers-hv-vmbus-check-for-ring-when-getting-debug-info.patch b/queue-4.19/drivers-hv-vmbus-check-for-ring-when-getting-debug-info.patch
new file mode 100644 (file)
index 0000000..74e57e9
--- /dev/null
@@ -0,0 +1,283 @@
+From ba50bf1ce9a51fc97db58b96d01306aa70bc3979 Mon Sep 17 00:00:00 2001
+From: Dexuan Cui <decui@microsoft.com>
+Date: Mon, 17 Dec 2018 20:16:09 +0000
+Subject: Drivers: hv: vmbus: Check for ring when getting debug info
+
+From: Dexuan Cui <decui@microsoft.com>
+
+commit ba50bf1ce9a51fc97db58b96d01306aa70bc3979 upstream.
+
+fc96df16a1ce is good and can already fix the "return stack garbage" issue,
+but let's also improve hv_ringbuffer_get_debuginfo(), which would silently
+return stack garbage, if people forget to check channel->state or
+ring_info->ring_buffer, when using the function in the future.
+
+Having an error check in the function would eliminate the potential risk.
+
+Add a Fixes tag to indicate the patch depdendency.
+
+Fixes: fc96df16a1ce ("Drivers: hv: vmbus: Return -EINVAL for the sys files for unopened channels")
+Cc: stable@vger.kernel.org
+Cc: K. Y. Srinivasan <kys@microsoft.com>
+Cc: Haiyang Zhang <haiyangz@microsoft.com>
+Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
+Signed-off-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/ring_buffer.c |   29 +++++++-------
+ drivers/hv/vmbus_drv.c   |   91 +++++++++++++++++++++++++++++++----------------
+ include/linux/hyperv.h   |    5 +-
+ 3 files changed, 78 insertions(+), 47 deletions(-)
+
+--- a/drivers/hv/ring_buffer.c
++++ b/drivers/hv/ring_buffer.c
+@@ -164,26 +164,25 @@ hv_get_ringbuffer_availbytes(const struc
+ }
+ /* Get various debug metrics for the specified ring buffer. */
+-void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
+-                               struct hv_ring_buffer_debug_info *debug_info)
++int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
++                              struct hv_ring_buffer_debug_info *debug_info)
+ {
+       u32 bytes_avail_towrite;
+       u32 bytes_avail_toread;
+-      if (ring_info->ring_buffer) {
+-              hv_get_ringbuffer_availbytes(ring_info,
+-                                      &bytes_avail_toread,
+-                                      &bytes_avail_towrite);
++      if (!ring_info->ring_buffer)
++              return -EINVAL;
+-              debug_info->bytes_avail_toread = bytes_avail_toread;
+-              debug_info->bytes_avail_towrite = bytes_avail_towrite;
+-              debug_info->current_read_index =
+-                      ring_info->ring_buffer->read_index;
+-              debug_info->current_write_index =
+-                      ring_info->ring_buffer->write_index;
+-              debug_info->current_interrupt_mask =
+-                      ring_info->ring_buffer->interrupt_mask;
+-      }
++      hv_get_ringbuffer_availbytes(ring_info,
++                                   &bytes_avail_toread,
++                                   &bytes_avail_towrite);
++      debug_info->bytes_avail_toread = bytes_avail_toread;
++      debug_info->bytes_avail_towrite = bytes_avail_towrite;
++      debug_info->current_read_index = ring_info->ring_buffer->read_index;
++      debug_info->current_write_index = ring_info->ring_buffer->write_index;
++      debug_info->current_interrupt_mask
++              = ring_info->ring_buffer->interrupt_mask;
++      return 0;
+ }
+ EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo);
+--- a/drivers/hv/vmbus_drv.c
++++ b/drivers/hv/vmbus_drv.c
+@@ -313,12 +313,16 @@ static ssize_t out_intr_mask_show(struct
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info outbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
++                                        &outbound);
++      if (ret < 0)
++              return ret;
++
+       return sprintf(buf, "%d\n", outbound.current_interrupt_mask);
+ }
+ static DEVICE_ATTR_RO(out_intr_mask);
+@@ -328,12 +332,15 @@ static ssize_t out_read_index_show(struc
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info outbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
++                                        &outbound);
++      if (ret < 0)
++              return ret;
+       return sprintf(buf, "%d\n", outbound.current_read_index);
+ }
+ static DEVICE_ATTR_RO(out_read_index);
+@@ -344,12 +351,15 @@ static ssize_t out_write_index_show(stru
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info outbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
++                                        &outbound);
++      if (ret < 0)
++              return ret;
+       return sprintf(buf, "%d\n", outbound.current_write_index);
+ }
+ static DEVICE_ATTR_RO(out_write_index);
+@@ -360,12 +370,15 @@ static ssize_t out_read_bytes_avail_show
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info outbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
++                                        &outbound);
++      if (ret < 0)
++              return ret;
+       return sprintf(buf, "%d\n", outbound.bytes_avail_toread);
+ }
+ static DEVICE_ATTR_RO(out_read_bytes_avail);
+@@ -376,12 +389,15 @@ static ssize_t out_write_bytes_avail_sho
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info outbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
++                                        &outbound);
++      if (ret < 0)
++              return ret;
+       return sprintf(buf, "%d\n", outbound.bytes_avail_towrite);
+ }
+ static DEVICE_ATTR_RO(out_write_bytes_avail);
+@@ -391,12 +407,15 @@ static ssize_t in_intr_mask_show(struct
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info inbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++      if (ret < 0)
++              return ret;
++
+       return sprintf(buf, "%d\n", inbound.current_interrupt_mask);
+ }
+ static DEVICE_ATTR_RO(in_intr_mask);
+@@ -406,12 +425,15 @@ static ssize_t in_read_index_show(struct
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info inbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++      if (ret < 0)
++              return ret;
++
+       return sprintf(buf, "%d\n", inbound.current_read_index);
+ }
+ static DEVICE_ATTR_RO(in_read_index);
+@@ -421,12 +443,15 @@ static ssize_t in_write_index_show(struc
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info inbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++      if (ret < 0)
++              return ret;
++
+       return sprintf(buf, "%d\n", inbound.current_write_index);
+ }
+ static DEVICE_ATTR_RO(in_write_index);
+@@ -437,12 +462,15 @@ static ssize_t in_read_bytes_avail_show(
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info inbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++      if (ret < 0)
++              return ret;
++
+       return sprintf(buf, "%d\n", inbound.bytes_avail_toread);
+ }
+ static DEVICE_ATTR_RO(in_read_bytes_avail);
+@@ -453,12 +481,15 @@ static ssize_t in_write_bytes_avail_show
+ {
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       struct hv_ring_buffer_debug_info inbound;
++      int ret;
+       if (!hv_dev->channel)
+               return -ENODEV;
+-      if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
+-              return -EINVAL;
+-      hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++
++      ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
++      if (ret < 0)
++              return ret;
++
+       return sprintf(buf, "%d\n", inbound.bytes_avail_towrite);
+ }
+ static DEVICE_ATTR_RO(in_write_bytes_avail);
+--- a/include/linux/hyperv.h
++++ b/include/linux/hyperv.h
+@@ -1166,8 +1166,9 @@ struct hv_ring_buffer_debug_info {
+       u32 bytes_avail_towrite;
+ };
+-void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
+-                          struct hv_ring_buffer_debug_info *debug_info);
++
++int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
++                              struct hv_ring_buffer_debug_info *debug_info);
+ /* Vmbus interface */
+ #define vmbus_driver_register(driver) \
diff --git a/queue-4.19/hv_balloon-avoid-touching-uninitialized-struct-page-during-tail-onlining.patch b/queue-4.19/hv_balloon-avoid-touching-uninitialized-struct-page-during-tail-onlining.patch
new file mode 100644 (file)
index 0000000..8510398
--- /dev/null
@@ -0,0 +1,71 @@
+From da8ced360ca8ad72d8f41f5c8fcd5b0e63e1555f Mon Sep 17 00:00:00 2001
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+Date: Fri, 4 Jan 2019 15:19:42 +0100
+Subject: hv_balloon: avoid touching uninitialized struct page during tail onlining
+
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+
+commit da8ced360ca8ad72d8f41f5c8fcd5b0e63e1555f upstream.
+
+Hyper-V memory hotplug protocol has 2M granularity and in Linux x86 we use
+128M. To deal with it we implement partial section onlining by registering
+custom page onlining callback (hv_online_page()). Later, when more memory
+arrives we try to online the 'tail' (see hv_bring_pgs_online()).
+
+It was found that in some cases this 'tail' onlining causes issues:
+
+ BUG: Bad page state in process kworker/0:2  pfn:109e3a
+ page:ffffe08344278e80 count:0 mapcount:1 mapping:0000000000000000 index:0x0
+ flags: 0xfffff80000000()
+ raw: 000fffff80000000 dead000000000100 dead000000000200 0000000000000000
+ raw: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+ page dumped because: nonzero mapcount
+ ...
+ Workqueue: events hot_add_req [hv_balloon]
+ Call Trace:
+  dump_stack+0x5c/0x80
+  bad_page.cold.112+0x7f/0xb2
+  free_pcppages_bulk+0x4b8/0x690
+  free_unref_page+0x54/0x70
+  hv_page_online_one+0x5c/0x80 [hv_balloon]
+  hot_add_req.cold.24+0x182/0x835 [hv_balloon]
+  ...
+
+Turns out that we now have deferred struct page initialization for memory
+hotplug so e.g. memory_block_action() in drivers/base/memory.c does
+pages_correctly_probed() check and in that check it avoids inspecting
+struct pages and checks sections instead. But in Hyper-V balloon driver we
+do PageReserved(pfn_to_page()) check and this is now wrong.
+
+Switch to checking online_section_nr() instead.
+
+Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/hv_balloon.c |   10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/hv/hv_balloon.c
++++ b/drivers/hv/hv_balloon.c
+@@ -888,12 +888,14 @@ static unsigned long handle_pg_range(uns
+                       pfn_cnt -= pgs_ol;
+                       /*
+                        * Check if the corresponding memory block is already
+-                       * online by checking its last previously backed page.
+-                       * In case it is we need to bring rest (which was not
+-                       * backed previously) online too.
++                       * online. It is possible to observe struct pages still
++                       * being uninitialized here so check section instead.
++                       * In case the section is online we need to bring the
++                       * rest of pfns (which were not backed previously)
++                       * online too.
+                        */
+                       if (start_pfn > has->start_pfn &&
+-                          !PageReserved(pfn_to_page(start_pfn - 1)))
++                          online_section_nr(pfn_to_section_nr(start_pfn)))
+                               hv_bring_pgs_online(has, start_pfn, pgs_ol);
+               }
index 4699e7ee3a7878c1e254ec8678318a3f0c43bfc7..9aec68818d3185aaede98f6160a0cd3846228a97 100644 (file)
@@ -44,3 +44,9 @@ char-mwave-fix-potential-spectre-v1-vulnerability.patch
 mmc-dw_mmc-bluefield-fix-the-license-information.patch
 mmc-meson-gx-free-irq-in-release-callback.patch
 staging-rtl8188eu-add-device-code-for-d-link-dwa-121-rev-b1.patch
+tty-handle-problem-if-line-discipline-does-not-have-receive_buf.patch
+uart-fix-crash-in-uart_write-and-uart_put_char.patch
+tty-n_hdlc-fix-__might_sleep-warning.patch
+hv_balloon-avoid-touching-uninitialized-struct-page-during-tail-onlining.patch
+drivers-hv-vmbus-check-for-ring-when-getting-debug-info.patch
+vgacon-unconfuse-vc_origin-when-using-soft-scrollback.patch
diff --git a/queue-4.19/tty-handle-problem-if-line-discipline-does-not-have-receive_buf.patch b/queue-4.19/tty-handle-problem-if-line-discipline-does-not-have-receive_buf.patch
new file mode 100644 (file)
index 0000000..f041e37
--- /dev/null
@@ -0,0 +1,33 @@
+From 27cfb3a53be46a54ec5e0bd04e51995b74c90343 Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Date: Sun, 20 Jan 2019 10:46:58 +0100
+Subject: tty: Handle problem if line discipline does not have receive_buf
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+commit 27cfb3a53be46a54ec5e0bd04e51995b74c90343 upstream.
+
+Some tty line disciplines do not have a receive buf callback, so
+properly check for that before calling it.  If they do not have this
+callback, just eat the character quietly, as we can't fail this call.
+
+Reported-by: Jann Horn <jannh@google.com>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/tty_io.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/tty_io.c
++++ b/drivers/tty/tty_io.c
+@@ -2188,7 +2188,8 @@ static int tiocsti(struct tty_struct *tt
+       ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return -EIO;
+-      ld->ops->receive_buf(tty, &ch, &mbz, 1);
++      if (ld->ops->receive_buf)
++              ld->ops->receive_buf(tty, &ch, &mbz, 1);
+       tty_ldisc_deref(ld);
+       return 0;
+ }
diff --git a/queue-4.19/tty-n_hdlc-fix-__might_sleep-warning.patch b/queue-4.19/tty-n_hdlc-fix-__might_sleep-warning.patch
new file mode 100644 (file)
index 0000000..c12bb4a
--- /dev/null
@@ -0,0 +1,42 @@
+From fc01d8c61ce02c034e67378cd3e645734bc18c8c Mon Sep 17 00:00:00 2001
+From: Paul Fulghum <paulkf@microgate.com>
+Date: Tue, 1 Jan 2019 12:28:53 -0800
+Subject: tty/n_hdlc: fix __might_sleep warning
+
+From: Paul Fulghum <paulkf@microgate.com>
+
+commit fc01d8c61ce02c034e67378cd3e645734bc18c8c upstream.
+
+Fix __might_sleep warning[1] in tty/n_hdlc.c read due to copy_to_user
+call while current is TASK_INTERRUPTIBLE.  This is a false positive
+since the code path does not depend on current state remaining
+TASK_INTERRUPTIBLE.  The loop breaks out and sets TASK_RUNNING after
+calling copy_to_user.
+
+This patch supresses the warning by setting TASK_RUNNING before calling
+copy_to_user.
+
+[1] https://syzkaller.appspot.com/bug?id=17d5de7f1fcab794cb8c40032f893f52de899324
+
+Signed-off-by: Paul Fulghum <paulkf@microgate.com>
+Reported-by: syzbot <syzbot+c244af085a0159d22879@syzkaller.appspotmail.com>
+Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: stable <stable@vger.kernel.org>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/n_hdlc.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/tty/n_hdlc.c
++++ b/drivers/tty/n_hdlc.c
+@@ -597,6 +597,7 @@ static ssize_t n_hdlc_tty_read(struct tt
+                               /* too large for caller's buffer */
+                               ret = -EOVERFLOW;
+                       } else {
++                              __set_current_state(TASK_RUNNING);
+                               if (copy_to_user(buf, rbuf->buf, rbuf->count))
+                                       ret = -EFAULT;
+                               else
diff --git a/queue-4.19/uart-fix-crash-in-uart_write-and-uart_put_char.patch b/queue-4.19/uart-fix-crash-in-uart_write-and-uart_put_char.patch
new file mode 100644 (file)
index 0000000..1e7a49e
--- /dev/null
@@ -0,0 +1,98 @@
+From aff9cf5955185d1f183227e46c5f8673fa483813 Mon Sep 17 00:00:00 2001
+From: Samir Virmani <samir@embedur.com>
+Date: Wed, 16 Jan 2019 10:28:07 -0800
+Subject: uart: Fix crash in uart_write and uart_put_char
+
+From: Samir Virmani <samir@embedur.com>
+
+commit aff9cf5955185d1f183227e46c5f8673fa483813 upstream.
+
+We were experiencing a crash similar to the one reported as part of
+commit:a5ba1d95e46e ("uart: fix race between uart_put_char() and
+uart_shutdown()") in our testbed as well. We continue to observe the same
+crash after integrating the commit a5ba1d95e46e ("uart: fix race between
+uart_put_char() and uart_shutdown()")
+
+On reviewing the change, the port lock should be taken prior to checking for
+if (!circ->buf) in fn. __uart_put_char and other fns. that update the buffer
+uart_state->xmit.
+
+Traceback:
+
+[11/27/2018 06:24:32.4870] Unable to handle kernel NULL pointer dereference
+                           at virtual address 0000003b
+
+[11/27/2018 06:24:32.4950] PC is at memcpy+0x48/0x180
+[11/27/2018 06:24:32.4950] LR is at uart_write+0x74/0x120
+[11/27/2018 06:24:32.4950] pc : [<ffffffc0002e6808>]
+                           lr : [<ffffffc0003747cc>] pstate: 000001c5
+[11/27/2018 06:24:32.4950] sp : ffffffc076433d30
+[11/27/2018 06:24:32.4950] x29: ffffffc076433d30 x28: 0000000000000140
+[11/27/2018 06:24:32.4950] x27: ffffffc0009b9d5e x26: ffffffc07ce36580
+[11/27/2018 06:24:32.4950] x25: 0000000000000000 x24: 0000000000000140
+[11/27/2018 06:24:32.4950] x23: ffffffc000891200 x22: ffffffc01fc34000
+[11/27/2018 06:24:32.4950] x21: 0000000000000fff x20: 0000000000000076
+[11/27/2018 06:24:32.4950] x19: 0000000000000076 x18: 0000000000000000
+[11/27/2018 06:24:32.4950] x17: 000000000047cf08 x16: ffffffc000099e68
+[11/27/2018 06:24:32.4950] x15: 0000000000000018 x14: 776d726966205948
+[11/27/2018 06:24:32.4950] x13: 50203a6c6974755f x12: 74647075205d3333
+[11/27/2018 06:24:32.4950] x11: 3a35323a36203831 x10: 30322f37322f3131
+[11/27/2018 06:24:32.4950] x9 : 5b205d303638342e x8 : 746164206f742070
+[11/27/2018 06:24:32.4950] x7 : 7520736920657261 x6 : 000000000000003b
+[11/27/2018 06:24:32.4950] x5 : 000000000000817a x4 : 0000000000000008
+[11/27/2018 06:24:32.4950] x3 : 2f37322f31312a5b x2 : 000000000000006e
+[11/27/2018 06:24:32.4950] x1 : ffffffc0009b9cf0 x0 : 000000000000003b
+
+[11/27/2018 06:24:32.4950] CPU2: stopping
+[11/27/2018 06:24:32.4950] CPU: 2 PID: 0 Comm: swapper/2 Tainted: P      D    O    4.1.51 #3
+[11/27/2018 06:24:32.4950] Hardware name: Broadcom-v8A (DT)
+[11/27/2018 06:24:32.4950] Call trace:
+[11/27/2018 06:24:32.4950] [<ffffffc0000883b8>] dump_backtrace+0x0/0x150
+[11/27/2018 06:24:32.4950] [<ffffffc00008851c>] show_stack+0x14/0x20
+[11/27/2018 06:24:32.4950] [<ffffffc0005ee810>] dump_stack+0x90/0xb0
+[11/27/2018 06:24:32.4950] [<ffffffc00008e844>] handle_IPI+0x18c/0x1a0
+[11/27/2018 06:24:32.4950] [<ffffffc000080c68>] gic_handle_irq+0x88/0x90
+
+Fixes: a5ba1d95e46e ("uart: fix race between uart_put_char() and uart_shutdown()")
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Samir Virmani <samir@embedur.com>
+Acked-by: Tycho Andersen <tycho@tycho.ws>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/serial/serial_core.c |   12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -550,10 +550,12 @@ static int uart_put_char(struct tty_stru
+       int ret = 0;
+       circ = &state->xmit;
+-      if (!circ->buf)
++      port = uart_port_lock(state, flags);
++      if (!circ->buf) {
++              uart_port_unlock(port, flags);
+               return 0;
++      }
+-      port = uart_port_lock(state, flags);
+       if (port && uart_circ_chars_free(circ) != 0) {
+               circ->buf[circ->head] = c;
+               circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
+@@ -586,11 +588,13 @@ static int uart_write(struct tty_struct
+               return -EL3HLT;
+       }
++      port = uart_port_lock(state, flags);
+       circ = &state->xmit;
+-      if (!circ->buf)
++      if (!circ->buf) {
++              uart_port_unlock(port, flags);
+               return 0;
++      }
+-      port = uart_port_lock(state, flags);
+       while (port) {
+               c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+               if (count < c)
diff --git a/queue-4.19/vgacon-unconfuse-vc_origin-when-using-soft-scrollback.patch b/queue-4.19/vgacon-unconfuse-vc_origin-when-using-soft-scrollback.patch
new file mode 100644 (file)
index 0000000..a2c9880
--- /dev/null
@@ -0,0 +1,71 @@
+From bfd8d8fe98b8792f362cd210a7873969f8d2fc04 Mon Sep 17 00:00:00 2001
+From: Nicolas Pitre <nicolas.pitre@linaro.org>
+Date: Thu, 10 Jan 2019 16:33:55 -0500
+Subject: vgacon: unconfuse vc_origin when using soft scrollback
+
+From: Nicolas Pitre <nicolas.pitre@linaro.org>
+
+commit bfd8d8fe98b8792f362cd210a7873969f8d2fc04 upstream.
+
+When CONFIG_VGACON_SOFT_SCROLLBACK is selected, the VGA display memory
+index and vc_visible_origin don't change when scrollback is activated.
+The actual screen content is saved away and the scrollbackdata is copied
+over it. However the vt code, and /dev/vcs devices in particular, still
+expect vc_origin to always point at the actual screen content not the
+displayed scrollback content.
+
+So adjust vc_origin to point at the saved screen content when scrollback
+is active and set it back to vc_visible_origin when restoring the screen.
+
+This fixes /dev/vcsa<n> that return scrollback content when they
+shouldn't (onli /dev/vcsa without a number should), and also fixes
+/dev/vcsu that should return scrollback content when scrollback is
+active but currently doesn't.
+
+An unnecessary call to vga_set_mem_top() is also removed.
+
+Signed-off-by: Nicolas Pitre <nico@linaro.org>
+Cc: stable@vger.kernel.org # v4.19+
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/video/console/vgacon.c |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/video/console/vgacon.c
++++ b/drivers/video/console/vgacon.c
+@@ -271,6 +271,7 @@ static void vgacon_scrollback_update(str
+ static void vgacon_restore_screen(struct vc_data *c)
+ {
++      c->vc_origin = c->vc_visible_origin;
+       vgacon_scrollback_cur->save = 0;
+       if (!vga_is_gfx && !vgacon_scrollback_cur->restore) {
+@@ -287,8 +288,7 @@ static void vgacon_scrolldelta(struct vc
+       int start, end, count, soff;
+       if (!lines) {
+-              c->vc_visible_origin = c->vc_origin;
+-              vga_set_mem_top(c);
++              vgacon_restore_screen(c);
+               return;
+       }
+@@ -298,6 +298,7 @@ static void vgacon_scrolldelta(struct vc
+       if (!vgacon_scrollback_cur->save) {
+               vgacon_cursor(c, CM_ERASE);
+               vgacon_save_screen(c);
++              c->vc_origin = (unsigned long)c->vc_screenbuf;
+               vgacon_scrollback_cur->save = 1;
+       }
+@@ -335,7 +336,7 @@ static void vgacon_scrolldelta(struct vc
+               int copysize;
+               int diff = c->vc_rows - count;
+-              void *d = (void *) c->vc_origin;
++              void *d = (void *) c->vc_visible_origin;
+               void *s = (void *) c->vc_screenbuf;
+               count *= c->vc_size_row;