From: Greg Kroah-Hartman Date: Fri, 15 May 2026 15:03:55 +0000 (+0200) Subject: 6.6-stable patches X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9eb9b236b3f50d2b840dc799b31816a60f1ab537;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: batman-adv-stop-tp_meter-sessions-during-mesh-teardown.patch batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failure.patch bluetooth-l2cap-fix-null-ptr-deref-in-l2cap_sock_get_sndtimeo_cb.patch bonding-fix-use-after-free-due-to-enslave-fail-after-slave-array-update.patch btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch ksmbd-fix-use-after-free-in-__ksmbd_close_fd-via-durable-scavenger.patch kvm-arm64-wake-up-from-wfi-when-iqrchip-is-in-userspace.patch mm-damon-core-disallow-time-quota-setting-zero-esz.patch mm-damon-core-implement-damon_kdamond_pid.patch mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch mtd-spi-nor-sst-factor-out-common-write-operation-to-sst_nor_write_data.patch mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch pwm-imx-tpm-count-the-number-of-enabled-channels-in-probe.patch rxrpc-also-unshare-data-response-packets-when-paged-frags-are-present.patch tracing-probes-limit-size-of-event-probe-to-3k.patch usb-dwc3-move-guid-programming-after-phy-initialization.patch usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch --- diff --git a/queue-6.6/batman-adv-stop-tp_meter-sessions-during-mesh-teardown.patch b/queue-6.6/batman-adv-stop-tp_meter-sessions-during-mesh-teardown.patch new file mode 100644 index 0000000000..9505981947 --- /dev/null +++ b/queue-6.6/batman-adv-stop-tp_meter-sessions-during-mesh-teardown.patch @@ -0,0 +1,237 @@ +From stable+bounces-247657-greg=kroah.com@vger.kernel.org Fri May 15 13:28:18 2026 +From: Sven Eckelmann +Date: Fri, 15 May 2026 12:56:49 +0200 +Subject: batman-adv: stop tp_meter sessions during mesh teardown +To: stable@vger.kernel.org +Cc: Jiexun Wang , stable@kernel.org, Yuan Tan , Yifan Wu , Juefei Pu , Xin Liu , Luxing Yin , Ren Wei , Sven Eckelmann +Message-ID: <20260515105649.180995-1-sven@narfation.org> + +From: Jiexun Wang + +commit 3d3cf6a7314aca4df0a6dde28ce784a2a30d0166 upstream. + +TP meter sessions remain linked on bat_priv->tp_list after the netlink +request has already finished. When the mesh interface is removed, +batadv_mesh_free() currently tears down the mesh without first draining +these sessions. + +A running sender thread or a late incoming tp_meter packet can then keep +processing against a mesh instance which is already shutting down. +Synchronize tp_meter with the mesh lifetime by stopping all active +sessions from batadv_mesh_free() and waiting for sender threads to exit +before teardown continues. + +Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Co-developed-by: Luxing Yin +Signed-off-by: Luxing Yin +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +[ Context ] +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/main.c | 1 + net/batman-adv/tp_meter.c | 94 +++++++++++++++++++++++++++++++++++++--------- + net/batman-adv/tp_meter.h | 1 + net/batman-adv/types.h | 4 + + 4 files changed, 82 insertions(+), 18 deletions(-) + +--- a/net/batman-adv/main.c ++++ b/net/batman-adv/main.c +@@ -262,6 +262,7 @@ void batadv_mesh_free(struct net_device + atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + + batadv_purge_outstanding_packets(bat_priv, NULL); ++ batadv_tp_stop_all(bat_priv); + + batadv_gw_node_free(bat_priv); + +--- a/net/batman-adv/tp_meter.c ++++ b/net/batman-adv/tp_meter.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -365,23 +366,38 @@ static void batadv_tp_vars_put(struct ba + } + + /** +- * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer +- * @bat_priv: the bat priv with all the soft interface information +- * @tp_vars: the private data of the current TP meter session to cleanup ++ * batadv_tp_list_detach() - remove tp session from mesh session list once ++ * @tp_vars: the private data of the current TP meter session + */ +-static void batadv_tp_sender_cleanup(struct batadv_priv *bat_priv, +- struct batadv_tp_vars *tp_vars) ++static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars) + { +- cancel_delayed_work(&tp_vars->finish_work); ++ bool detached = false; + + spin_lock_bh(&tp_vars->bat_priv->tp_list_lock); +- hlist_del_rcu(&tp_vars->list); ++ if (!hlist_unhashed(&tp_vars->list)) { ++ hlist_del_init_rcu(&tp_vars->list); ++ detached = true; ++ } + spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock); + ++ if (!detached) ++ return; ++ ++ atomic_dec(&tp_vars->bat_priv->tp_num); ++ + /* drop list reference */ + batadv_tp_vars_put(tp_vars); ++} + +- atomic_dec(&tp_vars->bat_priv->tp_num); ++/** ++ * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer ++ * @tp_vars: the private data of the current TP meter session to cleanup ++ */ ++static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars) ++{ ++ cancel_delayed_work_sync(&tp_vars->finish_work); ++ ++ batadv_tp_list_detach(tp_vars); + + /* kill the timer and remove its reference */ + del_timer_sync(&tp_vars->timer); +@@ -886,7 +902,8 @@ out: + batadv_orig_node_put(orig_node); + + batadv_tp_sender_end(bat_priv, tp_vars); +- batadv_tp_sender_cleanup(bat_priv, tp_vars); ++ batadv_tp_sender_cleanup(tp_vars); ++ complete(&tp_vars->finished); + + batadv_tp_vars_put(tp_vars); + +@@ -918,7 +935,8 @@ static void batadv_tp_start_kthread(stru + batadv_tp_vars_put(tp_vars); + + /* cleanup of failed tp meter variables */ +- batadv_tp_sender_cleanup(bat_priv, tp_vars); ++ batadv_tp_sender_cleanup(tp_vars); ++ complete(&tp_vars->finished); + return; + } + +@@ -1024,6 +1042,7 @@ void batadv_tp_start(struct batadv_priv + tp_vars->start_time = jiffies; + + init_waitqueue_head(&tp_vars->more_bytes); ++ init_completion(&tp_vars->finished); + + spin_lock_init(&tp_vars->unacked_lock); + INIT_LIST_HEAD(&tp_vars->unacked_list); +@@ -1126,14 +1145,7 @@ static void batadv_tp_receiver_shutdown( + "Shutting down for inactivity (more than %dms) from %pM\n", + BATADV_TP_RECV_TIMEOUT, tp_vars->other_end); + +- spin_lock_bh(&tp_vars->bat_priv->tp_list_lock); +- hlist_del_rcu(&tp_vars->list); +- spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock); +- +- /* drop list reference */ +- batadv_tp_vars_put(tp_vars); +- +- atomic_dec(&bat_priv->tp_num); ++ batadv_tp_list_detach(tp_vars); + + spin_lock_bh(&tp_vars->unacked_lock); + list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) { +@@ -1497,6 +1509,52 @@ out: + } + + /** ++ * batadv_tp_stop_all() - stop all currently running tp meter sessions ++ * @bat_priv: the bat priv with all the mesh interface information ++ */ ++void batadv_tp_stop_all(struct batadv_priv *bat_priv) ++{ ++ struct batadv_tp_vars *tp_vars[BATADV_TP_MAX_NUM]; ++ struct batadv_tp_vars *tp_var; ++ size_t count = 0; ++ size_t i; ++ ++ spin_lock_bh(&bat_priv->tp_list_lock); ++ hlist_for_each_entry(tp_var, &bat_priv->tp_list, list) { ++ if (WARN_ON_ONCE(count >= BATADV_TP_MAX_NUM)) ++ break; ++ ++ if (!kref_get_unless_zero(&tp_var->refcount)) ++ continue; ++ ++ tp_vars[count++] = tp_var; ++ } ++ spin_unlock_bh(&bat_priv->tp_list_lock); ++ ++ for (i = 0; i < count; i++) { ++ tp_var = tp_vars[i]; ++ ++ switch (tp_var->role) { ++ case BATADV_TP_SENDER: ++ batadv_tp_sender_shutdown(tp_var, ++ BATADV_TP_REASON_CANCEL); ++ wake_up(&tp_var->more_bytes); ++ wait_for_completion(&tp_var->finished); ++ break; ++ case BATADV_TP_RECEIVER: ++ batadv_tp_list_detach(tp_var); ++ if (timer_shutdown_sync(&tp_var->timer)) ++ batadv_tp_vars_put(tp_var); ++ break; ++ } ++ ++ batadv_tp_vars_put(tp_var); ++ } ++ ++ synchronize_net(); ++} ++ ++/** + * batadv_tp_meter_init() - initialize global tp_meter structures + */ + void __init batadv_tp_meter_init(void) +--- a/net/batman-adv/tp_meter.h ++++ b/net/batman-adv/tp_meter.h +@@ -17,6 +17,7 @@ void batadv_tp_start(struct batadv_priv + u32 test_length, u32 *cookie); + void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst, + u8 return_value); ++void batadv_tp_stop_all(struct batadv_priv *bat_priv); + void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb); + + #endif /* _NET_BATMAN_ADV_TP_METER_H_ */ +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1396,6 +1397,9 @@ struct batadv_tp_vars { + /** @finish_work: work item for the finishing procedure */ + struct delayed_work finish_work; + ++ /** @finished: completion signaled when a sender thread exits */ ++ struct completion finished; ++ + /** @test_length: test length in milliseconds */ + u32 test_length; + diff --git a/queue-6.6/batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failure.patch b/queue-6.6/batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failure.patch new file mode 100644 index 0000000000..646c41444f --- /dev/null +++ b/queue-6.6/batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failure.patch @@ -0,0 +1,59 @@ +From stable+bounces-247707-greg=kroah.com@vger.kernel.org Fri May 15 14:39:24 2026 +From: Sven Eckelmann +Date: Fri, 15 May 2026 13:49:53 +0200 +Subject: batman-adv: tp_meter: fix tp_num leak on kmalloc failure +To: stable@vger.kernel.org +Cc: Sven Eckelmann , stable@kernel.org +Message-ID: <20260515114953.437624-1-sven@narfation.org> + +From: Sven Eckelmann + +commit ce425dd05d0fe7594930a0fb103634f35ac47bb6 upstream. + +When batadv_tp_start() or batadv_tp_init_recv() fail to allocate a new +tp_vars object, the previously incremented bat_priv->tp_num counter is +never decremented. This causes tp_num to drift upward on each allocation +failure. Since only BATADV_TP_MAX_NUM sessions can be started and the count +is never reduced for these failed allocations, it causes to an exhaustion +of throughput meter sessions. In worst case, no new throughput meter +session can be started until the mesh interface is removed. + +The error handling must decrement tp_num releasing the lock and aborting +the creation of an throughput meter session + +Cc: stable@kernel.org +Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") +[ Context ] +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/tp_meter.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c +index 7f3dd3c393e0..16da48b23f57 100644 +--- a/net/batman-adv/tp_meter.c ++++ b/net/batman-adv/tp_meter.c +@@ -969,6 +969,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst, + + tp_vars = kmalloc(sizeof(*tp_vars), GFP_ATOMIC); + if (!tp_vars) { ++ atomic_dec(&bat_priv->tp_num); + spin_unlock_bh(&bat_priv->tp_list_lock); + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, + "Meter: %s cannot allocate list elements\n", +@@ -1344,8 +1345,10 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv, + } + + tp_vars = kmalloc(sizeof(*tp_vars), GFP_ATOMIC); +- if (!tp_vars) ++ if (!tp_vars) { ++ atomic_dec(&bat_priv->tp_num); + goto out_unlock; ++ } + + ether_addr_copy(tp_vars->other_end, icmp->orig); + tp_vars->role = BATADV_TP_RECEIVER; +-- +2.47.3 + diff --git a/queue-6.6/bluetooth-l2cap-fix-null-ptr-deref-in-l2cap_sock_get_sndtimeo_cb.patch b/queue-6.6/bluetooth-l2cap-fix-null-ptr-deref-in-l2cap_sock_get_sndtimeo_cb.patch new file mode 100644 index 0000000000..2fa7aee3f0 --- /dev/null +++ b/queue-6.6/bluetooth-l2cap-fix-null-ptr-deref-in-l2cap_sock_get_sndtimeo_cb.patch @@ -0,0 +1,33 @@ +From 78a88d43dab8d23aeef934ed8ce34d40e6b3d613 Mon Sep 17 00:00:00 2001 +From: Siwei Zhang +Date: Wed, 15 Apr 2026 16:53:36 -0400 +Subject: Bluetooth: L2CAP: Fix null-ptr-deref in l2cap_sock_get_sndtimeo_cb() + +From: Siwei Zhang + +commit 78a88d43dab8d23aeef934ed8ce34d40e6b3d613 upstream. + +Add the same NULL guard already present in +l2cap_sock_resume_cb() and l2cap_sock_ready_cb(). + +Fixes: 8d836d71e222 ("Bluetooth: Access sk_sndtimeo indirectly in l2cap_core.c") +Cc: stable@kernel.org +Signed-off-by: Siwei Zhang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/l2cap_sock.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/bluetooth/l2cap_sock.c ++++ b/net/bluetooth/l2cap_sock.c +@@ -1731,6 +1731,9 @@ static long l2cap_sock_get_sndtimeo_cb(s + { + struct sock *sk = chan->data; + ++ if (!sk) ++ return 0; ++ + return sk->sk_sndtimeo; + } + diff --git a/queue-6.6/bonding-fix-use-after-free-due-to-enslave-fail-after-slave-array-update.patch b/queue-6.6/bonding-fix-use-after-free-due-to-enslave-fail-after-slave-array-update.patch new file mode 100644 index 0000000000..a2ace654e7 --- /dev/null +++ b/queue-6.6/bonding-fix-use-after-free-due-to-enslave-fail-after-slave-array-update.patch @@ -0,0 +1,98 @@ +From e9acda52fd2ee0cdca332f996da7a95c5fd25294 Mon Sep 17 00:00:00 2001 +From: Nikolay Aleksandrov +Date: Fri, 23 Jan 2026 14:06:59 +0200 +Subject: bonding: fix use-after-free due to enslave fail after slave array update + +From: Nikolay Aleksandrov + +commit e9acda52fd2ee0cdca332f996da7a95c5fd25294 upstream. + +Fix a use-after-free which happens due to enslave failure after the new +slave has been added to the array. Since the new slave can be used for Tx +immediately, we can use it after it has been freed by the enslave error +cleanup path which frees the allocated slave memory. Slave update array is +supposed to be called last when further enslave failures are not expected. +Move it after xdp setup to avoid any problems. + +It is very easy to reproduce the problem with a simple xdp_pass prog: + ip l add bond1 type bond mode balance-xor + ip l set bond1 up + ip l set dev bond1 xdp object xdp_pass.o sec xdp_pass + ip l add dumdum type dummy + +Then run in parallel: + while :; do ip l set dumdum master bond1 1>/dev/null 2>&1; done; + mausezahn bond1 -a own -b rand -A rand -B 1.1.1.1 -c 0 -t tcp "dp=1-1023, flags=syn" + +The crash happens almost immediately: + [ 605.602850] Oops: general protection fault, probably for non-canonical address 0xe0e6fc2460000137: 0000 [#1] SMP KASAN NOPTI + [ 605.602916] KASAN: maybe wild-memory-access in range [0x07380123000009b8-0x07380123000009bf] + [ 605.602946] CPU: 0 UID: 0 PID: 2445 Comm: mausezahn Kdump: loaded Tainted: G B 6.19.0-rc6+ #21 PREEMPT(voluntary) + [ 605.602979] Tainted: [B]=BAD_PAGE + [ 605.602998] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 + [ 605.603032] RIP: 0010:netdev_core_pick_tx+0xcd/0x210 + [ 605.603063] Code: 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 3e 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 6b 08 49 8d 7d 30 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 25 01 00 00 49 8b 45 30 4c 89 e2 48 89 ee 48 89 + [ 605.603111] RSP: 0018:ffff88817b9af348 EFLAGS: 00010213 + [ 605.603145] RAX: dffffc0000000000 RBX: ffff88817d28b420 RCX: 0000000000000000 + [ 605.603172] RDX: 00e7002460000137 RSI: 0000000000000008 RDI: 07380123000009be + [ 605.603199] RBP: ffff88817b541a00 R08: 0000000000000001 R09: fffffbfff3ed8c0c + [ 605.603226] R10: ffffffff9f6c6067 R11: 0000000000000001 R12: 0000000000000000 + [ 605.603253] R13: 073801230000098e R14: ffff88817d28b448 R15: ffff88817b541a84 + [ 605.603286] FS: 00007f6570ef67c0(0000) GS:ffff888221dfa000(0000) knlGS:0000000000000000 + [ 605.603319] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [ 605.603343] CR2: 00007f65712fae40 CR3: 000000011371b000 CR4: 0000000000350ef0 + [ 605.603373] Call Trace: + [ 605.603392] + [ 605.603410] __dev_queue_xmit+0x448/0x32a0 + [ 605.603434] ? __pfx_vprintk_emit+0x10/0x10 + [ 605.603461] ? __pfx_vprintk_emit+0x10/0x10 + [ 605.603484] ? __pfx___dev_queue_xmit+0x10/0x10 + [ 605.603507] ? bond_start_xmit+0xbfb/0xc20 [bonding] + [ 605.603546] ? _printk+0xcb/0x100 + [ 605.603566] ? __pfx__printk+0x10/0x10 + [ 605.603589] ? bond_start_xmit+0xbfb/0xc20 [bonding] + [ 605.603627] ? add_taint+0x5e/0x70 + [ 605.603648] ? add_taint+0x2a/0x70 + [ 605.603670] ? end_report.cold+0x51/0x75 + [ 605.603693] ? bond_start_xmit+0xbfb/0xc20 [bonding] + [ 605.603731] bond_start_xmit+0x623/0xc20 [bonding] + +Fixes: 9e2ee5c7e7c3 ("net, bonding: Add XDP support to the bonding driver") +Signed-off-by: Nikolay Aleksandrov +Reported-by: Chen Zhen +Closes: https://lore.kernel.org/netdev/fae17c21-4940-5605-85b2-1d5e17342358@huawei.com/ +CC: Jussi Maki +CC: Daniel Borkmann +Acked-by: Daniel Borkmann +Link: https://patch.msgid.link/20260123120659.571187-1-razor@blackwall.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +Tested-by: Yunseong Kim +Signed-off-by: Yunseong Kim +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/bonding/bond_main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -2309,9 +2309,6 @@ skip_mac_set: + unblock_netpoll_tx(); + } + +- if (bond_mode_can_use_xmit_hash(bond)) +- bond_update_slave_arr(bond, NULL); +- + if (!slave_dev->netdev_ops->ndo_bpf || + !slave_dev->netdev_ops->ndo_xdp_xmit) { + if (bond->xdp_prog) { +@@ -2345,6 +2342,9 @@ skip_mac_set: + bpf_prog_inc(bond->xdp_prog); + } + ++ if (bond_mode_can_use_xmit_hash(bond)) ++ bond_update_slave_arr(bond, NULL); ++ + bond_xdp_set_features(bond_dev); + + slave_info(bond_dev, slave_dev, "Enslaving as %s interface with %s link\n", diff --git a/queue-6.6/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch b/queue-6.6/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch new file mode 100644 index 0000000000..bdb2a696c7 --- /dev/null +++ b/queue-6.6/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch @@ -0,0 +1,64 @@ +From stable+bounces-247728-greg=kroah.com@vger.kernel.org Fri May 15 14:40:14 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 08:06:20 -0400 +Subject: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak +To: stable@vger.kernel.org +Cc: Yochai Eisenrich , Yochai Eisenrich , David Sterba , Sasha Levin +Message-ID: <20260515120620.3073457-1-sashal@kernel.org> + +From: Yochai Eisenrich + +[ Upstream commit 973e57c726c1f8e77259d1c8e519519f1e9aea77 ] + +btrfs_ioctl_space_info() has a TOCTOU race between two passes over the +block group RAID type lists. The first pass counts entries to determine +the allocation size, then the second pass fills the buffer. The +groups_sem rwlock is released between passes, allowing concurrent block +group removal to reduce the entry count. + +When the second pass fills fewer entries than the first pass counted, +copy_to_user() copies the full alloc_size bytes including trailing +uninitialized kmalloc bytes to userspace. + +Fix by copying only total_spaces entries (the actually-filled count from +the second pass) instead of alloc_size bytes, and switch to kzalloc so +any future copy size mismatch cannot leak heap data. + +Fixes: 7fde62bffb57 ("Btrfs: buffer results in the space_info ioctl") +CC: stable@vger.kernel.org # 3.0 +Signed-off-by: Yochai Eisenrich +Reviewed-by: David Sterba +Signed-off-by: David Sterba +[ adapted upstream's `return -EFAULT;` to stable's `ret = -EFAULT;` fall-through to existing `out:` cleanup label ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/ioctl.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c +index 4723013995f5b..d17d1eff8eff4 100644 +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -3087,7 +3087,7 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info, + return -ENOMEM; + + space_args.total_spaces = 0; +- dest = kmalloc(alloc_size, GFP_KERNEL); ++ dest = kzalloc(alloc_size, GFP_KERNEL); + if (!dest) + return -ENOMEM; + dest_orig = dest; +@@ -3143,7 +3143,8 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info, + user_dest = (struct btrfs_ioctl_space_info __user *) + (arg + sizeof(struct btrfs_ioctl_space_args)); + +- if (copy_to_user(user_dest, dest_orig, alloc_size)) ++ if (copy_to_user(user_dest, dest_orig, ++ space_args.total_spaces * sizeof(*dest_orig))) + ret = -EFAULT; + + kfree(dest_orig); +-- +2.53.0 + diff --git a/queue-6.6/ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch b/queue-6.6/ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch new file mode 100644 index 0000000000..c4092d17d6 --- /dev/null +++ b/queue-6.6/ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch @@ -0,0 +1,113 @@ +From stable+bounces-244957-greg=kroah.com@vger.kernel.org Sat May 9 16:22:24 2026 +From: Sasha Levin +Date: Sat, 9 May 2026 10:22:16 -0400 +Subject: ceph: only d_add() negative dentries when they are unhashed +To: stable@vger.kernel.org +Cc: Max Kellermann , Viacheslav Dubeyko , Ilya Dryomov , Sasha Levin +Message-ID: <20260509142216.3462686-1-sashal@kernel.org> + +From: Max Kellermann + +[ Upstream commit 803447f93d75ab6e40c85e6d12b5630d281d70d6 ] + +Ceph can call d_add(dentry, NULL) on a negative dentry that is already +present in the primary dcache hash. + +In the current VFS that is not safe. d_add() goes through __d_add() +to __d_rehash(), which unconditionally reinserts dentry->d_hash into +the hlist_bl bucket. If the dentry is already hashed, reinserting the +same node can corrupt the bucket, including creating a self-loop. +Once that happens, __d_lookup() can spin forever in the hlist_bl walk, +typically looping only on the d_name.hash mismatch check and +eventually triggering RCU stall reports like this one: + + rcu: INFO: rcu_sched self-detected stall on CPU + rcu: 87-....: (2100 ticks this GP) idle=3a4c/1/0x4000000000000000 softirq=25003319/25003319 fqs=829 + rcu: (t=2101 jiffies g=79058445 q=698988 ncpus=192) + CPU: 87 UID: 2952868916 PID: 3933303 Comm: php-cgi8.3 Not tainted 6.18.17-i1-amd #950 NONE + Hardware name: Dell Inc. PowerEdge R7615/0G9DHV, BIOS 1.6.6 09/22/2023 + RIP: 0010:__d_lookup+0x46/0xb0 + Code: c1 e8 07 48 8d 04 c2 48 8b 00 49 89 fc 49 89 f5 48 89 c3 48 83 e3 fe 48 83 f8 01 77 0f eb 2d 0f 1f 44 00 00 48 8b 1b 48 85 db <74> 20 39 6b 18 75 f3 48 8d 7b 78 e8 ba 85 d0 00 4c 39 63 10 74 1f + RSP: 0018:ff745a70c8253898 EFLAGS: 00000282 + RAX: ff26e470054cb208 RBX: ff26e470054cb208 RCX: 000000006e958966 + RDX: ff26e48267340000 RSI: ff745a70c82539b0 RDI: ff26e458f74655c0 + RBP: 000000006e958966 R08: 0000000000000180 R09: 9cd08d909b919a89 + R10: ff26e458f74655c0 R11: 0000000000000000 R12: ff26e458f74655c0 + R13: ff745a70c82539b0 R14: d0d0d0d0d0d0d0d0 R15: 2f2f2f2f2f2f2f2f + FS: 00007f5770896980(0000) GS:ff26e482c5d88000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007f5764de50c0 CR3: 000000a72abb5001 CR4: 0000000000771ef0 + PKRU: 55555554 + Call Trace: + + lookup_fast+0x9f/0x100 + walk_component+0x1f/0x150 + link_path_walk+0x20e/0x3d0 + path_lookupat+0x68/0x180 + filename_lookup+0xdc/0x1e0 + vfs_statx+0x6c/0x140 + vfs_fstatat+0x67/0xa0 + __do_sys_newfstatat+0x24/0x60 + do_syscall_64+0x6a/0x230 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +This is reachable with reused cached negative dentries. A Ceph lookup +or atomic_open can be handed a negative dentry that is already hashed, +and fs/ceph/dir.c then hits one of two paths that incorrectly assume +"negative" also means "unhashed": + + - ceph_finish_lookup(): + MDS reply is -ENOENT with no trace + -> d_add(dentry, NULL) + + - ceph_lookup(): + local ENOENT fast path for a complete directory with shared caps + -> d_add(dentry, NULL) + +Both paths can therefore re-add an already-hashed negative dentry. + +Ceph already uses the correct pattern elsewhere: ceph_fill_trace() only +calls d_add(dn, NULL) for a negative null-dentry reply when d_unhashed(dn) +is true. + +Fix both fs/ceph/dir.c sites the same way: only call d_add() for a +negative dentry when it is actually unhashed. If the negative dentry +is already hashed, leave it in place and reuse it as-is. + +This preserves the existing behavior for unhashed dentries while +avoiding d_hash list corruption for reused hashed negatives. + +Cc: stable@vger.kernel.org +Fixes: 2817b000b02c ("ceph: directory operations") +Signed-off-by: Max Kellermann +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Ilya Dryomov +[ kept existing dout() debug call instead of upstream's doutc() form when adding the d_unhashed() guard around d_add() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/dir.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/fs/ceph/dir.c ++++ b/fs/ceph/dir.c +@@ -745,7 +745,8 @@ struct dentry *ceph_finish_lookup(struct + d_drop(dentry); + err = -ENOENT; + } else { +- d_add(dentry, NULL); ++ if (d_unhashed(dentry)) ++ d_add(dentry, NULL); + } + } + } +@@ -813,7 +814,8 @@ static struct dentry *ceph_lookup(struct + __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD); + spin_unlock(&ci->i_ceph_lock); + dout(" dir %p complete, -ENOENT\n", dir); +- d_add(dentry, NULL); ++ if (d_unhashed(dentry)) ++ d_add(dentry, NULL); + di->lease_shared_gen = atomic_read(&ci->i_shared_gen); + return NULL; + } diff --git a/queue-6.6/ksmbd-fix-use-after-free-in-__ksmbd_close_fd-via-durable-scavenger.patch b/queue-6.6/ksmbd-fix-use-after-free-in-__ksmbd_close_fd-via-durable-scavenger.patch new file mode 100644 index 0000000000..6fed1958ed --- /dev/null +++ b/queue-6.6/ksmbd-fix-use-after-free-in-__ksmbd_close_fd-via-durable-scavenger.patch @@ -0,0 +1,133 @@ +From 235e32320a470fcd3998fb3774f2290a0eb302a1 Mon Sep 17 00:00:00 2001 +From: Namjae Jeon +Date: Sat, 4 Apr 2026 21:09:02 +0900 +Subject: ksmbd: fix use-after-free in __ksmbd_close_fd() via durable scavenger + +From: Namjae Jeon + +commit 235e32320a470fcd3998fb3774f2290a0eb302a1 upstream. + +When a durable file handle survives session disconnect (TCP close without +SMB2_LOGOFF), session_fd_check() sets fp->conn = NULL to preserve the +handle for later reconnection. However, it did not clean up the byte-range +locks on fp->lock_list. + +Later, when the durable scavenger thread times out and calls +__ksmbd_close_fd(NULL, fp), the lock cleanup loop did: + + spin_lock(&fp->conn->llist_lock); + +This caused a slab use-after-free because fp->conn was NULL and the +original connection object had already been freed by +ksmbd_tcp_disconnect(). + +The root cause is asymmetric cleanup: lock entries (smb_lock->clist) were +left dangling on the freed conn->lock_list while fp->conn was nulled out. + +To fix this issue properly, we need to handle the lifetime of +smb_lock->clist across three paths: + - Safely skip clist deletion when list is empty and fp->conn is NULL. + - Remove the lock from the old connection's lock_list in + session_fd_check() + - Re-add the lock to the new connection's lock_list in + ksmbd_reopen_durable_fd(). + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Co-developed-by: munan Huang +Signed-off-by: munan Huang +Reviewed-by: ChenXiaoSong +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +[ Minor context conflict resolved. ] +Signed-off-by: Alva Lan +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/vfs_cache.c | 40 ++++++++++++++++++++++++++++++---------- + 1 file changed, 30 insertions(+), 10 deletions(-) + +--- a/fs/smb/server/vfs_cache.c ++++ b/fs/smb/server/vfs_cache.c +@@ -356,9 +356,11 @@ static void __ksmbd_close_fd(struct ksmb + * there are not accesses to fp->lock_list. + */ + list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) { +- spin_lock(&fp->conn->llist_lock); +- list_del(&smb_lock->clist); +- spin_unlock(&fp->conn->llist_lock); ++ if (!list_empty(&smb_lock->clist) && fp->conn) { ++ spin_lock(&fp->conn->llist_lock); ++ list_del(&smb_lock->clist); ++ spin_unlock(&fp->conn->llist_lock); ++ } + + list_del(&smb_lock->flist); + locks_free_lock(smb_lock->fl); +@@ -755,6 +757,7 @@ static bool session_fd_check(struct ksmb + struct ksmbd_inode *ci; + struct oplock_info *op; + struct ksmbd_conn *conn; ++ struct ksmbd_lock *smb_lock, *tmp_lock; + + if (!is_reconnectable(fp)) + return false; +@@ -771,6 +774,12 @@ static bool session_fd_check(struct ksmb + } + up_write(&ci->m_lock); + ++ list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) { ++ spin_lock(&fp->conn->llist_lock); ++ list_del_init(&smb_lock->clist); ++ spin_unlock(&fp->conn->llist_lock); ++ } ++ + fp->conn = NULL; + fp->tcon = NULL; + fp->volatile_id = KSMBD_NO_FID; +@@ -844,6 +853,9 @@ int ksmbd_reopen_durable_fd(struct ksmbd + { + struct ksmbd_inode *ci; + struct oplock_info *op; ++ struct ksmbd_conn *conn = work->conn; ++ struct ksmbd_lock *smb_lock; ++ unsigned int old_f_state; + + if (!fp->is_durable || fp->conn || fp->tcon) { + pr_err("Invalid durable fd [%p:%p]\n", fp->conn, fp->tcon); +@@ -855,9 +867,23 @@ int ksmbd_reopen_durable_fd(struct ksmbd + return -EBADF; + } + +- fp->conn = work->conn; ++ old_f_state = fp->f_state; ++ fp->f_state = FP_NEW; ++ __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); ++ if (!has_file_id(fp->volatile_id)) { ++ fp->f_state = old_f_state; ++ return -EBADF; ++ } ++ ++ fp->conn = conn; + fp->tcon = work->tcon; + ++ list_for_each_entry(smb_lock, &fp->lock_list, flist) { ++ spin_lock(&conn->llist_lock); ++ list_add_tail(&smb_lock->clist, &conn->lock_list); ++ spin_unlock(&conn->llist_lock); ++ } ++ + ci = fp->f_ci; + down_write(&ci->m_lock); + list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { +@@ -868,12 +894,6 @@ int ksmbd_reopen_durable_fd(struct ksmbd + } + up_write(&ci->m_lock); + +- __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); +- if (!has_file_id(fp->volatile_id)) { +- fp->conn = NULL; +- fp->tcon = NULL; +- return -EBADF; +- } + return 0; + } + diff --git a/queue-6.6/kvm-arm64-wake-up-from-wfi-when-iqrchip-is-in-userspace.patch b/queue-6.6/kvm-arm64-wake-up-from-wfi-when-iqrchip-is-in-userspace.patch new file mode 100644 index 0000000000..9ea9f6e42e --- /dev/null +++ b/queue-6.6/kvm-arm64-wake-up-from-wfi-when-iqrchip-is-in-userspace.patch @@ -0,0 +1,46 @@ +From stable+bounces-245815-greg=kroah.com@vger.kernel.org Tue May 12 16:51:01 2026 +From: Marc Zyngier +Date: Tue, 12 May 2026 15:50:35 +0100 +Subject: KVM: arm64: Wake-up from WFI when iqrchip is in userspace +To: stable@vger.kernel.org +Message-ID: <20260512145035.3676967-1-maz@kernel.org> + +From: Marc Zyngier + +commit 4ce98bf0865c349e7026ad9c14f48da264920953 upstream + +It appears that there is nothing in the wake-up path that +evaluates whether the in-kernel interrupts are pending unless +we have a vgic. + +This means that the userspace irqchip support has been broken for +about four years, and nobody noticed. It was also broken before +as we wouldn't wake-up on a PMU interrupt, but hey, who cares... + +It is probably time to remove the feature altogether, because it +was a terrible idea 10 years ago, and it still is. + +Fixes: b57de4ffd7c6d ("KVM: arm64: Simplify kvm_cpu_has_pending_timer()") +Link: https://patch.msgid.link/20260423163607.486345-1-maz@kernel.org +Signed-off-by: Marc Zyngier +Cc: stable@vger.kernel.org +Signed-off-by: Marc Zyngier +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/kvm/arm.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/arm64/kvm/arm.c ++++ b/arch/arm64/kvm/arm.c +@@ -557,6 +557,11 @@ int kvm_arch_vcpu_ioctl_set_mpstate(stru + int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) + { + bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF); ++ ++ irq_lines |= (!irqchip_in_kernel(v->kvm) && ++ (kvm_timer_should_notify_user(v) || ++ kvm_pmu_should_notify_user(v))); ++ + return ((irq_lines || kvm_vgic_vcpu_pending_irq(v)) + && !kvm_arm_vcpu_stopped(v) && !v->arch.pause); + } diff --git a/queue-6.6/mm-damon-core-disallow-time-quota-setting-zero-esz.patch b/queue-6.6/mm-damon-core-disallow-time-quota-setting-zero-esz.patch new file mode 100644 index 0000000000..7ae9a7ccf3 --- /dev/null +++ b/queue-6.6/mm-damon-core-disallow-time-quota-setting-zero-esz.patch @@ -0,0 +1,61 @@ +From 8bbde987c2b84f80da0853f739f0a920386f8b99 Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Mon, 6 Apr 2026 17:31:52 -0700 +Subject: mm/damon/core: disallow time-quota setting zero esz + +From: SeongJae Park + +commit 8bbde987c2b84f80da0853f739f0a920386f8b99 upstream. + +When the throughput of a DAMOS scheme is very slow, DAMOS time quota can +make the effective size quota smaller than damon_ctx->min_region_sz. In +the case, damos_apply_scheme() will skip applying the action, because the +action is tried at region level, which requires >=min_region_sz size. +That is, the quota is effectively exceeded for the quota charge window. + +Because no action will be applied, the total_charged_sz and +total_charged_ns are also not updated. damos_set_effective_quota() will +try to update the effective size quota before starting the next charge +window. However, because the total_charged_sz and total_charged_ns have +not updated, the throughput and effective size quota are also not changed. +Since effective size quota can only be decreased, other effective size +quota update factors including DAMOS quota goals and size quota cannot +make any change, either. + +As a result, the scheme is unexpectedly deactivated until the user notices +and mitigates the situation. The users can mitigate this situation by +changing the time quota online or re-install the scheme. While the +mitigation is somewhat straightforward, finding the situation would be +challenging, because DAMON is not providing good observabilities for that. +Even if such observability is provided, doing the additional monitoring +and the mitigation is somewhat cumbersome and not aligned to the intention +of the time quota. The time quota was intended to help reduce the user's +administration overhead. + +Fix the problem by setting time quota-modified effective size quota be at +least min_region_sz always. + +The issue was discovered [1] by sashiko. + +Link: https://lore.kernel.org/20260407003153.79589-1-sj@kernel.org +Link: https://lore.kernel.org/20260405192504.110014-1-sj@kernel.org [1] +Fixes: 1cd243030059 ("mm/damon/schemes: implement time quota") +Signed-off-by: SeongJae Park +Cc: # 5.16.x +Signed-off-by: Andrew Morton +Signed-off-by: SeongJae Park +Signed-off-by: Greg Kroah-Hartman +--- + mm/damon/core.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/mm/damon/core.c ++++ b/mm/damon/core.c +@@ -1026,6 +1026,7 @@ static void damos_set_effective_quota(st + else + throughput = PAGE_SIZE * 1024; + esz = throughput * quota->ms; ++ esz = max(DAMON_MIN_REGION, esz); + + if (quota->sz && quota->sz < esz) + esz = quota->sz; diff --git a/queue-6.6/mm-damon-core-implement-damon_kdamond_pid.patch b/queue-6.6/mm-damon-core-implement-damon_kdamond_pid.patch new file mode 100644 index 0000000000..3372ec4116 --- /dev/null +++ b/queue-6.6/mm-damon-core-implement-damon_kdamond_pid.patch @@ -0,0 +1,87 @@ +From 4262c53236977de3ceaa3bf2aefdf772c9b874dd Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Thu, 15 Jan 2026 07:20:41 -0800 +Subject: mm/damon/core: implement damon_kdamond_pid() + +From: SeongJae Park + +commit 4262c53236977de3ceaa3bf2aefdf772c9b874dd upstream. + +Patch series "mm/damon: hide kdamond and kdamond_lock from API callers". + +'kdamond' and 'kdamond_lock' fields initially exposed to DAMON API callers +for flexible synchronization and use cases. As DAMON API became somewhat +complicated compared to the early days, Keeping those exposed could only +encourage the API callers to invent more creative but complicated and +difficult-to-debug use cases. + +Fortunately DAMON API callers didn't invent that many creative use cases. +There exist only two use cases of 'kdamond' and 'kdamond_lock'. Finding +whether the kdamond is actively running, and getting the pid of the +kdamond. For the first use case, a dedicated API function, namely +'damon_is_running()' is provided, and all DAMON API callers are using the +function for the use case. Hence only the second use case is where the +fields are directly being used by DAMON API callers. + +To prevent future invention of complicated and erroneous use cases of the +fields, hide the fields from the API callers. For that, provide new +dedicated DAMON API functions for the remaining use case, namely +damon_kdamond_pid(), migrate DAMON API callers to use the new function, +and mark the fields as private fields. + + +This patch (of 5): + +'kdamond' and 'kdamond_lock' are directly being used by DAMON API callers +for getting the pid of the corresponding kdamond. To discourage invention +of creative but complicated and erroneous new usages of the fields that +require careful synchronization, implement a new API function that can +simply be used without the manual synchronizations. + +Link: https://lkml.kernel.org/r/20260115152047.68415-1-sj@kernel.org +Link: https://lkml.kernel.org/r/20260115152047.68415-2-sj@kernel.org +Signed-off-by: SeongJae Park +Signed-off-by: Andrew Morton +Signed-off-by: SeongJae Park +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/damon.h | 1 + + mm/damon/core.c | 17 +++++++++++++++++ + 2 files changed, 18 insertions(+) + +--- a/include/linux/damon.h ++++ b/include/linux/damon.h +@@ -677,6 +677,7 @@ static inline unsigned int damon_max_nr_ + + int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive); + int damon_stop(struct damon_ctx **ctxs, int nr_ctxs); ++int damon_kdamond_pid(struct damon_ctx *ctx); + + int damon_set_region_biggest_system_ram_default(struct damon_target *t, + unsigned long *start, unsigned long *end); +--- a/mm/damon/core.c ++++ b/mm/damon/core.c +@@ -762,6 +762,23 @@ int damon_stop(struct damon_ctx **ctxs, + return err; + } + ++/** ++ * damon_kdamond_pid() - Return pid of a given DAMON context's worker thread. ++ * @ctx: The DAMON context of the question. ++ * ++ * Return: pid if @ctx is running, negative error code otherwise. ++ */ ++int damon_kdamond_pid(struct damon_ctx *ctx) ++{ ++ int pid = -EINVAL; ++ ++ mutex_lock(&ctx->kdamond_lock); ++ if (ctx->kdamond) ++ pid = ctx->kdamond->pid; ++ mutex_unlock(&ctx->kdamond_lock); ++ return pid; ++} ++ + /* + * Reset the aggregated monitoring results ('nr_accesses' of each region). + */ diff --git a/queue-6.6/mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch b/queue-6.6/mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch new file mode 100644 index 0000000000..61d97fbcad --- /dev/null +++ b/queue-6.6/mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch @@ -0,0 +1,259 @@ +From b98b7ff6025ae82570d4915e083f0cbd8d48b3cf Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Sun, 19 Apr 2026 09:10:01 -0700 +Subject: mm/damon/lru_sort: detect and use fresh enabled and kdamond_pid values + +From: SeongJae Park + +commit b98b7ff6025ae82570d4915e083f0cbd8d48b3cf upstream. + +DAMON_LRU_SORT updates 'enabled' and 'kdamond_pid' parameter values, which +represents the running status of its kdamond, when the user explicitly +requests start/stop of the kdamond. The kdamond can, however, be stopped +in events other than the explicit user request in the following three +events. + +1. ctx->regions_score_histogram allocation failure at beginning of the + execution, +2. damon_commit_ctx() failure due to invalid user input, and +3. damon_commit_ctx() failure due to its internal allocation failures. + +Hence, if the kdamond is stopped by the above three events, the values of +the status parameters can be stale. Users could show the stale values and +be confused. This is already bad, but the real consequence is worse. +DAMON_LRU_SORT avoids unnecessary damon_start() and damon_stop() calls +based on the 'enabled' parameter value. And the update of 'enabled' +parameter value depends on the damon_start() and damon_stop() call +results. Hence, once the kdamond has stopped by the unintentional events, +the user cannot restart the kdamond before the system reboot. For +example, the issue can be reproduced via below steps. + + # cd /sys/module/damon_lru_sort/parameters + # + # # start DAMON_LRU_SORT + # echo Y > enabled + # ps -ef | grep kdamond + root 806 2 0 17:53 ? 00:00:00 [kdamond.0] + root 808 803 0 17:53 pts/4 00:00:00 grep kdamond + # + # # commit wrong input to stop kdamond withou explicit stop request + # echo 3 > addr_unit + # echo Y > commit_inputs + bash: echo: write error: Invalid argument + # + # # confirm kdamond is stopped + # ps -ef | grep kdamond + root 811 803 0 17:53 pts/4 00:00:00 grep kdamond + # + # # users casn now show stable status + # cat enabled + Y + # cat kdamond_pid + 806 + # + # # even after fixing the wrong parameter, + # # kdamond cannot be restarted. + # echo 1 > addr_unit + # echo Y > enabled + # ps -ef | grep kdamond + root 815 803 0 17:54 pts/4 00:00:00 grep kdamond + +The problem will only rarely happen in real and common setups for the +following reasons. The allocation failures are unlikely in such setups +since those allocations are arguably too small to fail. Also sane users +on real production environments may not commit wrong input parameters. +But once it happens, the consequence is quite bad. And the bug is a bug. + +The issue stems from the fact that there are multiple events that can +change the status, and following all the events is challenging. +Dynamically detect and use the fresh status for the parameters when those +are requested. + +Link: https://lore.kernel.org/20260419161003.79176-3-sj@kernel.org +Fixes: 40e983cca927 ("mm/damon: introduce DAMON-based LRU-lists Sorting") +Co-developed-by: Liew Rui Yan +Signed-off-by: Liew Rui Yan +Signed-off-by: SeongJae Park +Cc: # 6.0.x +Signed-off-by: Andrew Morton +Signed-off-by: SeongJae Park +(port parts of 42b7491af14c ("mm/damon/core: introduce damon_call()") +and d2b5be741a50 ("mm/damon/sysfs: use DAMON core API +damon_is_running()") for damon_is_running() dependency) +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/damon.h | 1 + mm/damon/core.c | 16 +++++++++ + mm/damon/lru_sort.c | 88 +++++++++++++++++++++++++++++++------------------- + 3 files changed, 73 insertions(+), 32 deletions(-) + +--- a/include/linux/damon.h ++++ b/include/linux/damon.h +@@ -677,6 +677,7 @@ static inline unsigned int damon_max_nr_ + + int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive); + int damon_stop(struct damon_ctx **ctxs, int nr_ctxs); ++bool damon_is_running(struct damon_ctx *ctx); + int damon_kdamond_pid(struct damon_ctx *ctx); + + int damon_set_region_biggest_system_ram_default(struct damon_target *t, +--- a/mm/damon/core.c ++++ b/mm/damon/core.c +@@ -763,6 +763,22 @@ int damon_stop(struct damon_ctx **ctxs, + } + + /** ++ * damon_is_running() - Returns if a given DAMON context is running. ++ * @ctx: The DAMON context to see if running. ++ * ++ * Return: true if @ctx is running, false otherwise. ++ */ ++bool damon_is_running(struct damon_ctx *ctx) ++{ ++ bool running; ++ ++ mutex_lock(&ctx->kdamond_lock); ++ running = ctx->kdamond != NULL; ++ mutex_unlock(&ctx->kdamond_lock); ++ return running; ++} ++ ++/** + * damon_kdamond_pid() - Return pid of a given DAMON context's worker thread. + * @ctx: The DAMON context of the question. + * +--- a/mm/damon/lru_sort.c ++++ b/mm/damon/lru_sort.c +@@ -111,15 +111,6 @@ module_param(monitor_region_start, ulong + static unsigned long monitor_region_end __read_mostly; + module_param(monitor_region_end, ulong, 0600); + +-/* +- * PID of the DAMON thread +- * +- * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread. +- * Else, -1. +- */ +-static int kdamond_pid __read_mostly = -1; +-module_param(kdamond_pid, int, 0400); +- + static struct damos_stat damon_lru_sort_hot_stat; + DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_lru_sort_hot_stat, + lru_sort_tried_hot_regions, lru_sorted_hot_regions, +@@ -249,60 +240,93 @@ static int damon_lru_sort_turn(bool on) + { + int err; + +- if (!on) { +- err = damon_stop(&ctx, 1); +- if (!err) +- kdamond_pid = -1; +- return err; +- } ++ if (!on) ++ return damon_stop(&ctx, 1); + + err = damon_lru_sort_apply_parameters(); + if (err) + return err; + +- err = damon_start(&ctx, 1, true); +- if (err) +- return err; +- kdamond_pid = ctx->kdamond->pid; +- return 0; ++ return damon_start(&ctx, 1, true); ++} ++ ++static bool damon_lru_sort_enabled(void) ++{ ++ if (!ctx) ++ return false; ++ return damon_is_running(ctx); + } + + static int damon_lru_sort_enabled_store(const char *val, + const struct kernel_param *kp) + { +- bool is_enabled = enabled; +- bool enable; + int err; + +- err = kstrtobool(val, &enable); ++ err = kstrtobool(val, &enabled); + if (err) + return err; + +- if (is_enabled == enable) ++ if (damon_lru_sort_enabled() == enabled) + return 0; + + /* Called before init function. The function will handle this. */ + if (!ctx) +- goto set_param_out; ++ return 0; + +- err = damon_lru_sort_turn(enable); +- if (err) +- return err; ++ return damon_lru_sort_turn(enabled); ++} + +-set_param_out: +- enabled = enable; +- return err; ++static int damon_lru_sort_enabled_load(char *buffer, ++ const struct kernel_param *kp) ++{ ++ return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N'); + } + + static const struct kernel_param_ops enabled_param_ops = { + .set = damon_lru_sort_enabled_store, +- .get = param_get_bool, ++ .get = damon_lru_sort_enabled_load, + }; + + module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); + MODULE_PARM_DESC(enabled, + "Enable or disable DAMON_LRU_SORT (default: disabled)"); + ++static int damon_lru_sort_kdamond_pid_store(const char *val, ++ const struct kernel_param *kp) ++{ ++ /* ++ * kdamond_pid is read-only, but kernel command line could write it. ++ * Do nothing here. ++ */ ++ return 0; ++} ++ ++static int damon_lru_sort_kdamond_pid_load(char *buffer, ++ const struct kernel_param *kp) ++{ ++ int kdamond_pid = -1; ++ ++ if (ctx) { ++ kdamond_pid = damon_kdamond_pid(ctx); ++ if (kdamond_pid < 0) ++ kdamond_pid = -1; ++ } ++ return sprintf(buffer, "%d\n", kdamond_pid); ++} ++ ++static const struct kernel_param_ops kdamond_pid_param_ops = { ++ .set = damon_lru_sort_kdamond_pid_store, ++ .get = damon_lru_sort_kdamond_pid_load, ++}; ++ ++/* ++ * PID of the DAMON thread ++ * ++ * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread. ++ * Else, -1. ++ */ ++module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400); ++ + static int damon_lru_sort_handle_commit_inputs(void) + { + int err; diff --git a/queue-6.6/mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch b/queue-6.6/mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch new file mode 100644 index 0000000000..601596baeb --- /dev/null +++ b/queue-6.6/mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch @@ -0,0 +1,240 @@ +From 64a140afa5ed1c6f5ba6d451512cbdbbab1ba339 Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Sun, 19 Apr 2026 09:10:00 -0700 +Subject: mm/damon/reclaim: detect and use fresh enabled and kdamond_pid values + +From: SeongJae Park + +commit 64a140afa5ed1c6f5ba6d451512cbdbbab1ba339 upstream. + +Patch series "mm/damon/modules: detect and use fresh status", v3. + +DAMON modules including DAMON_RECLAIM, DAMON_LRU_SORT and DAMON_STAT +commonly expose the kdamond running status via their parameters. Under +certain scenarios including wrong user inputs and memory allocation +failures, those parameter values can be stale. It can confuse users. For +DAMON_RECLAIM and DAMON_LRU_SORT, it even makes the kdamond unable to be +restarted before the system reboot. + +The problem comes from the fact that there are multiple events for the +status changes and it is difficult to follow up all the scenarios. Fix +the issue by detecting and using the status on demand, instead of using a +cached status that is difficult to be updated. + +Patches 1-3 fix the bugs in DAMON_RECLAIM, DAMON_LRU_SORT and DAMON_STAT +in the order. + + +This patch (of 3): + +DAMON_RECLAIM updates 'enabled' and 'kdamond_pid' parameter values, which +represents the running status of its kdamond, when the user explicitly +requests start/stop of the kdamond. The kdamond can, however, be stopped +in events other than the explicit user request in the following three +events. + +1. ctx->regions_score_histogram allocation failure at beginning of the + execution, +2. damon_commit_ctx() failure due to invalid user input, and +3. damon_commit_ctx() failure due to its internal allocation failures. + +Hence, if the kdamond is stopped by the above three events, the values of +the status parameters can be stale. Users could show the stale values and +be confused. This is already bad, but the real consequence is worse. +DAMON_RECLAIM avoids unnecessary damon_start() and damon_stop() calls +based on the 'enabled' parameter value. And the update of 'enabled' +parameter value depends on the damon_start() and damon_stop() call +results. Hence, once the kdamond has stopped by the unintentional events, +the user cannot restart the kdamond before the system reboot. For +example, the issue can be reproduced via below steps. + + # cd /sys/module/damon_reclaim/parameters + # + # # start DAMON_RECLAIM + # echo Y > enabled + # ps -ef | grep kdamond + root 806 2 0 17:53 ? 00:00:00 [kdamond.0] + root 808 803 0 17:53 pts/4 00:00:00 grep kdamond + # + # # commit wrong input to stop kdamond withou explicit stop request + # echo 3 > addr_unit + # echo Y > commit_inputs + bash: echo: write error: Invalid argument + # + # # confirm kdamond is stopped + # ps -ef | grep kdamond + root 811 803 0 17:53 pts/4 00:00:00 grep kdamond + # + # # users casn now show stable status + # cat enabled + Y + # cat kdamond_pid + 806 + # + # # even after fixing the wrong parameter, + # # kdamond cannot be restarted. + # echo 1 > addr_unit + # echo Y > enabled + # ps -ef | grep kdamond + root 815 803 0 17:54 pts/4 00:00:00 grep kdamond + +The problem will only rarely happen in real and common setups for the +following reasons. The allocation failures are unlikely in such setups +since those allocations are arguably too small to fail. Also sane users +on real production environments may not commit wrong input parameters. +But once it happens, the consequence is quite bad. And the bug is a bug. + +The issue stems from the fact that there are multiple events that can +change the status, and following all the events is challenging. +Dynamically detect and use the fresh status for the parameters when those +are requested. + +Link: https://lore.kernel.org/20260419161003.79176-1-sj@kernel.org +Link: https://lore.kernel.org/20260419161003.79176-2-sj@kernel.org +Fixes: e035c280f6df ("mm/damon/reclaim: support online inputs update") +Co-developed-by: Liew Rui Yan +Signed-off-by: Liew Rui Yan +Signed-off-by: SeongJae Park +Cc: # 5.19.x +Signed-off-by: Andrew Morton +Signed-off-by: SeongJae Park +Signed-off-by: Greg Kroah-Hartman +--- + mm/damon/reclaim.c | 88 +++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 56 insertions(+), 32 deletions(-) + +--- a/mm/damon/reclaim.c ++++ b/mm/damon/reclaim.c +@@ -107,15 +107,6 @@ module_param(monitor_region_end, ulong, + static bool skip_anon __read_mostly; + module_param(skip_anon, bool, 0600); + +-/* +- * PID of the DAMON thread +- * +- * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread. +- * Else, -1. +- */ +-static int kdamond_pid __read_mostly = -1; +-module_param(kdamond_pid, int, 0400); +- + static struct damos_stat damon_reclaim_stat; + DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat, + reclaim_tried_regions, reclaimed_regions, quota_exceeds); +@@ -203,60 +194,93 @@ static int damon_reclaim_turn(bool on) + { + int err; + +- if (!on) { +- err = damon_stop(&ctx, 1); +- if (!err) +- kdamond_pid = -1; +- return err; +- } ++ if (!on) ++ return damon_stop(&ctx, 1); + + err = damon_reclaim_apply_parameters(); + if (err) + return err; + +- err = damon_start(&ctx, 1, true); +- if (err) +- return err; +- kdamond_pid = ctx->kdamond->pid; +- return 0; ++ return damon_start(&ctx, 1, true); ++} ++ ++static bool damon_reclaim_enabled(void) ++{ ++ if (!ctx) ++ return false; ++ return damon_is_running(ctx); + } + + static int damon_reclaim_enabled_store(const char *val, + const struct kernel_param *kp) + { +- bool is_enabled = enabled; +- bool enable; + int err; + +- err = kstrtobool(val, &enable); ++ err = kstrtobool(val, &enabled); + if (err) + return err; + +- if (is_enabled == enable) ++ if (damon_reclaim_enabled() == enabled) + return 0; + + /* Called before init function. The function will handle this. */ + if (!ctx) +- goto set_param_out; ++ return 0; + +- err = damon_reclaim_turn(enable); +- if (err) +- return err; ++ return damon_reclaim_turn(enabled); ++} + +-set_param_out: +- enabled = enable; +- return err; ++static int damon_reclaim_enabled_load(char *buffer, ++ const struct kernel_param *kp) ++{ ++ return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N'); + } + + static const struct kernel_param_ops enabled_param_ops = { + .set = damon_reclaim_enabled_store, +- .get = param_get_bool, ++ .get = damon_reclaim_enabled_load, + }; + + module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); + MODULE_PARM_DESC(enabled, + "Enable or disable DAMON_RECLAIM (default: disabled)"); + ++static int damon_reclaim_kdamond_pid_store(const char *val, ++ const struct kernel_param *kp) ++{ ++ /* ++ * kdamond_pid is read-only, but kernel command line could write it. ++ * Do nothing here. ++ */ ++ return 0; ++} ++ ++static int damon_reclaim_kdamond_pid_load(char *buffer, ++ const struct kernel_param *kp) ++{ ++ int kdamond_pid = -1; ++ ++ if (ctx) { ++ kdamond_pid = damon_kdamond_pid(ctx); ++ if (kdamond_pid < 0) ++ kdamond_pid = -1; ++ } ++ return sprintf(buffer, "%d\n", kdamond_pid); ++} ++ ++static const struct kernel_param_ops kdamond_pid_param_ops = { ++ .set = damon_reclaim_kdamond_pid_store, ++ .get = damon_reclaim_kdamond_pid_load, ++}; ++ ++/* ++ * PID of the DAMON thread ++ * ++ * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread. ++ * Else, -1. ++ */ ++module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400); ++ + static int damon_reclaim_handle_commit_inputs(void) + { + int err; diff --git a/queue-6.6/mtd-spi-nor-sst-factor-out-common-write-operation-to-sst_nor_write_data.patch b/queue-6.6/mtd-spi-nor-sst-factor-out-common-write-operation-to-sst_nor_write_data.patch new file mode 100644 index 0000000000..971becd4f0 --- /dev/null +++ b/queue-6.6/mtd-spi-nor-sst-factor-out-common-write-operation-to-sst_nor_write_data.patch @@ -0,0 +1,107 @@ +From 18bcb4aa54eab75dce41e5c176a1c2bff94f0f79 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cs=C3=B3k=C3=A1s=2C=20Bence?= +Date: Wed, 10 Jul 2024 11:14:01 +0200 +Subject: mtd: spi-nor: sst: Factor out common write operation to `sst_nor_write_data()` +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bence Csókás + +commit 18bcb4aa54eab75dce41e5c176a1c2bff94f0f79 upstream. + +Writing to the Flash in `sst_nor_write()` is a 3-step process: +first an optional one-byte write to get 2-byte-aligned, then the +bulk of the data is written out in vendor-specific 2-byte writes. +Finally, if there's a byte left over, another one-byte write. +This was implemented 3 times in the body of `sst_nor_write()`. +To reduce code duplication, factor out these sub-steps to their +own function. + +Signed-off-by: Csókás, Bence +Reviewed-by: Pratyush Yadav +[pratyush@kernel.org: fixup whitespace, use %zu instead of %i in WARN()] +Signed-off-by: Pratyush Yadav +Link: https://lore.kernel.org/r/20240710091401.1282824-1-csokas.bence@prolan.hu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/spi-nor/sst.c | 39 +++++++++++++++++++-------------------- + 1 file changed, 19 insertions(+), 20 deletions(-) + +--- a/drivers/mtd/spi-nor/sst.c ++++ b/drivers/mtd/spi-nor/sst.c +@@ -123,6 +123,21 @@ static const struct flash_info sst_nor_p + .fixups = &sst26vf_nor_fixups }, + }; + ++static int sst_nor_write_data(struct spi_nor *nor, loff_t to, size_t len, ++ const u_char *buf) ++{ ++ u8 op = (len == 1) ? SPINOR_OP_BP : SPINOR_OP_AAI_WP; ++ int ret; ++ ++ nor->program_opcode = op; ++ ret = spi_nor_write_data(nor, to, 1, buf); ++ if (ret < 0) ++ return ret; ++ WARN(ret != len, "While writing %zu byte written %i bytes\n", len, ret); ++ ++ return spi_nor_wait_till_ready(nor); ++} ++ + static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) + { +@@ -144,16 +159,10 @@ static int sst_nor_write(struct mtd_info + + /* Start write from odd address. */ + if (to % 2) { +- nor->program_opcode = SPINOR_OP_BP; +- + /* write one byte. */ +- ret = spi_nor_write_data(nor, to, 1, buf); ++ ret = sst_nor_write_data(nor, to, 1, buf); + if (ret < 0) + goto out; +- WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret); +- ret = spi_nor_wait_till_ready(nor); +- if (ret) +- goto out; + + to++; + actual++; +@@ -161,16 +170,11 @@ static int sst_nor_write(struct mtd_info + + /* Write out most of the data here. */ + for (; actual < len - 1; actual += 2) { +- nor->program_opcode = SPINOR_OP_AAI_WP; +- + /* write two bytes. */ +- ret = spi_nor_write_data(nor, to, 2, buf + actual); ++ ret = sst_nor_write_data(nor, to, 2, buf + actual); + if (ret < 0) + goto out; +- WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret); +- ret = spi_nor_wait_till_ready(nor); +- if (ret) +- goto out; ++ + to += 2; + nor->sst_write_second = true; + } +@@ -190,14 +194,9 @@ static int sst_nor_write(struct mtd_info + if (ret) + goto out; + +- nor->program_opcode = SPINOR_OP_BP; +- ret = spi_nor_write_data(nor, to, 1, buf + actual); ++ ret = sst_nor_write_data(nor, to, 1, buf + actual); + if (ret < 0) + goto out; +- WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret); +- ret = spi_nor_wait_till_ready(nor); +- if (ret) +- goto out; + + actual += 1; + diff --git a/queue-6.6/mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch b/queue-6.6/mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch new file mode 100644 index 0000000000..ae48bdc704 --- /dev/null +++ b/queue-6.6/mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch @@ -0,0 +1,61 @@ +From a0f64241d3566a49c0a9b33ba7ae458ae22003a9 Mon Sep 17 00:00:00 2001 +From: Sanjaikumar V S +Date: Wed, 11 Mar 2026 10:30:56 +0000 +Subject: mtd: spi-nor: sst: Fix write enable before AAI sequence + +From: Sanjaikumar V S + +commit a0f64241d3566a49c0a9b33ba7ae458ae22003a9 upstream. + +When writing to SST flash starting at an odd address, a single byte is +first programmed using the byte program (BP) command. After this +operation completes, the flash hardware automatically clears the Write +Enable Latch (WEL) bit. + +If an AAI (Auto Address Increment) word program sequence follows, it +requires WEL to be set. Without re-enabling writes, the AAI sequence +fails. + +Add spi_nor_write_enable() after the odd-address byte program when more +data needs to be written. Use a local boolean for clarity. + +Fixes: b199489d37b2 ("mtd: spi-nor: add the framework for SPI NOR") +Cc: stable@vger.kernel.org +Signed-off-by: Sanjaikumar V S +Tested-by: Hendrik Donner +Reviewed-by: Hendrik Donner +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mtd/spi-nor/sst.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/mtd/spi-nor/sst.c ++++ b/drivers/mtd/spi-nor/sst.c +@@ -159,6 +159,8 @@ static int sst_nor_write(struct mtd_info + + /* Start write from odd address. */ + if (to % 2) { ++ bool needs_write_enable = (len > 1); ++ + /* write one byte. */ + ret = sst_nor_write_data(nor, to, 1, buf); + if (ret < 0) +@@ -166,6 +168,17 @@ static int sst_nor_write(struct mtd_info + + to++; + actual++; ++ ++ /* ++ * Byte program clears the write enable latch. If more ++ * data needs to be written using the AAI sequence, ++ * re-enable writes. ++ */ ++ if (needs_write_enable) { ++ ret = spi_nor_write_enable(nor); ++ if (ret) ++ goto out; ++ } + } + + /* Write out most of the data here. */ diff --git a/queue-6.6/pwm-imx-tpm-count-the-number-of-enabled-channels-in-probe.patch b/queue-6.6/pwm-imx-tpm-count-the-number-of-enabled-channels-in-probe.patch new file mode 100644 index 0000000000..e483a57e9f --- /dev/null +++ b/queue-6.6/pwm-imx-tpm-count-the-number-of-enabled-channels-in-probe.patch @@ -0,0 +1,60 @@ +From 3962c24f2d14e8a7f8a23f56b7ce320523947342 Mon Sep 17 00:00:00 2001 +From: "Viorel Suman (OSS)" +Date: Wed, 11 Mar 2026 14:33:09 +0200 +Subject: pwm: imx-tpm: Count the number of enabled channels in probe +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Viorel Suman (OSS) + +commit 3962c24f2d14e8a7f8a23f56b7ce320523947342 upstream. + +On a soft reset TPM PWM IP may preserve its internal state from previous +runtime, therefore on a subsequent OS boot and driver probe +"enable_count" value and TPM PWM IP internal channels "enabled" states +may get unaligned. In consequence on a suspend/resume cycle the call "if +(--tpm->enable_count == 0)" may lead to "enable_count" overflow the +system being blocked from entering suspend due to: + + if (tpm->enable_count > 0) + return -EBUSY; + +Fix the problem by counting the enabled channels in probe function. + +Signed-off-by: Viorel Suman (OSS) +Fixes: 738a1cfec2ed ("pwm: Add i.MX TPM PWM driver support") +Link: https://patch.msgid.link/20260311123309.348904-1-viorel.suman@oss.nxp.com +Cc: stable@vger.kernel.org +Signed-off-by: Uwe Kleine-König +[ukleinek: backport to linux-6.6.y] +Signed-off-by: Uwe Kleine-König +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pwm/pwm-imx-tpm.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/pwm/pwm-imx-tpm.c ++++ b/drivers/pwm/pwm-imx-tpm.c +@@ -350,6 +350,7 @@ static int pwm_imx_tpm_probe(struct plat + { + struct imx_tpm_pwm_chip *tpm; + int ret; ++ unsigned int i; + u32 val; + + tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL); +@@ -383,6 +384,13 @@ static int pwm_imx_tpm_probe(struct plat + + mutex_init(&tpm->lock); + ++ /* count the enabled channels */ ++ for (i = 0; i < tpm->chip.npwm; ++i) { ++ val = readl(tpm->base + PWM_IMX_TPM_CnSC(i)); ++ if (FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val)) ++ ++tpm->enable_count; ++ } ++ + ret = pwmchip_add(&tpm->chip); + if (ret) { + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); diff --git a/queue-6.6/rxrpc-also-unshare-data-response-packets-when-paged-frags-are-present.patch b/queue-6.6/rxrpc-also-unshare-data-response-packets-when-paged-frags-are-present.patch new file mode 100644 index 0000000000..904f974933 --- /dev/null +++ b/queue-6.6/rxrpc-also-unshare-data-response-packets-when-paged-frags-are-present.patch @@ -0,0 +1,62 @@ +From aa54b1d27fe0c2b78e664a34fd0fdf7cd1960d71 Mon Sep 17 00:00:00 2001 +From: Hyunwoo Kim +Date: Fri, 8 May 2026 17:53:09 +0900 +Subject: rxrpc: Also unshare DATA/RESPONSE packets when paged frags are present + +From: Hyunwoo Kim + +commit aa54b1d27fe0c2b78e664a34fd0fdf7cd1960d71 upstream. + +The DATA-packet handler in rxrpc_input_call_event() and the RESPONSE +handler in rxrpc_verify_response() copy the skb to a linear one before +calling into the security ops only when skb_cloned() is true. An skb +that is not cloned but still carries externally-owned paged fragments +(e.g. SKBFL_SHARED_FRAG set by splice() into a UDP socket via +__ip_append_data, or a chained skb_has_frag_list()) falls through to +the in-place decryption path, which binds the frag pages directly into +the AEAD/skcipher SGL via skb_to_sgvec(). + +Extend the gate to also unshare when skb_has_frag_list() or +skb_has_shared_frag() is true. This catches the splice-loopback vector +and other externally-shared frag sources while preserving the +zero-copy fast path for skbs whose frags are kernel-private (e.g. NIC +page_pool RX, GRO). The OOM/trace handling already in place is reused. + +Fixes: d0d5c0cd1e71 ("rxrpc: Use skb_unshare() rather than skb_cow_data()") +Cc: stable@vger.kernel.org +Signed-off-by: Hyunwoo Kim +Reviewed-by: Jiayuan Chen +Acked-by: David Howells +Signed-off-by: Linus Torvalds +Signed-off-by: Wentao Guan +Signed-off-by: Greg Kroah-Hartman +--- + net/rxrpc/call_event.c | 4 +++- + net/rxrpc/conn_event.c | 3 ++- + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/net/rxrpc/call_event.c ++++ b/net/rxrpc/call_event.c +@@ -461,7 +461,9 @@ bool rxrpc_input_call_event(struct rxrpc + + if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA && + sp->hdr.securityIndex != 0 && +- skb_cloned(skb)) { ++ (skb_cloned(skb) || ++ skb_has_frag_list(skb) || ++ skb_has_shared_frag(skb))) { + /* Unshare the packet so that it can be modified by + * in-place decryption. + */ +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -231,7 +231,8 @@ static int rxrpc_verify_response(struct + { + int ret; + +- if (skb_cloned(skb)) { ++ if (skb_cloned(skb) || skb_has_frag_list(skb) || ++ skb_has_shared_frag(skb)) { + /* Copy the packet if shared so that we can do in-place + * decryption. + */ diff --git a/queue-6.6/series b/queue-6.6/series index 5652688ed0..c3b8912dcd 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -442,3 +442,22 @@ spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch spi-microchip-core-qspi-fix-controller-deregistration.patch fbcon-avoid-oob-font-access-if-console-rotation-fails.patch rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch +bluetooth-l2cap-fix-null-ptr-deref-in-l2cap_sock_get_sndtimeo_cb.patch +bonding-fix-use-after-free-due-to-enslave-fail-after-slave-array-update.patch +mm-damon-core-disallow-time-quota-setting-zero-esz.patch +rxrpc-also-unshare-data-response-packets-when-paged-frags-are-present.patch +mm-damon-core-implement-damon_kdamond_pid.patch +mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch +usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch +mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch +ksmbd-fix-use-after-free-in-__ksmbd_close_fd-via-durable-scavenger.patch +mtd-spi-nor-sst-factor-out-common-write-operation-to-sst_nor_write_data.patch +mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch +pwm-imx-tpm-count-the-number-of-enabled-channels-in-probe.patch +batman-adv-stop-tp_meter-sessions-during-mesh-teardown.patch +batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failure.patch +btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch +tracing-probes-limit-size-of-event-probe-to-3k.patch +usb-dwc3-move-guid-programming-after-phy-initialization.patch +ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch +kvm-arm64-wake-up-from-wfi-when-iqrchip-is-in-userspace.patch diff --git a/queue-6.6/tracing-probes-limit-size-of-event-probe-to-3k.patch b/queue-6.6/tracing-probes-limit-size-of-event-probe-to-3k.patch new file mode 100644 index 0000000000..b224386722 --- /dev/null +++ b/queue-6.6/tracing-probes-limit-size-of-event-probe-to-3k.patch @@ -0,0 +1,77 @@ +From stable+bounces-247730-greg=kroah.com@vger.kernel.org Fri May 15 14:40:38 2026 +From: Sasha Levin +Date: Fri, 15 May 2026 08:06:51 -0400 +Subject: tracing/probes: Limit size of event probe to 3K +To: stable@vger.kernel.org +Cc: Steven Rostedt , Mathieu Desnoyers , "Masami Hiramatsu (Google)" , Sasha Levin +Message-ID: <20260515120651.3074726-1-sashal@kernel.org> + +From: Steven Rostedt + +[ Upstream commit b2aa3b4d64e460ac606f386c24e7d8a873ce6f1a ] + +There currently isn't a max limit an event probe can be. One could make an +event greater than PAGE_SIZE, which makes the event useless because if +it's bigger than the max event that can be recorded into the ring buffer, +then it will never be recorded. + +A event probe should never need to be greater than 3K, so make that the +max size. As long as the max is less than the max that can be recorded +onto the ring buffer, it should be fine. + +Cc: stable@vger.kernel.org +Cc: Mathieu Desnoyers +Acked-by: Masami Hiramatsu (Google) +Fixes: 93ccae7a22274 ("tracing/kprobes: Support basic types on dynamic events") +Link: https://patch.msgid.link/20260428122302.706610ba@gandalf.local.home +Signed-off-by: Steven Rostedt +[ adjusted context to place MAX_PROBE_EVENT_SIZE near MAX_STRING_SIZE and appended EVENT_TOO_BIG after NEED_STRING_TYPE ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/trace_probe.c | 6 ++++++ + kernel/trace/trace_probe.h | 4 +++- + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c +index d46a1033ba5b3..dee9494ed189a 100644 +--- a/kernel/trace/trace_probe.c ++++ b/kernel/trace/trace_probe.c +@@ -1366,6 +1366,12 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, + parg->offset = *size; + *size += parg->type->size * (parg->count ?: 1); + ++ if (*size > MAX_PROBE_EVENT_SIZE) { ++ ret = -E2BIG; ++ trace_probe_log_err(ctx->offset, EVENT_TOO_BIG); ++ goto fail; ++ } ++ + if (parg->count) { + len = strlen(parg->type->fmttype) + 6; + parg->fmt = kmalloc(len, GFP_KERNEL); +diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h +index c71fa9c2f3815..ce5a0935cd45c 100644 +--- a/kernel/trace/trace_probe.h ++++ b/kernel/trace/trace_probe.h +@@ -35,6 +35,7 @@ + #define MAX_ARG_NAME_LEN 32 + #define MAX_BTF_ARGS_LEN 128 + #define MAX_STRING_SIZE PATH_MAX ++#define MAX_PROBE_EVENT_SIZE 3072 + + /* Reserved field names */ + #define FIELD_STRING_IP "__probe_ip" +@@ -546,7 +547,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, + C(NO_BTF_FIELD, "This field is not found."), \ + C(BAD_BTF_TID, "Failed to get BTF type info."),\ + C(BAD_TYPE4STR, "This type does not fit for string."),\ +- C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"), ++ C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\ ++ C(EVENT_TOO_BIG, "Event too big (too many fields?)"), + + #undef C + #define C(a, b) TP_ERR_##a +-- +2.53.0 + diff --git a/queue-6.6/usb-dwc3-move-guid-programming-after-phy-initialization.patch b/queue-6.6/usb-dwc3-move-guid-programming-after-phy-initialization.patch new file mode 100644 index 0000000000..ec1fe57062 --- /dev/null +++ b/queue-6.6/usb-dwc3-move-guid-programming-after-phy-initialization.patch @@ -0,0 +1,63 @@ +From sashal@kernel.org Wed May 13 15:11:20 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 09:11:17 -0400 +Subject: usb: dwc3: Move GUID programming after PHY initialization +To: stable@vger.kernel.org +Cc: Selvarasu Ganesan , stable , Pritam Manohar Sutar , Thinh Nguyen , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260513131117.3723171-1-sashal@kernel.org> + +From: Selvarasu Ganesan + +[ Upstream commit aad35f9c926ec220b0742af1ada45666ae667956 ] + +The Linux Version Code is currently written to the GUID register before +PHY initialization. Certain PHY implementations (such as Synopsys eUSB +PHY performing link_sw_reset) clear the GUID register to its default +value during initialization, causing the kernel version information to +be lost. + +Move the GUID register programming to occur after PHY initialization +completes to ensure the Linux version information persists. + +Fixes: fa0ea13e9f1c ("usb: dwc3: core: write LINUX_VERSION_CODE to our GUID register") +Cc: stable +Reported-by: Pritam Manohar Sutar +Signed-off-by: Selvarasu Ganesan +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260417063314.2359-1-selvarasu.g@samsung.com +Signed-off-by: Greg Kroah-Hartman +[ adapted dwc3_writel(dwc, ...) to dwc3_writel(dwc->regs, ...) ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -1240,12 +1240,6 @@ static int dwc3_core_init(struct dwc3 *d + + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + +- /* +- * Write Linux Version Code to our GUID register so it's easy to figure +- * out which kernel version a bug was found. +- */ +- dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE); +- + ret = dwc3_phy_setup(dwc); + if (ret) + return ret; +@@ -1277,6 +1271,12 @@ static int dwc3_core_init(struct dwc3 *d + if (ret) + goto err_exit_phy; + ++ /* ++ * Write Linux Version Code to our GUID register so it's easy to figure ++ * out which kernel version a bug was found. ++ */ ++ dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE); ++ + dwc3_core_setup_global_control(dwc); + dwc3_core_num_eps(dwc); + diff --git a/queue-6.6/usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch b/queue-6.6/usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch new file mode 100644 index 0000000000..442472e63e --- /dev/null +++ b/queue-6.6/usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch @@ -0,0 +1,84 @@ +From 2909f0d4994fb4306bf116df5ccee797791fce2c Mon Sep 17 00:00:00 2001 +From: Amit Sunil Dhamne +Date: Tue, 14 Apr 2026 00:58:32 +0000 +Subject: usb: typec: tcpm: reset internal port states on soft reset AMS + +From: Amit Sunil Dhamne + +commit 2909f0d4994fb4306bf116df5ccee797791fce2c upstream. + +Reset internal port states (such as vdm_sm_running and +explicit_contract) on soft reset AMS as the port needs to negotiate a +new contract. The consequence of leaving the states in as-is cond are as +follows: + * port is in SRC power role and an explicit contract is negotiated + with the port partner (in sink role) + * port partner sends a Soft Reset AMS while VDM State Machine is + running + * port accepts the Soft Reset request and the port advertises src caps + * port partner sends a Request message but since the explicit_contract + and vdm_sm_running are true from previous negotiation, the port ends + up sending Soft Reset instead of Accept msg. + +Stub Log: +[ 203.653942] AMS DISCOVER_IDENTITY start +[ 203.653947] PD TX, header: 0x176f +[ 203.655901] PD TX complete, status: 0 +[ 203.657470] PD RX, header: 0x124f [1] +[ 203.657477] Rx VDM cmd 0xff008081 type 2 cmd 1 len 1 +[ 203.657482] AMS DISCOVER_IDENTITY finished +[ 203.657484] cc:=4 +[ 204.155698] PD RX, header: 0x144f [1] +[ 204.155718] Rx VDM cmd 0xeeee8001 type 0 cmd 1 len 1 +[ 204.155741] PD TX, header: 0x196f +[ 204.157622] PD TX complete, status: 0 +[ 204.160060] PD RX, header: 0x4d [1] +[ 204.160066] state change SRC_READY -> SOFT_RESET [rev2 SOFT_RESET_AMS] +[ 204.160076] PD TX, header: 0x163 +[ 204.162486] PD TX complete, status: 0 +[ 204.162832] AMS SOFT_RESET_AMS finished +[ 204.162840] cc:=4 +[ 204.162891] AMS POWER_NEGOTIATION start +[ 204.162896] state change SOFT_RESET -> AMS_START [rev2 POWER_NEGOTIATION] +[ 204.162908] state change AMS_START -> SRC_SEND_CAPABILITIES [rev2 POWER_NEGOTIATION] +[ 204.162913] PD TX, header: 0x1361 +[ 204.165529] PD TX complete, status: 0 +[ 204.165571] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES_TIMEOUT @ 60 ms [rev2 POWER_NEGOTIATION] +[ 204.166996] PD RX, header: 0x1242 [1] +[ 204.167009] state change SRC_SEND_CAPABILITIES -> SRC_SOFT_RESET_WAIT_SNK_TX [rev2 POWER_NEGOTIATION] +[ 204.167019] AMS POWER_NEGOTIATION finished +[ 204.167020] cc:=4 +[ 204.167083] AMS SOFT_RESET_AMS start +[ 204.167086] state change SRC_SOFT_RESET_WAIT_SNK_TX -> SOFT_RESET_SEND [rev2 SOFT_RESET_AMS] +[ 204.167092] PD TX, header: 0x16d +[ 204.168824] PD TX complete, status: 0 +[ 204.168854] pending state change SOFT_RESET_SEND -> HARD_RESET_SEND @ 60 ms [rev2 SOFT_RESET_AMS] +[ 204.171876] PD RX, header: 0x43 [1] +[ 204.171879] AMS SOFT_RESET_AMS finished + +This causes COMMON.PROC.PD.11.2 check failure for +TEST.PD.VDM.SRC.2_Rev2Src test on the PD compliance tester. + +Signed-off-by: Amit Sunil Dhamne +Fixes: 8d3a0578ad1a ("usb: typec: tcpm: Respond Wait if VDM state machine is running") +Fixes: f0690a25a140 ("staging: typec: USB Type-C Port Manager (tcpm)") +Cc: stable +Reviewed-by: Badhri Jagan Sridharan +Acked-by: Heikki Krogerus +Link: https://patch.msgid.link/20260414-fix-soft-reset-v1-1-01d7cb9764e2@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/tcpm/tcpm.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -4610,6 +4610,8 @@ static void run_state_machine(struct tcp + usb_power_delivery_unregister_capabilities(port->partner_source_caps); + port->partner_source_caps = NULL; + tcpm_pd_send_control(port, PD_CTRL_ACCEPT); ++ port->vdm_sm_running = false; ++ port->explicit_contract = false; + tcpm_ams_finish(port); + if (port->pwr_role == TYPEC_SOURCE) { + port->upcoming_state = SRC_SEND_CAPABILITIES;