--- /dev/null
+From 9972605a238339b85bd16b084eed5f18414d22db Mon Sep 17 00:00:00 2001
+From: Shakeel Butt <shakeel.butt@linux.dev>
+Date: Fri, 2 Aug 2024 16:58:22 -0700
+Subject: memcg: protect concurrent access to mem_cgroup_idr
+
+From: Shakeel Butt <shakeel.butt@linux.dev>
+
+commit 9972605a238339b85bd16b084eed5f18414d22db upstream.
+
+Commit 73f576c04b94 ("mm: memcontrol: fix cgroup creation failure after
+many small jobs") decoupled the memcg IDs from the CSS ID space to fix the
+cgroup creation failures. It introduced IDR to maintain the memcg ID
+space. The IDR depends on external synchronization mechanisms for
+modifications. For the mem_cgroup_idr, the idr_alloc() and idr_replace()
+happen within css callback and thus are protected through cgroup_mutex
+from concurrent modifications. However idr_remove() for mem_cgroup_idr
+was not protected against concurrency and can be run concurrently for
+different memcgs when they hit their refcnt to zero. Fix that.
+
+We have been seeing list_lru based kernel crashes at a low frequency in
+our fleet for a long time. These crashes were in different part of
+list_lru code including list_lru_add(), list_lru_del() and reparenting
+code. Upon further inspection, it looked like for a given object (dentry
+and inode), the super_block's list_lru didn't have list_lru_one for the
+memcg of that object. The initial suspicions were either the object is
+not allocated through kmem_cache_alloc_lru() or somehow
+memcg_list_lru_alloc() failed to allocate list_lru_one() for a memcg but
+returned success. No evidence were found for these cases.
+
+Looking more deeply, we started seeing situations where valid memcg's id
+is not present in mem_cgroup_idr and in some cases multiple valid memcgs
+have same id and mem_cgroup_idr is pointing to one of them. So, the most
+reasonable explanation is that these situations can happen due to race
+between multiple idr_remove() calls or race between
+idr_alloc()/idr_replace() and idr_remove(). These races are causing
+multiple memcgs to acquire the same ID and then offlining of one of them
+would cleanup list_lrus on the system for all of them. Later access from
+other memcgs to the list_lru cause crashes due to missing list_lru_one.
+
+Link: https://lkml.kernel.org/r/20240802235822.1830976-1-shakeel.butt@linux.dev
+Fixes: 73f576c04b94 ("mm: memcontrol: fix cgroup creation failure after many small jobs")
+Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
+Acked-by: Muchun Song <muchun.song@linux.dev>
+Reviewed-by: Roman Gushchin <roman.gushchin@linux.dev>
+Acked-by: Johannes Weiner <hannes@cmpxchg.org>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/memcontrol.c | 22 ++++++++++++++++++++--
+ 1 file changed, 20 insertions(+), 2 deletions(-)
+
+--- a/mm/memcontrol.c
++++ b/mm/memcontrol.c
+@@ -5568,11 +5568,28 @@ static struct cftype mem_cgroup_legacy_f
+
+ #define MEM_CGROUP_ID_MAX ((1UL << MEM_CGROUP_ID_SHIFT) - 1)
+ static DEFINE_IDR(mem_cgroup_idr);
++static DEFINE_SPINLOCK(memcg_idr_lock);
++
++static int mem_cgroup_alloc_id(void)
++{
++ int ret;
++
++ idr_preload(GFP_KERNEL);
++ spin_lock(&memcg_idr_lock);
++ ret = idr_alloc(&mem_cgroup_idr, NULL, 1, MEM_CGROUP_ID_MAX + 1,
++ GFP_NOWAIT);
++ spin_unlock(&memcg_idr_lock);
++ idr_preload_end();
++ return ret;
++}
+
+ static void mem_cgroup_id_remove(struct mem_cgroup *memcg)
+ {
+ if (memcg->id.id > 0) {
++ spin_lock(&memcg_idr_lock);
+ idr_remove(&mem_cgroup_idr, memcg->id.id);
++ spin_unlock(&memcg_idr_lock);
++
+ memcg->id.id = 0;
+ }
+ }
+@@ -5706,8 +5723,7 @@ static struct mem_cgroup *mem_cgroup_all
+ if (!memcg)
+ return ERR_PTR(error);
+
+- memcg->id.id = idr_alloc(&mem_cgroup_idr, NULL,
+- 1, MEM_CGROUP_ID_MAX + 1, GFP_KERNEL);
++ memcg->id.id = mem_cgroup_alloc_id();
+ if (memcg->id.id < 0) {
+ error = memcg->id.id;
+ goto fail;
+@@ -5854,7 +5870,9 @@ static int mem_cgroup_css_online(struct
+ * publish it here at the end of onlining. This matches the
+ * regular ID destruction during offlining.
+ */
++ spin_lock(&memcg_idr_lock);
+ idr_replace(&mem_cgroup_idr, memcg, memcg->id.id);
++ spin_unlock(&memcg_idr_lock);
+
+ return 0;
+ offline_kmem:
--- /dev/null
+From 6eabce6608d6f3440f4c03aa3d3ef50a47a3d193 Mon Sep 17 00:00:00 2001
+From: George Kennedy <george.kennedy@oracle.com>
+Date: Wed, 17 Jul 2024 07:24:38 -0500
+Subject: serial: core: check uartclk for zero to avoid divide by zero
+
+From: George Kennedy <george.kennedy@oracle.com>
+
+commit 6eabce6608d6f3440f4c03aa3d3ef50a47a3d193 upstream.
+
+Calling ioctl TIOCSSERIAL with an invalid baud_base can
+result in uartclk being zero, which will result in a
+divide by zero error in uart_get_divisor(). The check for
+uartclk being zero in uart_set_info() needs to be done
+before other settings are made as subsequent calls to
+ioctl TIOCSSERIAL for the same port would be impacted if
+the uartclk check was done where uartclk gets set.
+
+Oops: divide error: 0000 PREEMPT SMP KASAN PTI
+RIP: 0010:uart_get_divisor (drivers/tty/serial/serial_core.c:580)
+Call Trace:
+ <TASK>
+serial8250_get_divisor (drivers/tty/serial/8250/8250_port.c:2576
+ drivers/tty/serial/8250/8250_port.c:2589)
+serial8250_do_set_termios (drivers/tty/serial/8250/8250_port.c:502
+ drivers/tty/serial/8250/8250_port.c:2741)
+serial8250_set_termios (drivers/tty/serial/8250/8250_port.c:2862)
+uart_change_line_settings (./include/linux/spinlock.h:376
+ ./include/linux/serial_core.h:608 drivers/tty/serial/serial_core.c:222)
+uart_port_startup (drivers/tty/serial/serial_core.c:342)
+uart_startup (drivers/tty/serial/serial_core.c:368)
+uart_set_info (drivers/tty/serial/serial_core.c:1034)
+uart_set_info_user (drivers/tty/serial/serial_core.c:1059)
+tty_set_serial (drivers/tty/tty_io.c:2637)
+tty_ioctl (drivers/tty/tty_io.c:2647 drivers/tty/tty_io.c:2791)
+__x64_sys_ioctl (fs/ioctl.c:52 fs/ioctl.c:907
+ fs/ioctl.c:893 fs/ioctl.c:893)
+do_syscall_64 (arch/x86/entry/common.c:52
+ (discriminator 1) arch/x86/entry/common.c:83 (discriminator 1))
+entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
+
+Reported-by: syzkaller <syzkaller@googlegroups.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: George Kennedy <george.kennedy@oracle.com>
+Rule: add
+Link: https://lore.kernel.org/stable/1721148848-9784-1-git-send-email-george.kennedy%40oracle.com
+Link: https://lore.kernel.org/r/1721219078-3209-1-git-send-email-george.kennedy@oracle.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/serial_core.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -881,6 +881,14 @@ static int uart_set_info(struct tty_stru
+ new_flags = (__force upf_t)new_info->flags;
+ old_custom_divisor = uport->custom_divisor;
+
++ if (!(uport->flags & UPF_FIXED_PORT)) {
++ unsigned int uartclk = new_info->baud_base * 16;
++ /* check needs to be done here before other settings made */
++ if (uartclk == 0) {
++ retval = -EINVAL;
++ goto exit;
++ }
++ }
+ if (!capable(CAP_SYS_ADMIN)) {
+ retval = -EPERM;
+ if (change_irq || change_port ||
--- /dev/null
+From 7d3b793faaab1305994ce568b59d61927235f57b Mon Sep 17 00:00:00 2001
+From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+Date: Tue, 23 Jul 2024 08:53:01 -0400
+Subject: serial: sc16is7xx: fix invalid FIFO access with special register set
+
+From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+
+commit 7d3b793faaab1305994ce568b59d61927235f57b upstream.
+
+When enabling access to the special register set, Receiver time-out and
+RHR interrupts can happen. In this case, the IRQ handler will try to read
+from the FIFO thru the RHR register at address 0x00, but address 0x00 is
+mapped to DLL register, resulting in erroneous FIFO reading.
+
+Call graph example:
+ sc16is7xx_startup(): entry
+ sc16is7xx_ms_proc(): entry
+ sc16is7xx_set_termios(): entry
+ sc16is7xx_set_baud(): DLH/DLL = $009C --> access special register set
+ sc16is7xx_port_irq() entry --> IIR is 0x0C
+ sc16is7xx_handle_rx() entry
+ sc16is7xx_fifo_read(): --> unable to access FIFO (RHR) because it is
+ mapped to DLL (LCR=LCR_CONF_MODE_A)
+ sc16is7xx_set_baud(): exit --> Restore access to general register set
+
+Fix the problem by claiming the efr_lock mutex when accessing the Special
+register set.
+
+Fixes: dfeae619d781 ("serial: sc16is7xx")
+Cc: stable@vger.kernel.org
+Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+Link: https://lore.kernel.org/r/20240723125302.1305372-3-hugo@hugovil.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/sc16is7xx.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/tty/serial/sc16is7xx.c
++++ b/drivers/tty/serial/sc16is7xx.c
+@@ -591,6 +591,8 @@ static int sc16is7xx_set_baud(struct uar
+ SC16IS7XX_MCR_CLKSEL_BIT,
+ prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT);
+
++ mutex_lock(&one->efr_lock);
++
+ /* Backup LCR and access special register set (DLL/DLH) */
+ lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
+@@ -605,6 +607,8 @@ static int sc16is7xx_set_baud(struct uar
+ /* Restore LCR and access to general register set */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
+
++ mutex_unlock(&one->efr_lock);
++
+ return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div);
+ }
+
--- /dev/null
+From 133f4c00b8b2bfcacead9b81e7e8edfceb4b06c4 Mon Sep 17 00:00:00 2001
+From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+Date: Tue, 23 Jul 2024 08:53:00 -0400
+Subject: serial: sc16is7xx: fix TX fifo corruption
+
+From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+
+commit 133f4c00b8b2bfcacead9b81e7e8edfceb4b06c4 upstream.
+
+Sometimes, when a packet is received on channel A at almost the same time
+as a packet is about to be transmitted on channel B, we observe with a
+logic analyzer that the received packet on channel A is transmitted on
+channel B. In other words, the Tx buffer data on channel B is corrupted
+with data from channel A.
+
+The problem appeared since commit 4409df5866b7 ("serial: sc16is7xx: change
+EFR lock to operate on each channels"), which changed the EFR locking to
+operate on each channel instead of chip-wise.
+
+This commit has introduced a regression, because the EFR lock is used not
+only to protect the EFR registers access, but also, in a very obscure and
+undocumented way, to protect access to the data buffer, which is shared by
+the Tx and Rx handlers, but also by each channel of the IC.
+
+Fix this regression first by switching to kfifo_out_linear_ptr() in
+sc16is7xx_handle_tx() to eliminate the need for a shared Rx/Tx buffer.
+
+Secondly, replace the chip-wise Rx buffer with a separate Rx buffer for
+each channel.
+
+Fixes: 4409df5866b7 ("serial: sc16is7xx: change EFR lock to operate on each channels")
+Cc: stable@vger.kernel.org
+Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+Link: https://lore.kernel.org/r/20240723125302.1305372-2-hugo@hugovil.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/sc16is7xx.c | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+--- a/drivers/tty/serial/sc16is7xx.c
++++ b/drivers/tty/serial/sc16is7xx.c
+@@ -326,6 +326,7 @@ struct sc16is7xx_one {
+ struct kthread_work reg_work;
+ struct kthread_delayed_work ms_work;
+ struct sc16is7xx_one_config config;
++ unsigned char buf[SC16IS7XX_FIFO_SIZE]; /* Rx buffer. */
+ unsigned int old_mctrl;
+ u8 old_lcr; /* Value before EFR access. */
+ bool irda_mode;
+@@ -339,7 +340,6 @@ struct sc16is7xx_port {
+ unsigned long gpio_valid_mask;
+ #endif
+ u8 mctrl_mask;
+- unsigned char buf[SC16IS7XX_FIFO_SIZE];
+ struct kthread_worker kworker;
+ struct task_struct *kworker_task;
+ struct sc16is7xx_one p[];
+@@ -611,18 +611,18 @@ static int sc16is7xx_set_baud(struct uar
+ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
+ unsigned int iir)
+ {
+- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
++ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ unsigned int lsr = 0, bytes_read, i;
+ bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false;
+ u8 ch, flag;
+
+- if (unlikely(rxlen >= sizeof(s->buf))) {
++ if (unlikely(rxlen >= sizeof(one->buf))) {
+ dev_warn_ratelimited(port->dev,
+ "ttySC%i: Possible RX FIFO overrun: %d\n",
+ port->line, rxlen);
+ port->icount.buf_overrun++;
+ /* Ensure sanity of RX level */
+- rxlen = sizeof(s->buf);
++ rxlen = sizeof(one->buf);
+ }
+
+ while (rxlen) {
+@@ -635,10 +635,10 @@ static void sc16is7xx_handle_rx(struct u
+ lsr = 0;
+
+ if (read_lsr) {
+- s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
++ one->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
+ bytes_read = 1;
+ } else {
+- sc16is7xx_fifo_read(port, s->buf, rxlen);
++ sc16is7xx_fifo_read(port, one->buf, rxlen);
+ bytes_read = rxlen;
+ }
+
+@@ -671,7 +671,7 @@ static void sc16is7xx_handle_rx(struct u
+ }
+
+ for (i = 0; i < bytes_read; ++i) {
+- ch = s->buf[i];
++ ch = one->buf[i];
+ if (uart_handle_sysrq_char(port, ch))
+ continue;
+
+@@ -689,10 +689,10 @@ static void sc16is7xx_handle_rx(struct u
+
+ static void sc16is7xx_handle_tx(struct uart_port *port)
+ {
+- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ struct tty_port *tport = &port->state->port;
+ unsigned long flags;
+ unsigned int txlen;
++ unsigned char *tail;
+
+ if (unlikely(port->x_char)) {
+ sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char);
+@@ -717,8 +717,9 @@ static void sc16is7xx_handle_tx(struct u
+ txlen = 0;
+ }
+
+- txlen = uart_fifo_out(port, s->buf, txlen);
+- sc16is7xx_fifo_write(port, s->buf, txlen);
++ txlen = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen);
++ sc16is7xx_fifo_write(port, tail, txlen);
++ uart_xmit_advance(port, txlen);
+
+ uart_port_lock_irqsave(port, &flags);
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
tracefs-use-generic-inode-rcu-for-synchronizing-freeing.patch
ntp-safeguard-against-time_constant-overflow.patch
timekeeping-fix-bogus-clock_was_set-invocation-in-do_adjtimex.patch
+serial-core-check-uartclk-for-zero-to-avoid-divide-by-zero.patch
+serial-sc16is7xx-fix-tx-fifo-corruption.patch
+serial-sc16is7xx-fix-invalid-fifo-access-with-special-register-set.patch
+tty-vt-conmakehash-cope-with-abs_srctree-no-longer-in-env.patch
+memcg-protect-concurrent-access-to-mem_cgroup_idr.patch
--- /dev/null
+From 6e20753da6bc651e02378a0cdb78f16c42098c88 Mon Sep 17 00:00:00 2001
+From: Max Krummenacher <max.krummenacher@toradex.com>
+Date: Thu, 25 Jul 2024 15:20:45 +0200
+Subject: tty: vt: conmakehash: cope with abs_srctree no longer in env
+
+From: Max Krummenacher <max.krummenacher@toradex.com>
+
+commit 6e20753da6bc651e02378a0cdb78f16c42098c88 upstream.
+
+conmakehash uses getenv("abs_srctree") from the environment to strip
+the absolute path from the generated sources.
+However since commit e2bad142bb3d ("kbuild: unexport abs_srctree and
+abs_objtree") this environment variable no longer gets set.
+Instead use basename() to indicate the used file in a comment of the
+generated source file.
+
+Fixes: 3bd85c6c97b2 ("tty: vt: conmakehash: Don't mention the full path of the input in output")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Max Krummenacher <max.krummenacher@toradex.com>
+Link: https://lore.kernel.org/stable/20240725132056.9151-1-max.oss.09%40gmail.com
+Link: https://lore.kernel.org/r/20240725132056.9151-1-max.oss.09@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/vt/conmakehash.c | 20 +++++++-------------
+ 1 file changed, 7 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/tty/vt/conmakehash.c b/drivers/tty/vt/conmakehash.c
+index dc2177fec715..82d9db68b2ce 100644
+--- a/drivers/tty/vt/conmakehash.c
++++ b/drivers/tty/vt/conmakehash.c
+@@ -11,6 +11,8 @@
+ * Copyright (C) 1995-1997 H. Peter Anvin
+ */
+
++#include <libgen.h>
++#include <linux/limits.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <sysexits.h>
+@@ -76,8 +78,8 @@ static void addpair(int fp, int un)
+ int main(int argc, char *argv[])
+ {
+ FILE *ctbl;
+- const char *tblname, *rel_tblname;
+- const char *abs_srctree;
++ const char *tblname;
++ char base_tblname[PATH_MAX];
+ char buffer[65536];
+ int fontlen;
+ int i, nuni, nent;
+@@ -102,16 +104,6 @@ int main(int argc, char *argv[])
+ }
+ }
+
+- abs_srctree = getenv("abs_srctree");
+- if (abs_srctree && !strncmp(abs_srctree, tblname, strlen(abs_srctree)))
+- {
+- rel_tblname = tblname + strlen(abs_srctree);
+- while (*rel_tblname == '/')
+- ++rel_tblname;
+- }
+- else
+- rel_tblname = tblname;
+-
+ /* For now we assume the default font is always 256 characters. */
+ fontlen = 256;
+
+@@ -253,6 +245,8 @@ int main(int argc, char *argv[])
+ for ( i = 0 ; i < fontlen ; i++ )
+ nuni += unicount[i];
+
++ strncpy(base_tblname, tblname, PATH_MAX);
++ base_tblname[PATH_MAX - 1] = 0;
+ printf("\
+ /*\n\
+ * Do not edit this file; it was automatically generated by\n\
+@@ -264,7 +258,7 @@ int main(int argc, char *argv[])
+ #include <linux/types.h>\n\
+ \n\
+ u8 dfont_unicount[%d] = \n\
+-{\n\t", rel_tblname, fontlen);
++{\n\t", basename(base_tblname), fontlen);
+
+ for ( i = 0 ; i < fontlen ; i++ )
+ {
+--
+2.46.0
+