--- /dev/null
+From stable+bounces-213326-greg=kroah.com@vger.kernel.org Wed Feb 4 01:42:53 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Feb 2026 19:39:21 -0500
+Subject: drm/amdgpu/gfx11: adjust KGQ reset sequence
+To: stable@vger.kernel.org
+Cc: "Alex Deucher" <alexander.deucher@amd.com>, "Timur Kristóf" <timur.kristof@gmail.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260204003922.1467007-1-sashal@kernel.org>
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 3eb46fbb601f9a0b4df8eba79252a0a85e983044 ]
+
+Kernel gfx queues do not need to be reinitialized or
+remapped after a reset. This fixes queue reset failures
+on APUs.
+
+v2: preserve init and remap for MMIO case.
+
+Fixes: b3e9bfd86658 ("drm/amdgpu/gfx11: add ring reset callbacks")
+Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4789
+Reviewed-by: Timur Kristóf <timur.kristof@gmail.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit b340ff216fdabfe71ba0cdd47e9835a141d08e10)
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 45 +++++++++++++++++----------------
+ 1 file changed, 24 insertions(+), 21 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+@@ -6568,36 +6568,39 @@ static void gfx_v11_0_emit_mem_sync(stru
+ static int gfx_v11_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid)
+ {
+ struct amdgpu_device *adev = ring->adev;
++ bool use_mmio = false;
+ int r;
+
+ if (amdgpu_sriov_vf(adev))
+ return -EINVAL;
+
+- r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, false);
++ r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio);
+ if (r)
+ return r;
+
+- r = amdgpu_bo_reserve(ring->mqd_obj, false);
+- if (unlikely(r != 0)) {
+- dev_err(adev->dev, "fail to resv mqd_obj\n");
+- return r;
+- }
+- r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&ring->mqd_ptr);
+- if (!r) {
+- r = gfx_v11_0_kgq_init_queue(ring, true);
+- amdgpu_bo_kunmap(ring->mqd_obj);
+- ring->mqd_ptr = NULL;
+- }
+- amdgpu_bo_unreserve(ring->mqd_obj);
+- if (r) {
+- dev_err(adev->dev, "fail to unresv mqd_obj\n");
+- return r;
+- }
++ if (use_mmio) {
++ r = amdgpu_bo_reserve(ring->mqd_obj, false);
++ if (unlikely(r != 0)) {
++ dev_err(adev->dev, "fail to resv mqd_obj\n");
++ return r;
++ }
++ r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&ring->mqd_ptr);
++ if (!r) {
++ r = gfx_v11_0_kgq_init_queue(ring, true);
++ amdgpu_bo_kunmap(ring->mqd_obj);
++ ring->mqd_ptr = NULL;
++ }
++ amdgpu_bo_unreserve(ring->mqd_obj);
++ if (r) {
++ dev_err(adev->dev, "fail to unresv mqd_obj\n");
++ return r;
++ }
+
+- r = amdgpu_mes_map_legacy_queue(adev, ring);
+- if (r) {
+- dev_err(adev->dev, "failed to remap kgq\n");
+- return r;
++ r = amdgpu_mes_map_legacy_queue(adev, ring);
++ if (r) {
++ dev_err(adev->dev, "failed to remap kgq\n");
++ return r;
++ }
+ }
+
+ return amdgpu_ring_test_ring(ring);
--- /dev/null
+From stable+bounces-213293-greg=kroah.com@vger.kernel.org Tue Feb 3 18:53:18 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Feb 2026 12:50:55 -0500
+Subject: mptcp: avoid dup SUB_CLOSED events after disconnect
+To: stable@vger.kernel.org
+Cc: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Marco Angaroni <marco.angaroni@italtel.com>, Geliang Tang <geliang@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260203175055.1341617-1-sashal@kernel.org>
+
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+
+[ Upstream commit 280d654324e33f8e6e3641f76764694c7b64c5db ]
+
+In case of subflow disconnect(), which can also happen with the first
+subflow in case of errors like timeout or reset, mptcp_subflow_ctx_reset
+will reset most fields from the mptcp_subflow_context structure,
+including close_event_done. Then, when another subflow is closed, yet
+another SUB_CLOSED event for the disconnected initial subflow is sent.
+Because of the previous reset, there are no source address and
+destination port.
+
+A solution is then to also check the subflow's local id: it shouldn't be
+negative anyway.
+
+Another solution would be not to reset subflow->close_event_done at
+disconnect time, but when reused. But then, probably the whole reset
+could be done when being reused. Let's not change this logic, similar
+to TCP with tcp_disconnect().
+
+Fixes: d82809b6c5f2 ("mptcp: avoid duplicated SUB_CLOSED events")
+Cc: stable@vger.kernel.org
+Reported-by: Marco Angaroni <marco.angaroni@italtel.com>
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/603
+Reviewed-by: Geliang Tang <geliang@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260127-net-mptcp-dup-nl-events-v1-1-7f71e1bc4feb@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Adjust context ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/protocol.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -2591,8 +2591,8 @@ out:
+ void mptcp_close_ssk(struct sock *sk, struct sock *ssk,
+ struct mptcp_subflow_context *subflow)
+ {
+- /* The first subflow can already be closed and still in the list */
+- if (subflow->close_event_done)
++ /* The first subflow can already be closed or disconnected */
++ if (subflow->close_event_done || READ_ONCE(subflow->local_id) < 0)
+ return;
+
+ subflow->close_event_done = true;
--- /dev/null
+From stable+bounces-213310-greg=kroah.com@vger.kernel.org Tue Feb 3 21:47:16 2026
+From: longli@linux.microsoft.com
+Date: Tue, 3 Feb 2026 12:45:23 -0800
+Subject: net: mana: Change the function signature of mana_get_primary_netdev_rcu
+To: stable@vger.kernel.org, linux-kernel@vger.kernel.org
+Cc: Long Li <longli@microsoft.com>, Leon Romanovsky <leon@kernel.org>, stable@kernel.org
+Message-ID: <20260203204524.827567-1-longli@linux.microsoft.com>
+
+From: Long Li <longli@microsoft.com>
+
+commit a8445cfec101c42e9d64cdb2dac13973b22c205c upstream.
+
+Change mana_get_primary_netdev_rcu() to mana_get_primary_netdev(), and
+return the ndev with refcount held. The caller is responsible for dropping
+the refcount.
+
+Also drop the check for IFF_SLAVE as it is not necessary if the upper
+device is present.
+
+Signed-off-by: Long Li <longli@microsoft.com>
+Link: https://patch.msgid.link/1741821332-9392-1-git-send-email-longli@linuxonhyperv.com
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Fixes: 1df03a4b4414 ("RDMA/mana_ib: Set correct device into ib")
+Cc: stable@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/hw/mana/device.c | 7 +++----
+ drivers/infiniband/hw/mana/mana_ib.h | 1 +
+ drivers/net/ethernet/microsoft/mana/mana_en.c | 22 ++++++++++++++--------
+ include/net/mana/mana.h | 4 +++-
+ 4 files changed, 21 insertions(+), 13 deletions(-)
+
+--- a/drivers/infiniband/hw/mana/device.c
++++ b/drivers/infiniband/hw/mana/device.c
+@@ -84,10 +84,8 @@ static int mana_ib_probe(struct auxiliar
+ dev->ib_dev.num_comp_vectors = mdev->gdma_context->max_num_queues;
+ dev->ib_dev.dev.parent = mdev->gdma_context->dev;
+
+- rcu_read_lock(); /* required to get primary netdev */
+- ndev = mana_get_primary_netdev_rcu(mc, 0);
++ ndev = mana_get_primary_netdev(mc, 0, &dev->dev_tracker);
+ if (!ndev) {
+- rcu_read_unlock();
+ ret = -ENODEV;
+ ibdev_err(&dev->ib_dev, "Failed to get netdev for IB port 1");
+ goto free_ib_device;
+@@ -95,7 +93,8 @@ static int mana_ib_probe(struct auxiliar
+ ether_addr_copy(mac_addr, ndev->dev_addr);
+ addrconf_addr_eui48((u8 *)&dev->ib_dev.node_guid, ndev->dev_addr);
+ ret = ib_device_set_netdev(&dev->ib_dev, ndev, 1);
+- rcu_read_unlock();
++ /* mana_get_primary_netdev() returns ndev with refcount held */
++ netdev_put(ndev, &dev->dev_tracker);
+ if (ret) {
+ ibdev_err(&dev->ib_dev, "Failed to set ib netdev, ret %d", ret);
+ goto free_ib_device;
+--- a/drivers/infiniband/hw/mana/mana_ib.h
++++ b/drivers/infiniband/hw/mana/mana_ib.h
+@@ -64,6 +64,7 @@ struct mana_ib_dev {
+ struct gdma_queue **eqs;
+ struct xarray qp_table_wq;
+ struct mana_ib_adapter_caps adapter_caps;
++ netdevice_tracker dev_tracker;
+ };
+
+ struct mana_ib_wq {
+--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
+@@ -3000,21 +3000,27 @@ out:
+ kfree(ac);
+ }
+
+-struct net_device *mana_get_primary_netdev_rcu(struct mana_context *ac, u32 port_index)
++struct net_device *mana_get_primary_netdev(struct mana_context *ac,
++ u32 port_index,
++ netdevice_tracker *tracker)
+ {
+ struct net_device *ndev;
+
+- RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
+- "Taking primary netdev without holding the RCU read lock");
+ if (port_index >= ac->num_ports)
+ return NULL;
+
+- /* When mana is used in netvsc, the upper netdevice should be returned. */
+- if (ac->ports[port_index]->flags & IFF_SLAVE)
+- ndev = netdev_master_upper_dev_get_rcu(ac->ports[port_index]);
+- else
++ rcu_read_lock();
++
++ /* If mana is used in netvsc, the upper netdevice should be returned. */
++ ndev = netdev_master_upper_dev_get_rcu(ac->ports[port_index]);
++
++ /* If there is no upper device, use the parent Ethernet device */
++ if (!ndev)
+ ndev = ac->ports[port_index];
+
++ netdev_hold(ndev, tracker, GFP_ATOMIC);
++ rcu_read_unlock();
++
+ return ndev;
+ }
+-EXPORT_SYMBOL_NS(mana_get_primary_netdev_rcu, NET_MANA);
++EXPORT_SYMBOL_NS(mana_get_primary_netdev, NET_MANA);
+--- a/include/net/mana/mana.h
++++ b/include/net/mana/mana.h
+@@ -819,5 +819,7 @@ int mana_cfg_vport(struct mana_port_cont
+ u32 doorbell_pg_id);
+ void mana_uncfg_vport(struct mana_port_context *apc);
+
+-struct net_device *mana_get_primary_netdev_rcu(struct mana_context *ac, u32 port_index);
++struct net_device *mana_get_primary_netdev(struct mana_context *ac,
++ u32 port_index,
++ netdevice_tracker *tracker);
+ #endif /* _MANA_H */
--- /dev/null
+From stable+bounces-213295-greg=kroah.com@vger.kernel.org Tue Feb 3 18:53:24 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Feb 2026 12:51:12 -0500
+Subject: perf: sched: Fix perf crash with new is_user_task() helper
+To: stable@vger.kernel.org
+Cc: Steven Rostedt <rostedt@goodmis.org>, Guenter Roeck <linux@roeck-us.net>, "Peter Zijlstra (Intel)" <peterz@infradead.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260203175112.1341936-2-sashal@kernel.org>
+
+From: Steven Rostedt <rostedt@goodmis.org>
+
+[ Upstream commit 76ed27608f7dd235b727ebbb12163438c2fbb617 ]
+
+In order to do a user space stacktrace the current task needs to be a user
+task that has executed in user space. It use to be possible to test if a
+task is a user task or not by simply checking the task_struct mm field. If
+it was non NULL, it was a user task and if not it was a kernel task.
+
+But things have changed over time, and some kernel tasks now have their
+own mm field.
+
+An idea was made to instead test PF_KTHREAD and two functions were used to
+wrap this check in case it became more complex to test if a task was a
+user task or not[1]. But this was rejected and the C code simply checked
+the PF_KTHREAD directly.
+
+It was later found that not all kernel threads set PF_KTHREAD. The io-uring
+helpers instead set PF_USER_WORKER and this needed to be added as well.
+
+But checking the flags is still not enough. There's a very small window
+when a task exits that it frees its mm field and it is set back to NULL.
+If perf were to trigger at this moment, the flags test would say its a
+user space task but when perf would read the mm field it would crash with
+at NULL pointer dereference.
+
+Now there are flags that can be used to test if a task is exiting, but
+they are set in areas that perf may still want to profile the user space
+task (to see where it exited). The only real test is to check both the
+flags and the mm field.
+
+Instead of making this modification in every location, create a new
+is_user_task() helper function that does all the tests needed to know if
+it is safe to read the user space memory or not.
+
+[1] https://lore.kernel.org/all/20250425204120.639530125@goodmis.org/
+
+Fixes: 90942f9fac05 ("perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL")
+Closes: https://lore.kernel.org/all/0d877e6f-41a7-4724-875d-0b0a27b8a545@roeck-us.net/
+Reported-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Tested-by: Guenter Roeck <linux@roeck-us.net>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260129102821.46484722@gandalf.local.home
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/sched.h | 5 +++++
+ kernel/events/callchain.c | 2 +-
+ kernel/events/core.c | 6 +++---
+ 3 files changed, 9 insertions(+), 4 deletions(-)
+
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -1739,6 +1739,11 @@ static __always_inline bool is_percpu_th
+ #endif
+ }
+
++static __always_inline bool is_user_task(struct task_struct *task)
++{
++ return task->mm && !(task->flags & (PF_KTHREAD | PF_USER_WORKER));
++}
++
+ /* Per-process atomic flags. */
+ #define PFA_NO_NEW_PRIVS 0 /* May not gain new privileges. */
+ #define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */
+--- a/kernel/events/callchain.c
++++ b/kernel/events/callchain.c
+@@ -245,7 +245,7 @@ get_perf_callchain(struct pt_regs *regs,
+
+ if (user && !crosstask) {
+ if (!user_mode(regs)) {
+- if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
++ if (!is_user_task(current))
+ goto exit_put;
+ regs = task_pt_regs(current);
+ }
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -7095,7 +7095,7 @@ static void perf_sample_regs_user(struct
+ if (user_mode(regs)) {
+ regs_user->abi = perf_reg_abi(current);
+ regs_user->regs = regs;
+- } else if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
++ } else if (is_user_task(current)) {
+ perf_get_regs_user(regs_user, regs);
+ } else {
+ regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
+@@ -7735,7 +7735,7 @@ static u64 perf_virt_to_phys(u64 virt)
+ * Try IRQ-safe get_user_page_fast_only first.
+ * If failed, leave phys_addr as 0.
+ */
+- if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
++ if (is_user_task(current)) {
+ struct page *p;
+
+ pagefault_disable();
+@@ -7848,7 +7848,7 @@ perf_callchain(struct perf_event *event,
+ {
+ bool kernel = !event->attr.exclude_callchain_kernel;
+ bool user = !event->attr.exclude_callchain_user &&
+- !(current->flags & (PF_KTHREAD | PF_USER_WORKER));
++ is_user_task(current);
+ /* Disallow cross-task user callchains. */
+ bool crosstask = event->ctx->task && event->ctx->task != current;
+ const u32 max_stack = event->attr.sample_max_stack;
--- /dev/null
+From stable+bounces-213294-greg=kroah.com@vger.kernel.org Tue Feb 3 19:01:15 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Feb 2026 12:51:11 -0500
+Subject: perf: Simplify get_perf_callchain() user logic
+To: stable@vger.kernel.org
+Cc: Josh Poimboeuf <jpoimboe@kernel.org>, "Steven Rostedt (Google)" <rostedt@goodmis.org>, "Peter Zijlstra (Intel)" <peterz@infradead.org>, Namhyung Kim <namhyung@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260203175112.1341936-1-sashal@kernel.org>
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit d77e3319e31098a6cb97b7ce4e71ba676e327fd7 ]
+
+Simplify the get_perf_callchain() user logic a bit. task_pt_regs()
+should never be NULL.
+
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Acked-by: Namhyung Kim <namhyung@kernel.org>
+Link: https://lore.kernel.org/r/20250820180428.760066227@kernel.org
+Stable-dep-of: 76ed27608f7d ("perf: sched: Fix perf crash with new is_user_task() helper")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/events/callchain.c | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+--- a/kernel/events/callchain.c
++++ b/kernel/events/callchain.c
+@@ -246,21 +246,19 @@ get_perf_callchain(struct pt_regs *regs,
+ if (user && !crosstask) {
+ if (!user_mode(regs)) {
+ if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
+- regs = NULL;
+- else
+- regs = task_pt_regs(current);
++ goto exit_put;
++ regs = task_pt_regs(current);
+ }
+
+- if (regs) {
+- if (add_mark)
+- perf_callchain_store_context(&ctx, PERF_CONTEXT_USER);
++ if (add_mark)
++ perf_callchain_store_context(&ctx, PERF_CONTEXT_USER);
+
+- start_entry_idx = entry->nr;
+- perf_callchain_user(&ctx, regs);
+- fixup_uretprobe_trampoline_entries(entry, start_entry_idx);
+- }
++ start_entry_idx = entry->nr;
++ perf_callchain_user(&ctx, regs);
++ fixup_uretprobe_trampoline_entries(entry, start_entry_idx);
+ }
+
++exit_put:
+ put_callchain_entry(rctx);
+
+ return entry;
--- /dev/null
+From stable+bounces-213314-greg=kroah.com@vger.kernel.org Tue Feb 3 22:19:56 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Feb 2026 16:18:27 -0500
+Subject: pinctrl: lpass-lpi: implement .get_direction() for the GPIO driver
+To: stable@vger.kernel.org
+Cc: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>, Abel Vesa <abelvesa@kernel.org>, Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>, Abel Vesa <abel.vesa@oss.qualcomm.com>, Linus Walleij <linusw@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260203211827.1414472-1-sashal@kernel.org>
+
+From: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+
+[ Upstream commit 4f0d22ec60cee420125f4055af76caa0f373a3fe ]
+
+GPIO controller driver should typically implement the .get_direction()
+callback as GPIOLIB internals may try to use it to determine the state
+of a pin. Add it for the LPASS LPI driver.
+
+Reported-by: Abel Vesa <abelvesa@kernel.org>
+Cc: stable@vger.kernel.org
+Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver")
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Tested-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> # X1E CRD
+Tested-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
+Signed-off-by: Linus Walleij <linusw@kernel.org>
+[ PIN_CONFIG_LEVEL => PIN_CONFIG_OUTPUT ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
++++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
+@@ -298,6 +298,22 @@ static const struct pinconf_ops lpi_gpio
+ .pin_config_group_set = lpi_config_set,
+ };
+
++static int lpi_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
++{
++ unsigned long config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, 0);
++ struct lpi_pinctrl *state = gpiochip_get_data(chip);
++ unsigned long arg;
++ int ret;
++
++ ret = lpi_config_get(state->ctrl, pin, &config);
++ if (ret)
++ return ret;
++
++ arg = pinconf_to_config_argument(config);
++
++ return arg ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
++}
++
+ static int lpi_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
+ {
+ struct lpi_pinctrl *state = gpiochip_get_data(chip);
+@@ -395,6 +411,7 @@ static void lpi_gpio_dbg_show(struct seq
+ #endif
+
+ static const struct gpio_chip lpi_gpio_template = {
++ .get_direction = lpi_gpio_get_direction,
+ .direction_input = lpi_gpio_direction_input,
+ .direction_output = lpi_gpio_direction_output,
+ .get = lpi_gpio_get,
--- /dev/null
+From stable+bounces-213276-greg=kroah.com@vger.kernel.org Tue Feb 3 17:34:25 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Feb 2026 11:29:29 -0500
+Subject: pinctrl: qcom: sm8350-lpass-lpi: Merge with SC7280 to fix I2S2 and SWR TX pins
+To: stable@vger.kernel.org
+Cc: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>, Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>, Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>, Linus Walleij <linusw@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260203162929.1309413-1-sashal@kernel.org>
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
+
+[ Upstream commit 1fbe3abb449c5ef2178e1c3e3e8b9a43a7a410ac ]
+
+Qualcomm SC7280 and SM8350 SoCs have slightly different LPASS audio
+blocks (v9.4.5 and v9.2), however the LPASS LPI pin controllers are
+exactly the same. The driver for SM8350 has two issues, which can be
+fixed by simply moving over to SC7280 driver which has them correct:
+
+1. "i2s2_data_groups" listed twice GPIO12, but should have both GPIO12
+ and GPIO13,
+
+2. "swr_tx_data_groups" contained GPIO5 for "swr_tx_data2" function, but
+ that function is also available on GPIO14, thus listing it twice is
+ not necessary. OTOH, GPIO5 has also "swr_rx_data1", so selecting
+ swr_rx_data function should not block the TX one.
+
+Fixes: be9f6d56381d ("pinctrl: qcom: sm8350-lpass-lpi: add SM8350 LPASS TLMM")
+Cc: stable@vger.kernel.org
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
+Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Signed-off-by: Linus Walleij <linusw@kernel.org>
+[ .remove_new vs .remove ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/configs/defconfig | 1
+ drivers/pinctrl/qcom/Kconfig | 15 --
+ drivers/pinctrl/qcom/Makefile | 1
+ drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 3
+ drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c | 151 ------------------------
+ 5 files changed, 6 insertions(+), 165 deletions(-)
+ delete mode 100644 drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c
+
+--- a/arch/arm64/configs/defconfig
++++ b/arch/arm64/configs/defconfig
+@@ -635,7 +635,6 @@ CONFIG_PINCTRL_LPASS_LPI=m
+ CONFIG_PINCTRL_SC7280_LPASS_LPI=m
+ CONFIG_PINCTRL_SM6115_LPASS_LPI=m
+ CONFIG_PINCTRL_SM8250_LPASS_LPI=m
+-CONFIG_PINCTRL_SM8350_LPASS_LPI=m
+ CONFIG_PINCTRL_SM8450_LPASS_LPI=m
+ CONFIG_PINCTRL_SC8280XP_LPASS_LPI=m
+ CONFIG_PINCTRL_SM8550_LPASS_LPI=m
+--- a/drivers/pinctrl/qcom/Kconfig
++++ b/drivers/pinctrl/qcom/Kconfig
+@@ -60,13 +60,14 @@ config PINCTRL_LPASS_LPI
+ (Low Power Island) found on the Qualcomm Technologies Inc SoCs.
+
+ config PINCTRL_SC7280_LPASS_LPI
+- tristate "Qualcomm Technologies Inc SC7280 LPASS LPI pin controller driver"
++ tristate "Qualcomm Technologies Inc SC7280 and SM8350 LPASS LPI pin controller driver"
+ depends on ARM64 || COMPILE_TEST
+ depends on PINCTRL_LPASS_LPI
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) LPI
+- (Low Power Island) found on the Qualcomm Technologies Inc SC7280 platform.
++ (Low Power Island) found on the Qualcomm Technologies Inc SC7280
++ and SM8350 platforms.
+
+ config PINCTRL_SM4250_LPASS_LPI
+ tristate "Qualcomm Technologies Inc SM4250 LPASS LPI pin controller driver"
+@@ -95,16 +96,6 @@ config PINCTRL_SM8250_LPASS_LPI
+ Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) LPI
+ (Low Power Island) found on the Qualcomm Technologies Inc SM8250 platform.
+
+-config PINCTRL_SM8350_LPASS_LPI
+- tristate "Qualcomm Technologies Inc SM8350 LPASS LPI pin controller driver"
+- depends on ARM64 || COMPILE_TEST
+- depends on PINCTRL_LPASS_LPI
+- help
+- This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+- Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) LPI
+- (Low Power Island) found on the Qualcomm Technologies Inc SM8350
+- platform.
+-
+ config PINCTRL_SM8450_LPASS_LPI
+ tristate "Qualcomm Technologies Inc SM8450 LPASS LPI pin controller driver"
+ depends on ARM64 || COMPILE_TEST
+--- a/drivers/pinctrl/qcom/Makefile
++++ b/drivers/pinctrl/qcom/Makefile
+@@ -55,7 +55,6 @@ obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-
+ obj-$(CONFIG_PINCTRL_SM8250) += pinctrl-sm8250.o
+ obj-$(CONFIG_PINCTRL_SM8250_LPASS_LPI) += pinctrl-sm8250-lpass-lpi.o
+ obj-$(CONFIG_PINCTRL_SM8350) += pinctrl-sm8350.o
+-obj-$(CONFIG_PINCTRL_SM8350_LPASS_LPI) += pinctrl-sm8350-lpass-lpi.o
+ obj-$(CONFIG_PINCTRL_SM8450) += pinctrl-sm8450.o
+ obj-$(CONFIG_PINCTRL_SM8450_LPASS_LPI) += pinctrl-sm8450-lpass-lpi.o
+ obj-$(CONFIG_PINCTRL_SM8550) += pinctrl-sm8550.o
+--- a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c
++++ b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c
+@@ -131,6 +131,9 @@ static const struct of_device_id lpi_pin
+ {
+ .compatible = "qcom,sc7280-lpass-lpi-pinctrl",
+ .data = &sc7280_lpi_data,
++ }, {
++ .compatible = "qcom,sm8350-lpass-lpi-pinctrl",
++ .data = &sc7280_lpi_data,
+ },
+ { }
+ };
+--- a/drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c
++++ /dev/null
+@@ -1,151 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+-/*
+- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+- * Copyright (c) 2020-2023 Linaro Ltd.
+- */
+-
+-#include <linux/gpio/driver.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-
+-#include "pinctrl-lpass-lpi.h"
+-
+-enum lpass_lpi_functions {
+- LPI_MUX_dmic1_clk,
+- LPI_MUX_dmic1_data,
+- LPI_MUX_dmic2_clk,
+- LPI_MUX_dmic2_data,
+- LPI_MUX_dmic3_clk,
+- LPI_MUX_dmic3_data,
+- LPI_MUX_i2s1_clk,
+- LPI_MUX_i2s1_data,
+- LPI_MUX_i2s1_ws,
+- LPI_MUX_i2s2_clk,
+- LPI_MUX_i2s2_data,
+- LPI_MUX_i2s2_ws,
+- LPI_MUX_qua_mi2s_data,
+- LPI_MUX_qua_mi2s_sclk,
+- LPI_MUX_qua_mi2s_ws,
+- LPI_MUX_swr_rx_clk,
+- LPI_MUX_swr_rx_data,
+- LPI_MUX_swr_tx_clk,
+- LPI_MUX_swr_tx_data,
+- LPI_MUX_wsa_swr_clk,
+- LPI_MUX_wsa_swr_data,
+- LPI_MUX_gpio,
+- LPI_MUX__,
+-};
+-
+-static const struct pinctrl_pin_desc sm8350_lpi_pins[] = {
+- PINCTRL_PIN(0, "gpio0"),
+- PINCTRL_PIN(1, "gpio1"),
+- PINCTRL_PIN(2, "gpio2"),
+- PINCTRL_PIN(3, "gpio3"),
+- PINCTRL_PIN(4, "gpio4"),
+- PINCTRL_PIN(5, "gpio5"),
+- PINCTRL_PIN(6, "gpio6"),
+- PINCTRL_PIN(7, "gpio7"),
+- PINCTRL_PIN(8, "gpio8"),
+- PINCTRL_PIN(9, "gpio9"),
+- PINCTRL_PIN(10, "gpio10"),
+- PINCTRL_PIN(11, "gpio11"),
+- PINCTRL_PIN(12, "gpio12"),
+- PINCTRL_PIN(13, "gpio13"),
+- PINCTRL_PIN(14, "gpio14"),
+-};
+-
+-static const char * const swr_tx_clk_groups[] = { "gpio0" };
+-static const char * const swr_tx_data_groups[] = { "gpio1", "gpio2", "gpio5", "gpio14" };
+-static const char * const swr_rx_clk_groups[] = { "gpio3" };
+-static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5" };
+-static const char * const dmic1_clk_groups[] = { "gpio6" };
+-static const char * const dmic1_data_groups[] = { "gpio7" };
+-static const char * const dmic2_clk_groups[] = { "gpio8" };
+-static const char * const dmic2_data_groups[] = { "gpio9" };
+-static const char * const i2s2_clk_groups[] = { "gpio10" };
+-static const char * const i2s2_ws_groups[] = { "gpio11" };
+-static const char * const dmic3_clk_groups[] = { "gpio12" };
+-static const char * const dmic3_data_groups[] = { "gpio13" };
+-static const char * const qua_mi2s_sclk_groups[] = { "gpio0" };
+-static const char * const qua_mi2s_ws_groups[] = { "gpio1" };
+-static const char * const qua_mi2s_data_groups[] = { "gpio2", "gpio3", "gpio4" };
+-static const char * const i2s1_clk_groups[] = { "gpio6" };
+-static const char * const i2s1_ws_groups[] = { "gpio7" };
+-static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" };
+-static const char * const wsa_swr_clk_groups[] = { "gpio10" };
+-static const char * const wsa_swr_data_groups[] = { "gpio11" };
+-static const char * const i2s2_data_groups[] = { "gpio12", "gpio12" };
+-
+-static const struct lpi_pingroup sm8350_groups[] = {
+- LPI_PINGROUP(0, 0, swr_tx_clk, qua_mi2s_sclk, _, _),
+- LPI_PINGROUP(1, 2, swr_tx_data, qua_mi2s_ws, _, _),
+- LPI_PINGROUP(2, 4, swr_tx_data, qua_mi2s_data, _, _),
+- LPI_PINGROUP(3, 8, swr_rx_clk, qua_mi2s_data, _, _),
+- LPI_PINGROUP(4, 10, swr_rx_data, qua_mi2s_data, _, _),
+- LPI_PINGROUP(5, 12, swr_tx_data, swr_rx_data, _, _),
+- LPI_PINGROUP(6, LPI_NO_SLEW, dmic1_clk, i2s1_clk, _, _),
+- LPI_PINGROUP(7, LPI_NO_SLEW, dmic1_data, i2s1_ws, _, _),
+- LPI_PINGROUP(8, LPI_NO_SLEW, dmic2_clk, i2s1_data, _, _),
+- LPI_PINGROUP(9, LPI_NO_SLEW, dmic2_data, i2s1_data, _, _),
+- LPI_PINGROUP(10, 16, i2s2_clk, wsa_swr_clk, _, _),
+- LPI_PINGROUP(11, 18, i2s2_ws, wsa_swr_data, _, _),
+- LPI_PINGROUP(12, LPI_NO_SLEW, dmic3_clk, i2s2_data, _, _),
+- LPI_PINGROUP(13, LPI_NO_SLEW, dmic3_data, i2s2_data, _, _),
+- LPI_PINGROUP(14, 6, swr_tx_data, _, _, _),
+-};
+-
+-static const struct lpi_function sm8350_functions[] = {
+- LPI_FUNCTION(dmic1_clk),
+- LPI_FUNCTION(dmic1_data),
+- LPI_FUNCTION(dmic2_clk),
+- LPI_FUNCTION(dmic2_data),
+- LPI_FUNCTION(dmic3_clk),
+- LPI_FUNCTION(dmic3_data),
+- LPI_FUNCTION(i2s1_clk),
+- LPI_FUNCTION(i2s1_data),
+- LPI_FUNCTION(i2s1_ws),
+- LPI_FUNCTION(i2s2_clk),
+- LPI_FUNCTION(i2s2_data),
+- LPI_FUNCTION(i2s2_ws),
+- LPI_FUNCTION(qua_mi2s_data),
+- LPI_FUNCTION(qua_mi2s_sclk),
+- LPI_FUNCTION(qua_mi2s_ws),
+- LPI_FUNCTION(swr_rx_clk),
+- LPI_FUNCTION(swr_rx_data),
+- LPI_FUNCTION(swr_tx_clk),
+- LPI_FUNCTION(swr_tx_data),
+- LPI_FUNCTION(wsa_swr_clk),
+- LPI_FUNCTION(wsa_swr_data),
+-};
+-
+-static const struct lpi_pinctrl_variant_data sm8350_lpi_data = {
+- .pins = sm8350_lpi_pins,
+- .npins = ARRAY_SIZE(sm8350_lpi_pins),
+- .groups = sm8350_groups,
+- .ngroups = ARRAY_SIZE(sm8350_groups),
+- .functions = sm8350_functions,
+- .nfunctions = ARRAY_SIZE(sm8350_functions),
+-};
+-
+-static const struct of_device_id lpi_pinctrl_of_match[] = {
+- {
+- .compatible = "qcom,sm8350-lpass-lpi-pinctrl",
+- .data = &sm8350_lpi_data,
+- },
+- { }
+-};
+-MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match);
+-
+-static struct platform_driver lpi_pinctrl_driver = {
+- .driver = {
+- .name = "qcom-sm8350-lpass-lpi-pinctrl",
+- .of_match_table = lpi_pinctrl_of_match,
+- },
+- .probe = lpi_pinctrl_probe,
+- .remove_new = lpi_pinctrl_remove,
+-};
+-module_platform_driver(lpi_pinctrl_driver);
+-
+-MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
+-MODULE_DESCRIPTION("QTI SM8350 LPI GPIO pin control driver");
+-MODULE_LICENSE("GPL");
--- /dev/null
+From stable+bounces-213311-greg=kroah.com@vger.kernel.org Tue Feb 3 21:47:36 2026
+From: longli@linux.microsoft.com
+Date: Tue, 3 Feb 2026 12:45:24 -0800
+Subject: RDMA/mana_ib: Handle net event for pointing to the current netdev
+To: stable@vger.kernel.org, linux-kernel@vger.kernel.org
+Cc: Long Li <longli@microsoft.com>, Leon Romanovsky <leon@kernel.org>, stable@kernel.org
+Message-ID: <20260203204524.827567-2-longli@linux.microsoft.com>
+
+From: Long Li <longli@microsoft.com>
+
+commit bee35b7161aaaed9831e2f14876c374b9c566952 upstream.
+
+When running under Hyper-V, the master device to the RDMA device is always
+bonded to this RDMA device. This is not user-configurable.
+
+The master device can be unbind/bind from the kernel. During those events,
+the RDMA device should set to the current netdev to reflect the change of
+master device from those events.
+
+Signed-off-by: Long Li <longli@microsoft.com>
+Link: https://patch.msgid.link/1741821332-9392-2-git-send-email-longli@linuxonhyperv.com
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Fixes: 1df03a4b4414 ("RDMA/mana_ib: Set correct device into ib")
+Cc: stable@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/hw/mana/device.c | 47 +++++++++++++++++++++++++++++++++--
+ drivers/infiniband/hw/mana/mana_ib.h | 1
+ 2 files changed, 46 insertions(+), 2 deletions(-)
+
+--- a/drivers/infiniband/hw/mana/device.c
++++ b/drivers/infiniband/hw/mana/device.c
+@@ -51,6 +51,38 @@ static const struct ib_device_ops mana_i
+ ib_ind_table),
+ };
+
++static int mana_ib_netdev_event(struct notifier_block *this,
++ unsigned long event, void *ptr)
++{
++ struct mana_ib_dev *dev = container_of(this, struct mana_ib_dev, nb);
++ struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
++ struct gdma_context *gc = dev->gdma_dev->gdma_context;
++ struct mana_context *mc = gc->mana.driver_data;
++ struct net_device *ndev;
++
++ /* Only process events from our parent device */
++ if (event_dev != mc->ports[0])
++ return NOTIFY_DONE;
++
++ switch (event) {
++ case NETDEV_CHANGEUPPER:
++ ndev = mana_get_primary_netdev(mc, 0, &dev->dev_tracker);
++ /*
++ * RDMA core will setup GID based on updated netdev.
++ * It's not possible to race with the core as rtnl lock is being
++ * held.
++ */
++ ib_device_set_netdev(&dev->ib_dev, ndev, 1);
++
++ /* mana_get_primary_netdev() returns ndev with refcount held */
++ netdev_put(ndev, &dev->dev_tracker);
++
++ return NOTIFY_OK;
++ default:
++ return NOTIFY_DONE;
++ }
++}
++
+ static int mana_ib_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+ {
+@@ -108,17 +140,25 @@ static int mana_ib_probe(struct auxiliar
+ }
+ dev->gdma_dev = &mdev->gdma_context->mana_ib;
+
++ dev->nb.notifier_call = mana_ib_netdev_event;
++ ret = register_netdevice_notifier(&dev->nb);
++ if (ret) {
++ ibdev_err(&dev->ib_dev, "Failed to register net notifier, %d",
++ ret);
++ goto deregister_device;
++ }
++
+ ret = mana_ib_gd_query_adapter_caps(dev);
+ if (ret) {
+ ibdev_err(&dev->ib_dev, "Failed to query device caps, ret %d",
+ ret);
+- goto deregister_device;
++ goto deregister_net_notifier;
+ }
+
+ ret = mana_ib_create_eqs(dev);
+ if (ret) {
+ ibdev_err(&dev->ib_dev, "Failed to create EQs, ret %d", ret);
+- goto deregister_device;
++ goto deregister_net_notifier;
+ }
+
+ ret = mana_ib_gd_create_rnic_adapter(dev);
+@@ -147,6 +187,8 @@ destroy_rnic:
+ mana_ib_gd_destroy_rnic_adapter(dev);
+ destroy_eqs:
+ mana_ib_destroy_eqs(dev);
++deregister_net_notifier:
++ unregister_netdevice_notifier(&dev->nb);
+ deregister_device:
+ mana_gd_deregister_device(dev->gdma_dev);
+ free_ib_device:
+@@ -162,6 +204,7 @@ static void mana_ib_remove(struct auxili
+ xa_destroy(&dev->qp_table_wq);
+ mana_ib_gd_destroy_rnic_adapter(dev);
+ mana_ib_destroy_eqs(dev);
++ unregister_netdevice_notifier(&dev->nb);
+ mana_gd_deregister_device(dev->gdma_dev);
+ ib_dealloc_device(&dev->ib_dev);
+ }
+--- a/drivers/infiniband/hw/mana/mana_ib.h
++++ b/drivers/infiniband/hw/mana/mana_ib.h
+@@ -65,6 +65,7 @@ struct mana_ib_dev {
+ struct xarray qp_table_wq;
+ struct mana_ib_adapter_caps adapter_caps;
+ netdevice_tracker dev_tracker;
++ struct notifier_block nb;
+ };
+
+ struct mana_ib_wq {
revert-drm-nouveau-disp-set-drm_mode_config_funcs.atomic_-check-commit.patch
btrfs-prevent-use-after-free-on-folio-private-data-in-btrfs_subpage_clear_uptodate.patch
net-sched-act_ife-convert-comma-to-semicolon.patch
+pinctrl-qcom-sm8350-lpass-lpi-merge-with-sc7280-to-fix-i2s2-and-swr-tx-pins.patch
+mptcp-avoid-dup-sub_closed-events-after-disconnect.patch
+perf-simplify-get_perf_callchain-user-logic.patch
+perf-sched-fix-perf-crash-with-new-is_user_task-helper.patch
+writeback-fix-100-cpu-usage-when-dirtytime_expire_interval-is-0.patch
+drm-amdgpu-gfx11-adjust-kgq-reset-sequence.patch
+pinctrl-lpass-lpi-implement-.get_direction-for-the-gpio-driver.patch
+net-mana-change-the-function-signature-of-mana_get_primary_netdev_rcu.patch
+rdma-mana_ib-handle-net-event-for-pointing-to-the-current-netdev.patch
--- /dev/null
+From stable+bounces-213297-greg=kroah.com@vger.kernel.org Tue Feb 3 19:08:27 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Feb 2026 13:04:25 -0500
+Subject: writeback: fix 100% CPU usage when dirtytime_expire_interval is 0
+To: stable@vger.kernel.org
+Cc: Laveesh Bansal <laveeshb@laveeshbansal.com>, Jan Kara <jack@suse.cz>, Christian Brauner <brauner@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260203180425.1352516-1-sashal@kernel.org>
+
+From: Laveesh Bansal <laveeshb@laveeshbansal.com>
+
+[ Upstream commit 543467d6fe97e27e22a26e367fda972dbefebbff ]
+
+When vm.dirtytime_expire_seconds is set to 0, wakeup_dirtytime_writeback()
+schedules delayed work with a delay of 0, causing immediate execution.
+The function then reschedules itself with 0 delay again, creating an
+infinite busy loop that causes 100% kworker CPU usage.
+
+Fix by:
+- Only scheduling delayed work in wakeup_dirtytime_writeback() when
+ dirtytime_expire_interval is non-zero
+- Cancelling the delayed work in dirtytime_interval_handler() when
+ the interval is set to 0
+- Adding a guard in start_dirtytime_writeback() for defensive coding
+
+Tested by booting kernel in QEMU with virtme-ng:
+- Before fix: kworker CPU spikes to ~73%
+- After fix: CPU remains at normal levels
+- Setting interval back to non-zero correctly resumes writeback
+
+Fixes: a2f4870697a5 ("fs: make sure the timestamps for lazytime inodes eventually get written")
+Cc: stable@vger.kernel.org
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220227
+Signed-off-by: Laveesh Bansal <laveeshb@laveeshbansal.com>
+Link: https://patch.msgid.link/20260106145059.543282-2-laveeshb@laveeshbansal.com
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+[ adapted system_percpu_wq to system_wq for the workqueue used in dirtytime_interval_handler() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/fs-writeback.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/fs/fs-writeback.c
++++ b/fs/fs-writeback.c
+@@ -2418,12 +2418,14 @@ static void wakeup_dirtytime_writeback(s
+ wb_wakeup(wb);
+ }
+ rcu_read_unlock();
+- schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
++ if (dirtytime_expire_interval)
++ schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
+ }
+
+ static int __init start_dirtytime_writeback(void)
+ {
+- schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
++ if (dirtytime_expire_interval)
++ schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
+ return 0;
+ }
+ __initcall(start_dirtytime_writeback);
+@@ -2434,8 +2436,12 @@ int dirtytime_interval_handler(const str
+ int ret;
+
+ ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+- if (ret == 0 && write)
+- mod_delayed_work(system_wq, &dirtytime_work, 0);
++ if (ret == 0 && write) {
++ if (dirtytime_expire_interval)
++ mod_delayed_work(system_wq, &dirtytime_work, 0);
++ else
++ cancel_delayed_work_sync(&dirtytime_work);
++ }
+ return ret;
+ }
+