--- /dev/null
+From a84c8d44d6c542c5843abe7b580475f0ea12e8f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 10:59:49 -0400
+Subject: locking/rtmutex: Skip remove_waiter() when waiter is not enqueued
+
+From: Davidlohr Bueso <dave@stgolabs.net>
+
+[ Upstream commit 40a25d59e85b3c8709ac2424d44f65610467871e ]
+
+syzbot triggered the following splat in remove_waiter() via
+FUTEX_CMP_REQUEUE_PI:
+
+ KASAN: null-ptr-deref in range [0x0000000000000a88-0x0000000000000a8f]
+ class_raw_spinlock_constructor
+ remove_waiter+0x159/0x1200 kernel/locking/rtmutex.c:1561
+ rt_mutex_start_proxy_lock+0x103/0x120
+ futex_requeue+0x10e4/0x20d0
+ __x64_sys_futex+0x34f/0x4d0
+
+task_blocks_on_rt_mutex() does not arm the waiter upon deadlock detection,
+leaving waiter->task nil, where 3bfdc63936dd ("rtmutex: Use waiter::task instead
+of current in remove_waiter()") made this fatal.
+
+Furthermore, rt_mutex_start_proxy_lock() should not be calling into remove_waiter()
+upon a successfully grabbing the rtmutex. 1a1fb985f2e2 ("futex: Handle early deadlock
+return correctly"), moved the remove_waiter() out of __rt_mutex_start_proxy_lock()
+(where 'ret' was only ever 0 or < 0) into the wrapper. Tighten this check to
+account for try_to_take_rt_mutex().
+
+Fixes: 3bfdc63936dd ("rtmutex: Use waiter::task instead of current in remove_waiter()")
+Reported-by: syzbot+78147abe6c524f183ee9@syzkaller.appspotmail.com
+Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
+Signed-off-by: Thomas Gleixner <tglx@kernel.org>
+Cc: stable@vger.kernel.org
+Closes: https://lore.kernel.org/all/69f114ac.050a0220.ac8b.0003.GAE@google.com/
+Link: https://patch.msgid.link/20260507112913.1019537-1-dave@stgolabs.net
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/locking/rtmutex.c | 3 +++
+ kernel/locking/rtmutex_api.c | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
+index f79c9286c7c0c1..2118f8928eb7cb 100644
+--- a/kernel/locking/rtmutex.c
++++ b/kernel/locking/rtmutex.c
+@@ -1513,6 +1513,9 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,
+
+ lockdep_assert_held(&lock->wait_lock);
+
++ if (!waiter_task) /* never enqueued */
++ return;
++
+ raw_spin_lock(&waiter_task->pi_lock);
+ rt_mutex_dequeue(lock, waiter);
+ waiter_task->pi_blocked_on = NULL;
+diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c
+index 56d1938cb52a1f..c4e191340c59b3 100644
+--- a/kernel/locking/rtmutex_api.c
++++ b/kernel/locking/rtmutex_api.c
+@@ -322,7 +322,7 @@ int __sched rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,
+
+ raw_spin_lock_irq(&lock->wait_lock);
+ ret = __rt_mutex_start_proxy_lock(lock, waiter, task);
+- if (unlikely(ret))
++ if (unlikely(ret < 0))
+ remove_waiter(lock, waiter);
+ raw_spin_unlock_irq(&lock->wait_lock);
+
+--
+2.53.0
+
--- /dev/null
+From 3badcf0525a192bdf080670715b14358a443ff6b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 23:31:45 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context without DETACH_GROUP.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit behavior, while ensuring
+surviving siblings are ungrouped before the removed event leaves the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 156221bd56615c..9b01cfeb3a0663 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4422,7 +4422,8 @@ static void perf_event_enable_on_exec(int ctxn)
+
+ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+- struct perf_event_context *ctx);
++ struct perf_event_context *ctx,
++ unsigned long detach_flags);
+
+ /*
+ * Removes all events from the current task that have been marked
+@@ -4454,7 +4455,7 @@ static void perf_event_remove_on_exec(int ctxn)
+
+ modified = true;
+
+- perf_event_exit_event(event, ctx);
++ perf_event_exit_event(event, ctx, DETACH_GROUP);
+ }
+
+ raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -13024,10 +13025,11 @@ static void sync_child_event(struct perf_event *child_event)
+ }
+
+ static void
+-perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
++perf_event_exit_event(struct perf_event *event,
++ struct perf_event_context *ctx,
++ unsigned long detach_flags)
+ {
+ struct perf_event *parent_event = event->parent;
+- unsigned long detach_flags = 0;
+
+ if (parent_event) {
+ /*
+@@ -13042,7 +13044,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
+ * Do destroy all inherited groups, we don't care about those
+ * and being thorough is better.
+ */
+- detach_flags = DETACH_GROUP | DETACH_CHILD;
++ detach_flags |= DETACH_GROUP | DETACH_CHILD;
+ mutex_lock(&parent_event->child_mutex);
+ }
+
+@@ -13127,7 +13129,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
+ perf_event_task(child, child_ctx, 0);
+
+ list_for_each_entry_safe(child_event, next, &child_ctx->event_list, event_entry)
+- perf_event_exit_event(child_event, child_ctx);
++ perf_event_exit_event(child_event, child_ctx, 0);
+
+ mutex_unlock(&child_ctx->mutex);
+
+--
+2.53.0
+
--- /dev/null
+From e8757c81615774dbe75e0859f9525dd733240ebd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 10:59:48 -0400
+Subject: rtmutex: Use waiter::task instead of current in remove_waiter()
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit 3bfdc63936dd4773109b7b8c280c0f3b5ae7d349 ]
+
+remove_waiter() is used by the slowlock paths, but it is also used for
+proxy-lock rollback in rt_mutex_start_proxy_lock() when invoked from
+futex_requeue().
+
+In the latter case waiter::task is not current, but remove_waiter()
+operates on current for the dequeue operation. That results in several
+problems:
+
+ 1) the rbtree dequeue happens without waiter::task::pi_lock being held
+
+ 2) the waiter task's pi_blocked_on state is not cleared, which leaves a
+ dangling pointer primed for UAF around.
+
+ 3) rt_mutex_adjust_prio_chain() operates on the wrong top priority waiter
+ task
+
+Use waiter::task instead of current in all related operations in
+remove_waiter() to cure those problems.
+
+[ tglx: Fixup rt_mutex_adjust_prio_chain(), add a comment and amend the
+ changelog ]
+
+Fixes: 8161239a8bcc ("rtmutex: Simplify PI algorithm and make highest prio task get lock")
+Reported-by: Yuan Tan <yuantan098@gmail.com>
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Reported-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Thomas Gleixner <tglx@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/locking/rtmutex.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
+index cf72ef77bfe75a..f79c9286c7c0c1 100644
+--- a/kernel/locking/rtmutex.c
++++ b/kernel/locking/rtmutex.c
+@@ -1500,20 +1500,23 @@ static bool rtmutex_spin_on_owner(struct rt_mutex_base *lock,
+ *
+ * Must be called with lock->wait_lock held and interrupts disabled. It must
+ * have just failed to try_to_take_rt_mutex().
++ *
++ * When invoked from rt_mutex_start_proxy_lock() waiter::task != current !
+ */
+ static void __sched remove_waiter(struct rt_mutex_base *lock,
+ struct rt_mutex_waiter *waiter)
+ {
+ bool is_top_waiter = (waiter == rt_mutex_top_waiter(lock));
+ struct task_struct *owner = rt_mutex_owner(lock);
++ struct task_struct *waiter_task = waiter->task;
+ struct rt_mutex_base *next_lock;
+
+ lockdep_assert_held(&lock->wait_lock);
+
+- raw_spin_lock(¤t->pi_lock);
++ raw_spin_lock(&waiter_task->pi_lock);
+ rt_mutex_dequeue(lock, waiter);
+- current->pi_blocked_on = NULL;
+- raw_spin_unlock(¤t->pi_lock);
++ waiter_task->pi_blocked_on = NULL;
++ raw_spin_unlock(&waiter_task->pi_lock);
+
+ /*
+ * Only update priority if the waiter was the highest priority
+@@ -1549,7 +1552,7 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,
+ raw_spin_unlock_irq(&lock->wait_lock);
+
+ rt_mutex_adjust_prio_chain(owner, RT_MUTEX_MIN_CHAINWALK, lock,
+- next_lock, NULL, current);
++ next_lock, NULL, waiter_task);
+
+ raw_spin_lock_irq(&lock->wait_lock);
+ }
+--
+2.53.0
+
fbdev-fbcon-fix-out-of-bounds-read-in-err_out-of-fbcon_do_set_font.patch
nfsv4-flexfiles-reject-zero-filehandle-version-count.patch
ksmbd-fix-out-of-bounds-read-in-smb_check_perm_dacl.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+rtmutex-use-waiter-task-instead-of-current-in-remove.patch
+locking-rtmutex-skip-remove_waiter-when-waiter-is-no.patch
--- /dev/null
+From f6f4951c2cf47b7dd924f6539926d68a1b845398 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 23:30:55 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 146b37e97832a9..1478bad56e40a1 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4334,7 +4334,8 @@ static void perf_event_enable_on_exec(int ctxn)
+
+ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+- struct perf_event_context *ctx);
++ struct perf_event_context *ctx,
++ unsigned long detach_flags);
+
+ /*
+ * Removes all events from the current task that have been marked
+@@ -4365,7 +4366,7 @@ static void perf_event_remove_on_exec(int ctxn)
+
+ modified = true;
+
+- perf_event_exit_event(event, ctx);
++ perf_event_exit_event(event, ctx, DETACH_GROUP);
+ }
+
+ raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -13055,10 +13056,11 @@ static void sync_child_event(struct perf_event *child_event)
+ }
+
+ static void
+-perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
++perf_event_exit_event(struct perf_event *event,
++ struct perf_event_context *ctx,
++ unsigned long detach_flags)
+ {
+ struct perf_event *parent_event = event->parent;
+- unsigned long detach_flags = 0;
+
+ if (parent_event) {
+ /*
+@@ -13073,7 +13075,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
+ * Do destroy all inherited groups, we don't care about those
+ * and being thorough is better.
+ */
+- detach_flags = DETACH_GROUP | DETACH_CHILD;
++ detach_flags |= DETACH_GROUP | DETACH_CHILD;
+ mutex_lock(&parent_event->child_mutex);
+ }
+
+@@ -13158,7 +13160,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
+ perf_event_task(child, child_ctx, 0);
+
+ list_for_each_entry_safe(child_event, next, &child_ctx->event_list, event_entry)
+- perf_event_exit_event(child_event, child_ctx);
++ perf_event_exit_event(child_event, child_ctx, 0);
+
+ mutex_unlock(&child_ctx->mutex);
+
+--
+2.53.0
+
eventpoll-fix-ep_remove-struct-eventpoll-struct-file-uaf.patch
acpi-cppc-suppress-ubsan-warning-caused-by-field-misuse.patch
rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+virtio_net-support-dynamic-rss-indirection-table-siz.patch
--- /dev/null
+From fdae2106a7ec9598da34c7de2f1f528b5d28fbcf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 11:25:21 +0000
+Subject: virtio_net: Support dynamic rss indirection table size
+
+From: Philo Lu <lulie@linux.alibaba.com>
+
+commit 86a48a00efdf61197b6658e52c6140463eb313dc upstream.
+
+When reading/writing virtio_net_ctrl_rss, the indirection table size is
+obtained from vi->rss_indir_table_size, initialized during virtnet_probe().
+However, the indirection_table was statically sized as
+VIRTIO_NET_RSS_MAX_TABLE_LEN=128, potentially causing issues when
+vi->rss_indir_table_size exceeds this limit.
+
+This patch implements dynamic allocation for the indirection table,
+allocated alongside vi->rss after vi->rss_indir_table_size is initialized,
+and freed in virtnet_remove().
+
+In virtnet_commit_rss_command(), scatter-gather lists for RSS are
+initialized differently based on hash_report presence, so indirection_table
+is unused when !vi->has_rss. Therefore, allocation is unnecessary for
+hash_report-only scenarios.
+
+Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
+Signed-off-by: Philo Lu <lulie@linux.alibaba.com>
+Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Acked-by: Joe Damato <jdamato@fastly.com>
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ Hyokyung Kim: 6.1.y predates the refactor that moved the RSS config into
+ struct virtnet_info, so struct virtio_net_ctrl_rss is still embedded in
+ struct control_buf and reached through the heap-allocated vi->ctrl. Every
+ adaptation below follows from that single difference:
+ - the new allocation and all indirection_table accesses use vi->ctrl->rss
+ in place of upstream's vi->rss;
+ - because vi->ctrl is allocated in virtnet_alloc_queues() (via init_vqs())
+ and freed in virtnet_free_queues(), the table is allocated and freed there
+ too, not in virtnet_probe()/virtnet_remove(), so its lifetime tracks
+ vi->ctrl across the probe error-unwind and freeze/restore paths;
+ - since freeing the table now dereferences vi->ctrl, vi->ctrl is set to NULL
+ after each kfree so a re-entered virtnet_free_queues() cannot dereference
+ or free a stale pointer;
+ - the table is allocated with kcalloc() so it is zero-filled when
+ reallocated on the restore path (upstream never reallocates it). ]
+Signed-off-by: Hyokyung Kim <pulpannie@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/virtio_net.c | 43 +++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 38 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
+index b62b7696313757..2fb00df795d4ab 100644
+--- a/drivers/net/virtio_net.c
++++ b/drivers/net/virtio_net.c
+@@ -179,15 +179,16 @@ struct receive_queue {
+ * because table sizes may be differ according to the device configuration.
+ */
+ #define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
+-#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
+ struct virtio_net_ctrl_rss {
+ u32 hash_types;
+ u16 indirection_table_mask;
+ u16 unclassified_queue;
+- u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
++ u16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */
+ u16 max_tx_vq;
+ u8 hash_key_length;
+ u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
++
++ u16 *indirection_table;
+ };
+
+ /* Control VQ buffers: protected by the rtnl lock */
+@@ -2488,6 +2489,25 @@ static int virtnet_set_ringparam(struct net_device *dev,
+ return 0;
+ }
+
++static int rss_indirection_table_alloc(struct virtio_net_ctrl_rss *rss, u16 indir_table_size)
++{
++ if (!indir_table_size) {
++ rss->indirection_table = NULL;
++ return 0;
++ }
++
++ rss->indirection_table = kcalloc(indir_table_size, sizeof(u16), GFP_KERNEL);
++ if (!rss->indirection_table)
++ return -ENOMEM;
++
++ return 0;
++}
++
++static void rss_indirection_table_free(struct virtio_net_ctrl_rss *rss)
++{
++ kfree(rss->indirection_table);
++}
++
+ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+ {
+ struct net_device *dev = vi->dev;
+@@ -2497,11 +2517,15 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+ /* prepare sgs */
+ sg_init_table(sgs, 4);
+
+- sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
++ sg_buf_size = offsetof(struct virtio_net_ctrl_rss, hash_cfg_reserved);
+ sg_set_buf(&sgs[0], &vi->ctrl->rss, sg_buf_size);
+
+- sg_buf_size = sizeof(uint16_t) * (vi->ctrl->rss.indirection_table_mask + 1);
+- sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
++ if (vi->has_rss) {
++ sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
++ sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
++ } else {
++ sg_set_buf(&sgs[1], &vi->ctrl->rss.hash_cfg_reserved, sizeof(uint16_t));
++ }
+
+ sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
+ - offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
+@@ -3415,7 +3439,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+
+ kfree(vi->rq);
+ kfree(vi->sq);
++ if (vi->ctrl)
++ rss_indirection_table_free(&vi->ctrl->rss);
+ kfree(vi->ctrl);
++ vi->ctrl = NULL;
+ }
+
+ static void _free_receive_bufs(struct virtnet_info *vi)
+@@ -3610,6 +3637,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
+ vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL);
+ if (!vi->ctrl)
+ goto err_ctrl;
++ if ((vi->has_rss || vi->has_rss_hash_report) &&
++ rss_indirection_table_alloc(&vi->ctrl->rss, vi->rss_indir_table_size))
++ goto err_sq;
+ } else {
+ vi->ctrl = NULL;
+ }
+@@ -3642,7 +3672,10 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
+ err_rq:
+ kfree(vi->sq);
+ err_sq:
++ if (vi->ctrl)
++ rss_indirection_table_free(&vi->ctrl->rss);
+ kfree(vi->ctrl);
++ vi->ctrl = NULL;
+ err_ctrl:
+ return -ENOMEM;
+ }
+--
+2.53.0
+
--- /dev/null
+From 57e54b3034f105c415058add64a0f5b462f83737 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 23:29:08 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 8fa3ee209a5be6..da77f856e1c83b 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4536,7 +4536,8 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
+
+ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+- struct perf_event_context *ctx);
++ struct perf_event_context *ctx,
++ unsigned long detach_flags);
+
+ /*
+ * Removes all events from the current task that have been marked
+@@ -4563,7 +4564,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
+
+ modified = true;
+
+- perf_event_exit_event(event, ctx);
++ perf_event_exit_event(event, ctx, DETACH_GROUP);
+ }
+
+ raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -13477,10 +13478,11 @@ static void sync_child_event(struct perf_event *child_event)
+ }
+
+ static void
+-perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
++perf_event_exit_event(struct perf_event *event,
++ struct perf_event_context *ctx,
++ unsigned long detach_flags)
+ {
+ struct perf_event *parent_event = event->parent;
+- unsigned long detach_flags = 0;
+
+ if (parent_event) {
+ /*
+@@ -13495,7 +13497,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
+ * Do destroy all inherited groups, we don't care about those
+ * and being thorough is better.
+ */
+- detach_flags = DETACH_GROUP | DETACH_CHILD;
++ detach_flags |= DETACH_GROUP | DETACH_CHILD;
+ mutex_lock(&parent_event->child_mutex);
+ }
+
+@@ -13574,7 +13576,7 @@ static void perf_event_exit_task_context(struct task_struct *child)
+ perf_event_task(child, child_ctx, 0);
+
+ list_for_each_entry_safe(child_event, next, &child_ctx->event_list, event_entry)
+- perf_event_exit_event(child_event, child_ctx);
++ perf_event_exit_event(child_event, child_ctx, 0);
+
+ mutex_unlock(&child_ctx->mutex);
+
+--
+2.53.0
+
--- /dev/null
+From 3001d0c22e2f93bf90c6fe056e96630b6d5a10d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 20:03:59 +0200
+Subject: rust: kasan: KASAN+RUST requires clang
+
+From: Alice Ryhl <aliceryhl@google.com>
+
+[ Upstream commit 5b271543d0f08e9733d4732721e960e285f6448f ]
+
+Kernel KASAN involves passing various llvm/gcc specific arguments to
+the C and Rust compiler. Since these arguments differ between llvm and
+gcc, it's not safe to mix an llvm-based rustc with a gcc build when
+kasan is enabled.
+
+Signed-off-by: Alice Ryhl <aliceryhl@google.com>
+Reviewed-by: Gary Guo <gary@garyguo.net>
+Cc: stable@vger.kernel.org
+Fixes: e3117404b411 ("kbuild: rust: Enable KASAN support")
+Link: https://patch.msgid.link/20260408-kasan-rust-sw-tags-v3-1-e07964d14363@google.com
+Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ init/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/init/Kconfig b/init/Kconfig
+index f4b91b1857bf86..53eba5cd88ff51 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1974,6 +1974,7 @@ config RUST
+ depends on !CFI_CLANG || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
+ select CFI_ICALL_NORMALIZE_INTEGERS if CFI_CLANG
+ depends on !CALL_PADDING || RUSTC_VERSION >= 108100
++ depends on !KASAN || CC_IS_CLANG
+ depends on !KASAN_SW_TAGS
+ depends on !(MITIGATION_RETHUNK && KASAN) || RUSTC_VERSION >= 108300
+ help
+--
+2.53.0
+
platform-x86-intel-hid-protect-acpi-notify-handler-against-recursion.patch
loongarch-add-pio-for-early-access-before-acpi-pci-root-register.patch
rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+rust-kasan-kasan-rust-requires-clang.patch
--- /dev/null
+From 0f01cb9f5084015014a40f1541853d3081857f69 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jun 2026 11:06:51 -0700
+Subject: fscrypt: Fix key setup in edge case with multiple data unit sizes
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+[ Upstream commit dd015b566d505d698386103e9c80b739c7336eb8 ]
+
+The addition of support for customizable data unit sizes introduced an
+edge case where a file's contents can be en/decrypted with the wrong
+data unit size. It occurs when there are multiple v2 policies that:
+
+- Have *different* data unit sizes, via the log2_data_unit_size field
+
+- Share the same master_key_identifier, contents_encryption_mode, and
+ either FSCRYPT_POLICY_FLAG_DIRECT_KEY,
+ FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32, or
+ FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64
+
+- Are being used on the same filesystem, which also must be mounted with
+ the "inlinecrypt" mount option.
+
+Fortunately this edge case doesn't actually occur in practice. I just
+found it via code review. But it needs to be fixed regardless.
+
+The bug is caused by the data unit size not being fully considered when
+blk_crypto_keys are cached in mk_direct_keys, mk_iv_ino_lblk_32_keys,
+and mk_iv_ino_lblk_64_keys. They're differentiated only by master key,
+encryption mode, and flag. However, each one actually has a data unit
+size too. Only the first data unit size that is cached is used.
+
+To fix this, start using the data unit size to differentiate the cached
+keys. For several reasons, including avoiding increasing the size of
+struct fscrypt_master_key, just replace all three arrays with a single
+linked list instead of changing them into two-dimensional arrays. This
+works well when considering that in practice at most 2 entries are used
+across all three arrays, so it was already mostly wasted space.
+
+For simplicity, make the list also take over the publish/subscribe of
+the prepared key itself. That is, create separate list nodes for
+blk_crypto_keys vs crypto_skciphers, and add nodes to the list only when
+their key is actually prepared. (Note that the legacy
+fscrypt_direct_keys table in fs/crypto/keysetup_v1.c already works this
+way.) This eliminates the need for the additional memory barriers when
+reading and writing the fields of struct fscrypt_prepared_key.
+
+Note that I technically should have included the data unit size in the
+HKDF info string as well. But it's too late to change that.
+
+Fixes: 5b1188847180 ("fscrypt: support crypto data unit size less than filesystem block size")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618180652.52742-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/fscrypt_private.h | 52 +++++++++-------
+ fs/crypto/inline_crypt.c | 8 +--
+ fs/crypto/keyring.c | 23 ++++---
+ fs/crypto/keysetup.c | 118 ++++++++++++++++++++++--------------
+ 4 files changed, 120 insertions(+), 81 deletions(-)
+
+diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
+index 4e8e82a9ccf9a3..3bcde4b59efb0e 100644
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -236,7 +236,7 @@ struct fscrypt_symlink_data {
+ * @tfm: crypto API transform object
+ * @blk_key: key for blk-crypto
+ *
+- * Normally only one of the fields will be non-NULL.
++ * Only one of the fields is non-NULL.
+ */
+ struct fscrypt_prepared_key {
+ struct crypto_sync_skcipher *tfm;
+@@ -245,6 +245,15 @@ struct fscrypt_prepared_key {
+ #endif
+ };
+
++/* An entry in the linked list ->mk_mode_keys */
++struct fscrypt_mode_key {
++ struct fscrypt_prepared_key key;
++ struct list_head link;
++ u8 hkdf_context;
++ u8 mode_num;
++ u8 data_unit_bits;
++};
++
+ /*
+ * fscrypt_inode_info - the "encryption key" for an inode
+ *
+@@ -433,20 +442,12 @@ int fscrypt_derive_sw_secret(struct super_block *sb,
+ * @prep_key, depending on which encryption implementation the file will use.
+ */
+ static inline bool
+-fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
++fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
+ const struct fscrypt_inode_info *ci)
+ {
+- /*
+- * The two smp_load_acquire()'s here pair with the smp_store_release()'s
+- * in fscrypt_prepare_inline_crypt_key() and fscrypt_prepare_key().
+- * I.e., in some cases (namely, if this prep_key is a per-mode
+- * encryption key) another task can publish blk_key or tfm concurrently,
+- * executing a RELEASE barrier. We need to use smp_load_acquire() here
+- * to safely ACQUIRE the memory the other task published.
+- */
+ if (fscrypt_using_inline_encryption(ci))
+- return smp_load_acquire(&prep_key->blk_key) != NULL;
+- return smp_load_acquire(&prep_key->tfm) != NULL;
++ return prep_key->blk_key != NULL;
++ return prep_key->tfm != NULL;
+ }
+
+ #else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
+@@ -489,10 +490,10 @@ fscrypt_derive_sw_secret(struct super_block *sb,
+ }
+
+ static inline bool
+-fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
++fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
+ const struct fscrypt_inode_info *ci)
+ {
+- return smp_load_acquire(&prep_key->tfm) != NULL;
++ return prep_key->tfm != NULL;
+ }
+ #endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
+
+@@ -580,8 +581,8 @@ struct fscrypt_master_key {
+ /*
+ * Active and structural reference counts. An active ref guarantees
+ * that the struct continues to exist, continues to be in the keyring
+- * ->s_master_keys, and that any embedded subkeys (e.g.
+- * ->mk_direct_keys) that have been prepared continue to exist.
++ * ->s_master_keys, and that any non-file-scoped subkeys (e.g.
++ * ->mk_mode_keys) that have been prepared continue to exist.
+ * A structural ref only guarantees that the struct continues to exist.
+ *
+ * There is one active ref associated with ->mk_present being true, and
+@@ -635,12 +636,21 @@ struct fscrypt_master_key {
+ spinlock_t mk_decrypted_inodes_lock;
+
+ /*
+- * Per-mode encryption keys for the various types of encryption policies
+- * that use them. Allocated and derived on-demand.
++ * A list of 'struct fscrypt_mode_key' for the (hkdf_context, mode_num,
++ * data_unit_bits, inlinecrypt) combinations that are in use for this
++ * master key, for hkdf_context in [HKDF_CONTEXT_DIRECT_KEY,
++ * HKDF_CONTEXT_IV_INO_LBLK_32_KEY, HKDF_CONTEXT_IV_INO_LBLK_64_KEY].
++ *
++ * This is a linked list and not a hash table because in practice
++ * there's just a single encryption policy per master key, using
++ * _at most_ 2 nodes in this list. Per-file keys don't use this at all.
++ *
++ * This list is append-only until the master key is fully removed, at
++ * which time the list is cleared. Before then,
++ * fscrypt_mode_key_setup_mutex synchronizes appends, and searches use
++ * the RCU read lock together with ->mk_sem held for read.
+ */
+- struct fscrypt_prepared_key mk_direct_keys[FSCRYPT_MODE_MAX + 1];
+- struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[FSCRYPT_MODE_MAX + 1];
+- struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[FSCRYPT_MODE_MAX + 1];
++ struct list_head mk_mode_keys;
+
+ /* Hash key for inode numbers. Initialized only when needed. */
+ siphash_key_t mk_ino_hash_key;
+diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
+index ed6e926226b51d..645cc493607294 100644
+--- a/fs/crypto/inline_crypt.c
++++ b/fs/crypto/inline_crypt.c
+@@ -198,13 +198,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ goto fail;
+ }
+
+- /*
+- * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
+- * I.e., here we publish ->blk_key with a RELEASE barrier so that
+- * concurrent tasks can ACQUIRE it. Note that this concurrency is only
+- * possible for per-mode keys, not for per-file keys.
+- */
+- smp_store_release(&prep_key->blk_key, blk_key);
++ prep_key->blk_key = blk_key;
+ return 0;
+
+ fail:
+diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
+index 3adbd7167055a9..29bea5f3c98234 100644
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -87,14 +87,14 @@ void fscrypt_put_master_key(struct fscrypt_master_key *mk)
+ void fscrypt_put_master_key_activeref(struct super_block *sb,
+ struct fscrypt_master_key *mk)
+ {
+- size_t i;
++ struct fscrypt_mode_key *node, *tmp;
+
+ if (!refcount_dec_and_test(&mk->mk_active_refs))
+ return;
+ /*
+ * No active references left, so complete the full removal of this
+ * fscrypt_master_key struct by removing it from the keyring and
+- * destroying any subkeys embedded in it.
++ * destroying any non-file-scoped subkeys.
+ */
+
+ if (WARN_ON_ONCE(!sb->s_master_keys))
+@@ -110,13 +110,16 @@ void fscrypt_put_master_key_activeref(struct super_block *sb,
+ WARN_ON_ONCE(mk->mk_present);
+ WARN_ON_ONCE(!list_empty(&mk->mk_decrypted_inodes));
+
+- for (i = 0; i <= FSCRYPT_MODE_MAX; i++) {
+- fscrypt_destroy_prepared_key(
+- sb, &mk->mk_direct_keys[i]);
+- fscrypt_destroy_prepared_key(
+- sb, &mk->mk_iv_ino_lblk_64_keys[i]);
+- fscrypt_destroy_prepared_key(
+- sb, &mk->mk_iv_ino_lblk_32_keys[i]);
++ /*
++ * Destroy any non-file-scoped subkeys. Since ->mk_active_refs == 0,
++ * they're no longer referenced by any inodes. Nor can key setup run
++ * and use them again. So they're no longer needed. (This implies no
++ * concurrent readers, so we don't need list_del_rcu() for example.)
++ */
++ list_for_each_entry_safe(node, tmp, &mk->mk_mode_keys, link) {
++ fscrypt_destroy_prepared_key(sb, &node->key);
++ list_del(&node->link);
++ kfree(node);
+ }
+ memzero_explicit(&mk->mk_ino_hash_key,
+ sizeof(mk->mk_ino_hash_key));
+@@ -445,6 +448,8 @@ static int add_new_master_key(struct super_block *sb,
+ INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
+ spin_lock_init(&mk->mk_decrypted_inodes_lock);
+
++ INIT_LIST_HEAD(&mk->mk_mode_keys);
++
+ if (mk_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
+ err = allocate_master_key_users_keyring(mk);
+ if (err)
+diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
+index 4bd3918f50e3fa..f27997ef9a08c5 100644
+--- a/fs/crypto/keysetup.c
++++ b/fs/crypto/keysetup.c
+@@ -163,13 +163,7 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
+ tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+- /*
+- * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
+- * I.e., here we publish ->tfm with a RELEASE barrier so that
+- * concurrent tasks can ACQUIRE it. Note that this concurrency is only
+- * possible for per-mode keys, not for per-file keys.
+- */
+- smp_store_release(&prep_key->tfm, tfm);
++ prep_key->tfm = tfm;
+ return 0;
+ }
+
+@@ -190,9 +184,37 @@ int fscrypt_set_per_file_enc_key(struct fscrypt_inode_info *ci,
+ return fscrypt_prepare_key(&ci->ci_enc_key, raw_key, ci);
+ }
+
++/*
++ * Find the fscrypt_prepared_key (if any) for a particular (mk, hkdf_context,
++ * mode_num, data_unit_bits, inlinecrypt) combination.
++ *
++ * The caller must hold ->mk_sem for reading and ->mk_present must be true,
++ * ensuring that ->mk_mode_keys is still append-only.
++ */
++static struct fscrypt_prepared_key *
++fscrypt_find_mode_key(struct fscrypt_master_key *mk, u8 hkdf_context,
++ u8 mode_num, const struct fscrypt_inode_info *ci)
++{
++ struct fscrypt_mode_key *node;
++
++ /*
++ * The RCU read lock here is used only to synchronize with concurrent
++ * list_add_tail_rcu(). Concurrent deletions are impossible here, so
++ * returning a pointer to a node without taking any refcount is safe.
++ */
++ guard(rcu)();
++ list_for_each_entry_rcu(node, &mk->mk_mode_keys, link) {
++ if (node->hkdf_context == hkdf_context &&
++ node->mode_num == mode_num &&
++ node->data_unit_bits == ci->ci_data_unit_bits &&
++ fscrypt_is_key_prepared(&node->key, ci))
++ return &node->key;
++ }
++ return NULL;
++}
++
+ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
+ struct fscrypt_master_key *mk,
+- struct fscrypt_prepared_key *keys,
+ u8 hkdf_context, bool include_fs_uuid)
+ {
+ const struct inode *inode = ci->ci_inode;
+@@ -200,7 +222,8 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
+ struct fscrypt_mode *mode = ci->ci_mode;
+ const u8 mode_num = mode - fscrypt_modes;
+ struct fscrypt_prepared_key *prep_key;
+- u8 mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
++ struct fscrypt_mode_key *new_node;
++ u8 raw_mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
+ u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)];
+ unsigned int hkdf_infolen = 0;
+ bool use_hw_wrapped_key = false;
+@@ -223,48 +246,56 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
+ use_hw_wrapped_key = true;
+ }
+
+- prep_key = &keys[mode_num];
+- if (fscrypt_is_key_prepared(prep_key, ci)) {
++ prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
++ if (prep_key) {
+ ci->ci_enc_key = *prep_key;
+ return 0;
+ }
+
+- mutex_lock(&fscrypt_mode_key_setup_mutex);
++ guard(mutex)(&fscrypt_mode_key_setup_mutex);
+
+- if (fscrypt_is_key_prepared(prep_key, ci))
+- goto done_unlock;
++ prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
++ if (prep_key) {
++ ci->ci_enc_key = *prep_key;
++ return 0;
++ }
++
++ new_node = kzalloc_obj(*new_node);
++ if (!new_node)
++ return -ENOMEM;
++ new_node->hkdf_context = hkdf_context;
++ new_node->mode_num = mode_num;
++ new_node->data_unit_bits = ci->ci_data_unit_bits;
++ prep_key = &new_node->key;
+
+ if (use_hw_wrapped_key) {
+ err = fscrypt_prepare_inline_crypt_key(prep_key,
+ mk->mk_secret.bytes,
+ mk->mk_secret.size, true,
+ ci);
+- if (err)
+- goto out_unlock;
+- goto done_unlock;
++ } else {
++ static_assert(sizeof(mode_num) == 1);
++ static_assert(sizeof(sb->s_uuid) == 16);
++ static_assert(sizeof(hkdf_info) == 17);
++ hkdf_info[hkdf_infolen++] = mode_num;
++ if (include_fs_uuid) {
++ memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
++ sizeof(sb->s_uuid));
++ hkdf_infolen += sizeof(sb->s_uuid);
++ }
++ fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context,
++ hkdf_info, hkdf_infolen, raw_mode_key,
++ mode->keysize);
++ err = fscrypt_prepare_key(prep_key, raw_mode_key, ci);
++ memzero_explicit(raw_mode_key, mode->keysize);
+ }
+-
+- BUILD_BUG_ON(sizeof(mode_num) != 1);
+- BUILD_BUG_ON(sizeof(sb->s_uuid) != 16);
+- BUILD_BUG_ON(sizeof(hkdf_info) != 17);
+- hkdf_info[hkdf_infolen++] = mode_num;
+- if (include_fs_uuid) {
+- memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
+- sizeof(sb->s_uuid));
+- hkdf_infolen += sizeof(sb->s_uuid);
++ if (err) {
++ kfree(new_node);
++ return err;
+ }
+- fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context, hkdf_info,
+- hkdf_infolen, mode_key, mode->keysize);
+- err = fscrypt_prepare_key(prep_key, mode_key, ci);
+- memzero_explicit(mode_key, mode->keysize);
+- if (err)
+- goto out_unlock;
+-done_unlock:
++ list_add_tail_rcu(&new_node->link, &mk->mk_mode_keys);
+ ci->ci_enc_key = *prep_key;
+- err = 0;
+-out_unlock:
+- mutex_unlock(&fscrypt_mode_key_setup_mutex);
+- return err;
++ return 0;
+ }
+
+ /*
+@@ -311,8 +342,8 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_inode_info *ci,
+ {
+ int err;
+
+- err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_32_keys,
+- HKDF_CONTEXT_IV_INO_LBLK_32_KEY, true);
++ err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_IV_INO_LBLK_32_KEY,
++ true);
+ if (err)
+ return err;
+
+@@ -364,8 +395,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_inode_info *ci,
+ * encryption key. This ensures that the master key is
+ * consistently used only for HKDF, avoiding key reuse issues.
+ */
+- err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys,
+- HKDF_CONTEXT_DIRECT_KEY, false);
++ err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_DIRECT_KEY,
++ false);
+ } else if (ci->ci_policy.v2.flags &
+ FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
+ /*
+@@ -374,9 +405,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_inode_info *ci,
+ * the IVs. This format is optimized for use with inline
+ * encryption hardware compliant with the UFS standard.
+ */
+- err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys,
+- HKDF_CONTEXT_IV_INO_LBLK_64_KEY,
+- true);
++ err = setup_per_mode_enc_key(
++ ci, mk, HKDF_CONTEXT_IV_INO_LBLK_64_KEY, true);
+ } else if (ci->ci_policy.v2.flags &
+ FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
+ err = fscrypt_setup_iv_ino_lblk_32_key(ci, mk);
+--
+2.53.0
+
--- /dev/null
+From 8572b924e77f5d7c92c3270def5f810131ee2856 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jun 2026 15:19:21 -0700
+Subject: fscrypt: Replace mk_users keyring with simple list
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+[ Upstream commit 696c030e1e3438955aba443b308ee8b6faa3983e ]
+
+Change mk_users (the set of user claims to an fscrypt master key) from a
+'struct key' keyring to a simple linked list.
+
+It's still a collection of 'struct key' for quota tracking. It was
+originally thought to be natural that a collection of 'struct key'
+should be held in a 'struct key' keyring. In reality, it's just been
+causing problems, similar to how using 'struct key' for the filesystem
+keyring caused problems and was removed in commit d7e7b9af104c
+("fscrypt: stop using keyrings subsystem for fscrypt_master_key").
+
+Commit d3a7bd420076 ("fscrypt: clear keyring before calling key_put()")
+fixed mk_users cleanup to be synchronous. But that apparently wasn't
+enough: the keyring subsystem's redundant locking is still generating
+lockdep false positives due to the interaction with filesystem reclaim.
+
+With the simple list, the redundant locking and lockdep issue goes away.
+
+Of course, searching a linked list is linear-time whereas the
+'struct key' keyring used a fancy constant-time associative array. But
+that's fine here, since in practice there's just one entry in the list.
+In fact the new code is much faster in practice, since it's much smaller
+and doesn't have to convert the kuid_t into a string to search for it.
+
+Reported-by: syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f55b043dacf43776b50c
+Reported-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
+Closes: https://lore.kernel.org/keyrings/20260614150041.21172-1-med08elkadiri@gmail.com/
+Fixes: 23c688b54016 ("fscrypt: allow unprivileged users to add/remove keys for v2 policies")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618221921.87896-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/fscrypt_private.h | 32 ++++--
+ fs/crypto/keyring.c | 216 +++++++++++++++---------------------
+ 2 files changed, 113 insertions(+), 135 deletions(-)
+
+diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
+index 3bcde4b59efb0e..886ea39e924df0 100644
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -499,6 +499,19 @@ fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
+
+ /* keyring.c */
+
++/*
++ * fscrypt_master_key_user - a user's claim to a master key
++ */
++struct fscrypt_master_key_user {
++ struct list_head link;
++ kuid_t uid;
++ /*
++ * This 'struct key' contains no secret. It exists solely to charge the
++ * appropriate user's key quota.
++ */
++ struct key *quota_key;
++};
++
+ /*
+ * fscrypt_master_key_secret - secret key material of an in-use master key
+ */
+@@ -614,19 +627,18 @@ struct fscrypt_master_key {
+ struct fscrypt_key_specifier mk_spec;
+
+ /*
+- * Keyring which contains a key of type 'key_type_fscrypt_user' for each
+- * user who has added this key. Normally each key will be added by just
+- * one user, but it's possible that multiple users share a key, and in
+- * that case we need to keep track of those users so that one user can't
+- * remove the key before the others want it removed too.
++ * List of user claims to this key (struct fscrypt_master_key_user).
++ * Normally each key will be added by just one user, but it's possible
++ * that multiple users share a key, and in that case we need to keep
++ * track of those users so that one user can't remove the key before the
++ * others want it removed too.
+ *
+- * This is NULL for v1 policy keys; those can only be added by root.
++ * Used only for v2 policy keys. v1 policy keys can be added only by
++ * root, so user tracking doesn't apply to them.
+ *
+- * Locking: protected by ->mk_sem. (We don't just rely on the keyrings
+- * subsystem semaphore ->mk_users->sem, as we need support for atomic
+- * search+insert along with proper synchronization with other fields.)
++ * Locking: protected by ->mk_sem.
+ */
+- struct key *mk_users;
++ struct list_head mk_users;
+
+ /*
+ * List of inodes that were unlocked using this key. This allows the
+diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
+index 29bea5f3c98234..4ea4ee5cfc64b5 100644
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -65,22 +65,19 @@ static void fscrypt_free_master_key(struct rcu_head *head)
+ kfree_sensitive(mk);
+ }
+
++static void clear_mk_users(struct fscrypt_master_key *mk);
++
+ void fscrypt_put_master_key(struct fscrypt_master_key *mk)
+ {
+ if (!refcount_dec_and_test(&mk->mk_struct_refs))
+ return;
+ /*
+- * No structural references left, so free ->mk_users, and also free the
++ * No structural references left, so clear ->mk_users, and also free the
+ * fscrypt_master_key struct itself after an RCU grace period ensures
+ * that concurrent keyring lookups can no longer find it.
+ */
+ WARN_ON_ONCE(refcount_read(&mk->mk_active_refs) != 0);
+- if (mk->mk_users) {
+- /* Clear the keyring so the quota gets released right away. */
+- keyring_clear(mk->mk_users);
+- key_put(mk->mk_users);
+- mk->mk_users = NULL;
+- }
++ clear_mk_users(mk);
+ call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
+ }
+
+@@ -165,8 +162,8 @@ static void fscrypt_user_key_describe(const struct key *key, struct seq_file *m)
+ }
+
+ /*
+- * Type of key in ->mk_users. Each key of this type represents a particular
+- * user who has added a particular master key.
++ * Type of fscrypt_master_key_user::quota_key. This contains no secret; it
++ * exists solely to charge a user's key quota.
+ *
+ * Note that the name of this key type really should be something like
+ * ".fscrypt-user" instead of simply ".fscrypt". But the shorter name is chosen
+@@ -180,30 +177,9 @@ static struct key_type key_type_fscrypt_user = {
+ .describe = fscrypt_user_key_describe,
+ };
+
+-#define FSCRYPT_MK_USERS_DESCRIPTION_SIZE \
+- (CONST_STRLEN("fscrypt-") + 2 * FSCRYPT_KEY_IDENTIFIER_SIZE + \
+- CONST_STRLEN("-users") + 1)
+-
+ #define FSCRYPT_MK_USER_DESCRIPTION_SIZE \
+ (2 * FSCRYPT_KEY_IDENTIFIER_SIZE + CONST_STRLEN(".uid.") + 10 + 1)
+
+-static void format_mk_users_keyring_description(
+- char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE],
+- const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
+-{
+- sprintf(description, "fscrypt-%*phN-users",
+- FSCRYPT_KEY_IDENTIFIER_SIZE, mk_identifier);
+-}
+-
+-static void format_mk_user_description(
+- char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE],
+- const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
+-{
+-
+- sprintf(description, "%*phN.uid.%u", FSCRYPT_KEY_IDENTIFIER_SIZE,
+- mk_identifier, __kuid_val(current_fsuid()));
+-}
+-
+ /* Create ->s_master_keys if needed. Synchronized by fscrypt_add_key_mutex. */
+ static int allocate_filesystem_keyring(struct super_block *sb)
+ {
+@@ -338,91 +314,94 @@ fscrypt_find_master_key(struct super_block *sb,
+ return mk;
+ }
+
+-static int allocate_master_key_users_keyring(struct fscrypt_master_key *mk)
+-{
+- char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE];
+- struct key *keyring;
+-
+- format_mk_users_keyring_description(description,
+- mk->mk_spec.u.identifier);
+- keyring = keyring_alloc(description, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+- current_cred(), KEY_POS_SEARCH |
+- KEY_USR_SEARCH | KEY_USR_READ | KEY_USR_VIEW,
+- KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
+- if (IS_ERR(keyring))
+- return PTR_ERR(keyring);
+-
+- mk->mk_users = keyring;
+- return 0;
+-}
+-
+-/*
+- * Find the current user's "key" in the master key's ->mk_users.
+- * Returns ERR_PTR(-ENOKEY) if not found.
+- */
+-static struct key *find_master_key_user(struct fscrypt_master_key *mk)
++/* Find the current user's claim in ->mk_users. ->mk_sem must be held. */
++static struct fscrypt_master_key_user *
++find_master_key_user(struct fscrypt_master_key *mk)
+ {
+- char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
+- key_ref_t keyref;
++ struct fscrypt_master_key_user *mk_user;
++ kuid_t uid = current_fsuid();
+
+- format_mk_user_description(description, mk->mk_spec.u.identifier);
+-
+- /*
+- * We need to mark the keyring reference as "possessed" so that we
+- * acquire permission to search it, via the KEY_POS_SEARCH permission.
+- */
+- keyref = keyring_search(make_key_ref(mk->mk_users, true /*possessed*/),
+- &key_type_fscrypt_user, description, false);
+- if (IS_ERR(keyref)) {
+- if (PTR_ERR(keyref) == -EAGAIN || /* not found */
+- PTR_ERR(keyref) == -EKEYREVOKED) /* recently invalidated */
+- keyref = ERR_PTR(-ENOKEY);
+- return ERR_CAST(keyref);
++ list_for_each_entry(mk_user, &mk->mk_users, link) {
++ if (uid_eq(mk_user->uid, uid))
++ return mk_user;
+ }
+- return key_ref_to_ptr(keyref);
++ return NULL;
+ }
+
+ /*
+- * Give the current user a "key" in ->mk_users. This charges the user's quota
++ * Give the current user a claim in ->mk_users. This charges the user's quota
+ * and marks the master key as added by the current user, so that it cannot be
+ * removed by another user with the key. Either ->mk_sem must be held for
+ * write, or the master key must be still undergoing initialization.
+ */
+ static int add_master_key_user(struct fscrypt_master_key *mk)
+ {
++ kuid_t uid = current_fsuid();
+ char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
+- struct key *mk_user;
++ struct key *quota_key;
++ struct fscrypt_master_key_user *mk_user;
+ int err;
+
+- format_mk_user_description(description, mk->mk_spec.u.identifier);
+- mk_user = key_alloc(&key_type_fscrypt_user, description,
+- current_fsuid(), current_gid(), current_cred(),
+- KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
+- if (IS_ERR(mk_user))
+- return PTR_ERR(mk_user);
++ snprintf(description, sizeof(description), "%*phN.uid.%u",
++ FSCRYPT_KEY_IDENTIFIER_SIZE, mk->mk_spec.u.identifier,
++ __kuid_val(uid));
++ quota_key = key_alloc(&key_type_fscrypt_user, description, uid,
++ current_gid(), current_cred(),
++ KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
++ if (IS_ERR(quota_key))
++ return PTR_ERR(quota_key);
++
++ err = key_instantiate_and_link(quota_key, NULL, 0, NULL, NULL);
++ if (err) {
++ key_put(quota_key);
++ return err;
++ }
+
+- err = key_instantiate_and_link(mk_user, NULL, 0, mk->mk_users, NULL);
+- key_put(mk_user);
+- return err;
++ mk_user = kzalloc_obj(*mk_user);
++ if (!mk_user) {
++ key_put(quota_key);
++ return -ENOMEM;
++ }
++ mk_user->uid = uid;
++ mk_user->quota_key = quota_key;
++ list_add(&mk_user->link, &mk->mk_users);
++ return 0;
++}
++
++static void unlink_and_free_mk_user(struct fscrypt_master_key_user *mk_user)
++{
++ list_del(&mk_user->link);
++ key_put(mk_user->quota_key);
++ kfree(mk_user);
+ }
+
+ /*
+- * Remove the current user's "key" from ->mk_users.
++ * Remove the current user's claim from ->mk_users.
+ * ->mk_sem must be held for write.
+ *
+- * Returns 0 if removed, -ENOKEY if not found, or another -errno code.
++ * Returns 0 if removed or -ENOKEY if not found.
+ */
+ static int remove_master_key_user(struct fscrypt_master_key *mk)
+ {
+- struct key *mk_user;
+- int err;
++ struct fscrypt_master_key_user *mk_user;
+
+ mk_user = find_master_key_user(mk);
+- if (IS_ERR(mk_user))
+- return PTR_ERR(mk_user);
+- err = key_unlink(mk->mk_users, mk_user);
+- key_put(mk_user);
+- return err;
++ if (!mk_user)
++ return -ENOKEY;
++ unlink_and_free_mk_user(mk_user);
++ return 0;
++}
++
++/*
++ * Clear ->mk_users. Either ->mk_sem must be held for write, or 'mk' must have
++ * no structural references left.
++ */
++static void clear_mk_users(struct fscrypt_master_key *mk)
++{
++ struct fscrypt_master_key_user *mk_user, *tmp;
++
++ list_for_each_entry_safe(mk_user, tmp, &mk->mk_users, link)
++ unlink_and_free_mk_user(mk_user);
+ }
+
+ /*
+@@ -445,15 +424,14 @@ static int add_new_master_key(struct super_block *sb,
+ refcount_set(&mk->mk_struct_refs, 1);
+ mk->mk_spec = *mk_spec;
+
++ INIT_LIST_HEAD(&mk->mk_users);
++
+ INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
+ spin_lock_init(&mk->mk_decrypted_inodes_lock);
+
+ INIT_LIST_HEAD(&mk->mk_mode_keys);
+
+ if (mk_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
+- err = allocate_master_key_users_keyring(mk);
+- if (err)
+- goto out_put;
+ err = add_master_key_user(mk);
+ if (err)
+ goto out_put;
+@@ -482,19 +460,13 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
+ int err;
+
+ /*
+- * If the current user is already in ->mk_users, then there's nothing to
+- * do. Otherwise, we need to add the user to ->mk_users. (Neither is
+- * applicable for v1 policy keys, which have NULL ->mk_users.)
++ * For v2 policy keys (FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER): If the current
++ * user is already in ->mk_users, then there's nothing to do.
++ * Otherwise, add the user to ->mk_users.
+ */
+- if (mk->mk_users) {
+- struct key *mk_user = find_master_key_user(mk);
+-
+- if (mk_user != ERR_PTR(-ENOKEY)) {
+- if (IS_ERR(mk_user))
+- return PTR_ERR(mk_user);
+- key_put(mk_user);
++ if (mk->mk_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
++ if (find_master_key_user(mk) != NULL)
+ return 0;
+- }
+ err = add_master_key_user(mk);
+ if (err)
+ return err;
+@@ -893,7 +865,6 @@ int fscrypt_verify_key_added(struct super_block *sb,
+ {
+ struct fscrypt_key_specifier mk_spec;
+ struct fscrypt_master_key *mk;
+- struct key *mk_user;
+ int err;
+
+ mk_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
+@@ -905,13 +876,10 @@ int fscrypt_verify_key_added(struct super_block *sb,
+ goto out;
+ }
+ down_read(&mk->mk_sem);
+- mk_user = find_master_key_user(mk);
+- if (IS_ERR(mk_user)) {
+- err = PTR_ERR(mk_user);
+- } else {
+- key_put(mk_user);
++ if (find_master_key_user(mk) != NULL)
+ err = 0;
+- }
++ else
++ err = -ENOKEY;
+ up_read(&mk->mk_sem);
+ fscrypt_put_master_key(mk);
+ out:
+@@ -1103,16 +1071,18 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
+ down_write(&mk->mk_sem);
+
+ /* If relevant, remove current user's (or all users) claim to the key */
+- if (mk->mk_users && mk->mk_users->keys.nr_leaves_on_tree != 0) {
+- if (all_users)
+- err = keyring_clear(mk->mk_users);
+- else
++ if (!list_empty(&mk->mk_users)) {
++ if (all_users) {
++ clear_mk_users(mk);
++ err = 0;
++ } else {
+ err = remove_master_key_user(mk);
++ }
+ if (err) {
+ up_write(&mk->mk_sem);
+ goto out_put_key;
+ }
+- if (mk->mk_users->keys.nr_leaves_on_tree != 0) {
++ if (!list_empty(&mk->mk_users)) {
+ /*
+ * Other users have still added the key too. We removed
+ * the current user's claim to the key, but we still
+@@ -1198,6 +1168,8 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+ struct super_block *sb = file_inode(filp)->i_sb;
+ struct fscrypt_get_key_status_arg arg;
+ struct fscrypt_master_key *mk;
++ kuid_t uid;
++ const struct fscrypt_master_key_user *mk_user;
+ int err;
+
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+@@ -1230,19 +1202,13 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+ }
+
+ arg.status = FSCRYPT_KEY_STATUS_PRESENT;
+- if (mk->mk_users) {
+- struct key *mk_user;
+
+- arg.user_count = mk->mk_users->keys.nr_leaves_on_tree;
+- mk_user = find_master_key_user(mk);
+- if (!IS_ERR(mk_user)) {
++ uid = current_fsuid();
++ list_for_each_entry(mk_user, &mk->mk_users, link) {
++ arg.user_count++;
++ if (uid_eq(mk_user->uid, uid))
+ arg.status_flags |=
+ FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF;
+- key_put(mk_user);
+- } else if (mk_user != ERR_PTR(-ENOKEY)) {
+- err = PTR_ERR(mk_user);
+- goto out_release_key;
+- }
+ }
+ err = 0;
+ out_release_key:
+--
+2.53.0
+
--- /dev/null
+From 0459843e2962de0309deca8d97f06c75479adba5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Jun 2026 23:22:18 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 6b6fea8d33e044..449550b3bb286a 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4586,7 +4586,7 @@ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+ struct perf_event_context *ctx,
+ struct task_struct *task,
+- bool revoke);
++ unsigned long detach_flags);
+
+ /*
+ * Removes all events from the current task that have been marked
+@@ -4613,7 +4613,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
+
+ modified = true;
+
+- perf_event_exit_event(event, ctx, ctx->task, false);
++ perf_event_exit_event(event, ctx, ctx->task, DETACH_GROUP);
+ }
+
+ raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -12511,7 +12511,7 @@ static void __pmu_detach_event(struct pmu *pmu, struct perf_event *event,
+ /*
+ * De-schedule the event and mark it REVOKED.
+ */
+- perf_event_exit_event(event, ctx, ctx->task, true);
++ perf_event_exit_event(event, ctx, ctx->task, DETACH_REVOKE);
+
+ /*
+ * All _free_event() bits that rely on event->pmu:
+@@ -14095,12 +14095,13 @@ static void
+ perf_event_exit_event(struct perf_event *event,
+ struct perf_event_context *ctx,
+ struct task_struct *task,
+- bool revoke)
++ unsigned long detach_flags)
+ {
+ struct perf_event *parent_event = event->parent;
+- unsigned long detach_flags = DETACH_EXIT;
+ unsigned int attach_state;
+
++ detach_flags |= DETACH_EXIT;
++
+ if (parent_event) {
+ /*
+ * Do not destroy the 'original' grouping; because of the
+@@ -14123,8 +14124,8 @@ perf_event_exit_event(struct perf_event *event,
+ sync_child_event(event, task);
+ }
+
+- if (revoke)
+- detach_flags |= DETACH_GROUP | DETACH_REVOKE;
++ if (detach_flags & DETACH_REVOKE)
++ detach_flags |= DETACH_GROUP;
+
+ perf_remove_from_context(event, detach_flags);
+ /*
+@@ -14212,7 +14213,7 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
+ perf_event_task(task, ctx, 0);
+
+ list_for_each_entry_safe(child_event, next, &ctx->event_list, event_entry)
+- perf_event_exit_event(child_event, ctx, exit ? task : NULL, false);
++ perf_event_exit_event(child_event, ctx, exit ? task : NULL, 0);
+
+ mutex_unlock(&ctx->mutex);
+
+--
+2.53.0
+
--- /dev/null
+From 43f26212403918d90b27dfae878f9e0c7f8158e9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 19:59:43 +0200
+Subject: rust: kasan: KASAN+RUST requires clang
+
+From: Alice Ryhl <aliceryhl@google.com>
+
+[ Upstream commit 5b271543d0f08e9733d4732721e960e285f6448f ]
+
+Kernel KASAN involves passing various llvm/gcc specific arguments to
+the C and Rust compiler. Since these arguments differ between llvm and
+gcc, it's not safe to mix an llvm-based rustc with a gcc build when
+kasan is enabled.
+
+Signed-off-by: Alice Ryhl <aliceryhl@google.com>
+Reviewed-by: Gary Guo <gary@garyguo.net>
+Cc: stable@vger.kernel.org
+Fixes: e3117404b411 ("kbuild: rust: Enable KASAN support")
+Link: https://patch.msgid.link/20260408-kasan-rust-sw-tags-v3-1-e07964d14363@google.com
+Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ init/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/init/Kconfig b/init/Kconfig
+index cab3ad28ca49e7..0c25e78e10f47e 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -2096,6 +2096,7 @@ config RUST
+ depends on !CFI || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
+ select CFI_ICALL_NORMALIZE_INTEGERS if CFI
+ depends on !CALL_PADDING || RUSTC_VERSION >= 108100
++ depends on !KASAN || CC_IS_CLANG
+ depends on !KASAN_SW_TAGS
+ depends on !(MITIGATION_RETHUNK && KASAN) || RUSTC_VERSION >= 108300
+ help
+--
+2.53.0
+
rust-doctest-fix-incorrect-pattern-in-replacement.patch
rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
futex-requeue-revert-prevent-null-pointer-dereference-in-remove_waiter-on-self-deadlock.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+rust-kasan-kasan-rust-requires-clang.patch
+fscrypt-fix-key-setup-in-edge-case-with-multiple-dat.patch
+fscrypt-replace-mk_users-keyring-with-simple-list.patch
--- /dev/null
+From 2342107063f0bbeb4272bc4ad5f4a359b9b09068 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:36:00 +0000
+Subject: arm64: Fix early handling of FEAT_E2H0 not being implemented
+
+From: Marc Zyngier <maz@kernel.org>
+
+[ Upstream commit b3320142f3db9b3f2a23460abd3e22292e1530a5 ]
+
+Commit 3944382fa6f2 introduced checks for the FEAT_E2H0 not being
+implemented. However, the check is absolutely wrong and makes a
+point it testing a bit that is guaranteed to be zero.
+
+On top of that, the detection happens way too late, after the
+init_el2_state has done its job.
+
+This went undetected because the HW this was tested on has E2H being
+RAO/WI, and not RES1. However, the bug shows up when run as a nested
+guest, where HCR_EL2.E2H is not necessarily set to 1. As a result,
+booting the kernel in hVHE mode fails with timer accesses being
+cought in a trap loop (which was fun to debug).
+
+Fix the check for ID_AA64MMFR4_EL1.E2H0, and set the HCR_EL2.E2H bit
+early so that it can be checked by the rest of the init sequence.
+
+With this, hVHE works again in a NV environment that doesn't have
+FEAT_E2H0.
+
+Fixes: 3944382fa6f2 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+Link: https://lore.kernel.org/r/20240321115414.3169115-1-maz@kernel.org
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kernel/head.S | 29 ++++++++++++++++-------------
+ 1 file changed, 16 insertions(+), 13 deletions(-)
+
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index e32c8dd0b17a77..e0e710b36da378 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -576,6 +576,21 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+ isb
+ 0:
+ mov_q x0, HCR_HOST_NVHE_FLAGS
++
++ /*
++ * Compliant CPUs advertise their VHE-onlyness with
++ * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
++ * RES1 in that case. Publish the E2H bit early so that
++ * it can be picked up by the init_el2_state macro.
++ *
++ * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
++ * don't advertise it (they predate this relaxation).
++ */
++ mrs_s x1, SYS_ID_AA64MMFR4_EL1
++ tbz x1, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
++
++ orr x0, x0, #HCR_E2H
++1:
+ msr hcr_el2, x0
+ isb
+
+@@ -588,22 +603,10 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+
+ mov_q x1, INIT_SCTLR_EL1_MMU_OFF
+
+- /*
+- * Compliant CPUs advertise their VHE-onlyness with
+- * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
+- * RES1 in that case.
+- *
+- * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, but
+- * don't advertise it (they predate this relaxation).
+- */
+- mrs_s x0, SYS_ID_AA64MMFR4_EL1
+- ubfx x0, x0, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
+- tbnz x0, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
+-
+ mrs x0, hcr_el2
+ and x0, x0, #HCR_E2H
+ cbz x0, 2f
+-1:
++
+ /* Set a sane SCTLR_EL1, the VHE way */
+ pre_disable_mmu_workaround
+ msr_s SYS_SCTLR_EL12, x1
+--
+2.53.0
+
--- /dev/null
+From 820ad08c8680c42de17c2470541a1d68b6937375 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:36:03 +0000
+Subject: arm64: Revamp HCR_EL2.E2H RES1 detection
+
+From: Marc Zyngier <maz@kernel.org>
+
+[ Upstream commit ca88ecdce5f51874a7c151809bd2c936ee0d3805 ]
+
+We currently have two ways to identify CPUs that only implement FEAT_VHE
+and not FEAT_E2H0:
+
+- either they advertise it via ID_AA64MMFR4_EL1.E2H0,
+- or the HCR_EL2.E2H bit is RAO/WI
+
+However, there is a third category of "cpus" that fall between these
+two cases: on CPUs that do not implement FEAT_FGT, it is IMPDEF whether
+an access to ID_AA64MMFR4_EL1 can trap to EL2 when the register value
+is zero.
+
+A consequence of this is that on systems such as Neoverse V2, a NV
+guest cannot reliably detect that it is in a VHE-only configuration
+(E2H is writable, and ID_AA64MMFR0_EL1 is 0), despite the hypervisor's
+best effort to repaint the id register.
+
+Replace the RAO/WI test by a sequence that makes use of the VHE
+register remnapping between EL1 and EL2 to detect this situation,
+and work out whether we get the VHE behaviour even after having
+set HCR_EL2.E2H to 0.
+
+This solves the NV problem, and provides a more reliable acid test
+for CPUs that do not completely follow the letter of the architecture
+while providing a RES1 behaviour for HCR_EL2.E2H.
+
+Suggested-by: Mark Rutland <mark.rutland@arm.com>
+Acked-by: Mark Rutland <mark.rutland@arm.com>
+Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
+Tested-by: Jan Kotas <jank@cadence.com>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/15A85F2B-1A0C-4FA7-9FE4-EEC2203CC09E@global.cadence.com
+
+[ Backport: Resolved conflict in arch/arm64/include/asm/el2_setup.h
+ by replacing msr_hcr_el2 macro usages with raw msr hcr_el2 (since
+ the macro is missing in 6.6.y). ]
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/el2_setup.h | 38 +++++++++++++++++++++++++-----
+ 1 file changed, 32 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
+index 76b0d50d286d59..4c7467b382b608 100644
+--- a/arch/arm64/include/asm/el2_setup.h
++++ b/arch/arm64/include/asm/el2_setup.h
+@@ -24,22 +24,48 @@
+ * ID_AA64MMFR4_EL1.E2H0 < 0. On such CPUs HCR_EL2.E2H is RES1, but it
+ * can reset into an UNKNOWN state and might not read as 1 until it has
+ * been initialized explicitly.
+- *
+- * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
+- * don't advertise it (they predate this relaxation).
+- *
+ * Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H
+ * indicating whether the CPU is running in E2H mode.
+ */
+ mrs_s x1, SYS_ID_AA64MMFR4_EL1
+ sbfx x1, x1, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
+ cmp x1, #0
+- b.ge .LnVHE_\@
++ b.lt .LnE2H0_\@
+
++ /*
++ * Unfortunately, HCR_EL2.E2H can be RES1 even if not advertised
++ * as such via ID_AA64MMFR4_EL1.E2H0:
++ *
++ * - Fruity CPUs predate the !FEAT_E2H0 relaxation, and seem to
++ * have HCR_EL2.E2H implemented as RAO/WI.
++ *
++ * - On CPUs that lack FEAT_FGT, a hypervisor can't trap guest
++ * reads of ID_AA64MMFR4_EL1 to advertise !FEAT_E2H0. NV
++ * guests on these hosts can write to HCR_EL2.E2H without
++ * trapping to the hypervisor, but these writes have no
++ * functional effect.
++ *
++ * Handle both cases by checking for an essential VHE property
++ * (system register remapping) to decide whether we're
++ * effectively VHE-only or not.
++ */
++ msr hcr_el2, x0 // Setup HCR_EL2 as nVHE
++ isb
++ mov x1, #1 // Write something to FAR_EL1
++ msr far_el1, x1
++ isb
++ mov x1, #2 // Try to overwrite it via FAR_EL2
++ msr far_el2, x1
++ isb
++ mrs x1, far_el1 // If we see the latest write in FAR_EL1,
++ cmp x1, #2 // we can safely assume we are VHE only.
++ b.ne .LnVHE_\@ // Otherwise, we know that nVHE works.
++
++.LnE2H0_\@:
+ orr x0, x0, #HCR_E2H
+-.LnVHE_\@:
+ msr hcr_el2, x0
+ isb
++.LnVHE_\@:
+ .endm
+
+ .macro __init_el2_sctlr
+--
+2.53.0
+
--- /dev/null
+From eae585cefd26bee9a9c7bf93127f942fe74fecf2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:35:58 +0000
+Subject: arm64: sysreg: Add layout for ID_AA64MMFR4_EL1
+
+From: Marc Zyngier <maz@kernel.org>
+
+[ Upstream commit cfc680bb04c54e61faa51a34d8383a0aa25b583f ]
+
+ARMv9.5 has infroduced ID_AA64MMFR4_EL1 with a bunch of new features.
+Add the corresponding layout.
+
+This is extracted from the public ARM SysReg_xml_A_profile-2023-09
+delivery, timestamped d55f5af8e09052abe92a02adf820deea2eaed717.
+
+Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Reviewed-by: Miguel Luis <miguel.luis@oracle.com>
+Link: https://lore.kernel.org/r/20240122181344.258974-5-maz@kernel.org
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/tools/sysreg | 37 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
+index 76ce150e7347e5..f7180d391f829f 100644
+--- a/arch/arm64/tools/sysreg
++++ b/arch/arm64/tools/sysreg
+@@ -1669,6 +1669,43 @@ UnsignedEnum 3:0 TCRX
+ EndEnum
+ EndSysreg
+
++Sysreg ID_AA64MMFR4_EL1 3 0 0 7 4
++Res0 63:40
++UnsignedEnum 39:36 E3DSE
++ 0b0000 NI
++ 0b0001 IMP
++EndEnum
++Res0 35:28
++SignedEnum 27:24 E2H0
++ 0b0000 IMP
++ 0b1110 NI_NV1
++ 0b1111 NI
++EndEnum
++UnsignedEnum 23:20 NV_frac
++ 0b0000 NV_NV2
++ 0b0001 NV2_ONLY
++EndEnum
++UnsignedEnum 19:16 FGWTE3
++ 0b0000 NI
++ 0b0001 IMP
++EndEnum
++UnsignedEnum 15:12 HACDBS
++ 0b0000 NI
++ 0b0001 IMP
++EndEnum
++UnsignedEnum 11:8 ASID2
++ 0b0000 NI
++ 0b0001 IMP
++EndEnum
++SignedEnum 7:4 EIESB
++ 0b0000 NI
++ 0b0001 ToEL3
++ 0b0010 ToELx
++ 0b1111 ANY
++EndEnum
++Res0 3:0
++EndSysreg
++
+ Sysreg SCTLR_EL1 3 0 1 0 0
+ Field 63 TIDCP
+ Field 62 SPINTMASK
+--
+2.53.0
+
--- /dev/null
+From 4d28c6b03345d42076b2cd50522ac3ff5de150e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 Aug 2025 10:51:42 +0100
+Subject: arm64: sysreg: Correct sign definitions for EIESB and DoubleLock
+
+From: Fuad Tabba <tabba@google.com>
+
+[ Upstream commit f4d4ebc84995178273740f3e601e97fdefc561d2 ]
+
+The `ID_AA64MMFR4_EL1.EIESB` field, is an unsigned enumeration, but was
+incorrectly defined as a `SignedEnum` when introduced in commit
+cfc680bb04c5 ("arm64: sysreg: Add layout for ID_AA64MMFR4_EL1"). This is
+corrected to `UnsignedEnum`.
+
+Conversely, the `ID_AA64DFR0_EL1.DoubleLock` field, is a signed
+enumeration, but was incorrectly defined as an `UnsignedEnum`. This is
+corrected to `SignedEnum`, which wasn't correctly set when annotated as
+such in commit ad16d4cf0b4f ("arm64/sysreg: Initial unsigned annotations
+for ID registers").
+
+Signed-off-by: Fuad Tabba <tabba@google.com>
+Acked-by: Mark Rutland <mark.rutland@arm.com>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/tools/sysreg | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
+index f7180d391f829f..43089787196bad 100644
+--- a/arch/arm64/tools/sysreg
++++ b/arch/arm64/tools/sysreg
+@@ -1130,7 +1130,7 @@ UnsignedEnum 43:40 TraceFilt
+ 0b0000 NI
+ 0b0001 IMP
+ EndEnum
+-UnsignedEnum 39:36 DoubleLock
++SignedEnum 39:36 DoubleLock
+ 0b0000 IMP
+ 0b1111 NI
+ EndEnum
+@@ -1697,7 +1697,7 @@ UnsignedEnum 11:8 ASID2
+ 0b0000 NI
+ 0b0001 IMP
+ EndEnum
+-SignedEnum 7:4 EIESB
++UnsignedEnum 7:4 EIESB
+ 0b0000 NI
+ 0b0001 ToEL3
+ 0b0010 ToELx
+--
+2.53.0
+
--- /dev/null
+From f1de5423d12f895e07cc6891613229f018e70a6c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:35:59 +0000
+Subject: arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is
+ negative
+
+From: Marc Zyngier <maz@kernel.org>
+
+[ Upstream commit 3944382fa6f22b54fd399632b1af92c28123979b ]
+
+For CPUs that have ID_AA64MMFR4_EL1.E2H0 as negative, it is important
+to avoid the boot path that sets HCR_EL2.E2H=0. Fortunately, we
+already have this path to cope with fruity CPUs.
+
+Tweak init_el2 to look at ID_AA64MMFR4_EL1.E2H0 first.
+
+Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Link: https://lore.kernel.org/r/20240122181344.258974-8-maz@kernel.org
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kernel/head.S | 23 +++++++++++++++--------
+ 1 file changed, 15 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index 6517bf2644a08b..e32c8dd0b17a77 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -589,25 +589,32 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+ mov_q x1, INIT_SCTLR_EL1_MMU_OFF
+
+ /*
+- * Fruity CPUs seem to have HCR_EL2.E2H set to RES1,
+- * making it impossible to start in nVHE mode. Is that
+- * compliant with the architecture? Absolutely not!
++ * Compliant CPUs advertise their VHE-onlyness with
++ * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
++ * RES1 in that case.
++ *
++ * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, but
++ * don't advertise it (they predate this relaxation).
+ */
++ mrs_s x0, SYS_ID_AA64MMFR4_EL1
++ ubfx x0, x0, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
++ tbnz x0, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
++
+ mrs x0, hcr_el2
+ and x0, x0, #HCR_E2H
+- cbz x0, 1f
+-
++ cbz x0, 2f
++1:
+ /* Set a sane SCTLR_EL1, the VHE way */
+ pre_disable_mmu_workaround
+ msr_s SYS_SCTLR_EL12, x1
+ mov x2, #BOOT_CPU_FLAG_E2H
+- b 2f
++ b 3f
+
+-1:
++2:
+ pre_disable_mmu_workaround
+ msr sctlr_el1, x1
+ mov x2, xzr
+-2:
++3:
+ __init_el2_nvhe_prepare_eret
+
+ mov w0, #BOOT_CPU_MODE_EL2
+--
+2.53.0
+
--- /dev/null
+From 8b29c044e1ae8a35b483b0978e6fbb4c0976ea30 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:55 +0200
+Subject: crypto: talitos - fix SEC1 32k ahash request limitation
+
+From: Paul Louvel <paul.louvel@bootlin.com>
+
+commit 655ef638a2bc3cd0a9eff99a02f83cab94a3a917 upstream.
+
+Since commit c662b043cdca ("crypto: af_alg/hash: Support
+MSG_SPLICE_PAGES"), the crypto core may pass large scatterlists spanning
+multiple pages to drivers supporting ahash operations. As a result, a
+driver can now receive large ahash requests.
+
+The SEC1 engine has a limitation where a single descriptor cannot
+process more than 32k of data. The current implementation attempts to
+handle the entire request within a single descriptor, which leads to
+failures raised by the driver:
+
+ "length exceeds h/w max limit"
+
+Address this limitation by splitting large ahash requests into multiple
+descriptors, each respecting the 32k hardware limit. This allows
+processing arbitrarily large requests.
+
+Cc: stable@vger.kernel.org
+Fixes: c662b043cdca ("crypto: af_alg/hash: Support MSG_SPLICE_PAGES")
+Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 216 ++++++++++++++++++++++++++-------------
+ 1 file changed, 147 insertions(+), 69 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index a941ec08817eb4..ea6ae72c71ad62 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -12,6 +12,7 @@
+ * All rights reserved.
+ */
+
++#include <linux/workqueue.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mod_devicetable.h>
+@@ -870,10 +871,18 @@ struct talitos_ahash_req_ctx {
+ unsigned int swinit;
+ unsigned int first;
+ unsigned int last;
++ unsigned int last_request;
+ unsigned int to_hash_later;
+ unsigned int nbuf;
+ struct scatterlist bufsl[2];
+ struct scatterlist *psrc;
++
++ struct scatterlist request_bufsl[2];
++ struct ahash_request *areq;
++ struct scatterlist *request_sl;
++ unsigned int remaining_ahash_request_bytes;
++ unsigned int current_ahash_request_bytes;
++ struct work_struct sec1_ahash_process_remaining;
+ };
+
+ struct talitos_export_state {
+@@ -1759,7 +1768,20 @@ static void ahash_done(struct device *dev,
+
+ kfree(edesc);
+
+- ahash_request_complete(areq, err);
++ if (err) {
++ ahash_request_complete(areq, err);
++ return;
++ }
++
++ req_ctx->remaining_ahash_request_bytes -=
++ req_ctx->current_ahash_request_bytes;
++
++ if (!req_ctx->remaining_ahash_request_bytes) {
++ ahash_request_complete(areq, 0);
++ return;
++ }
++
++ schedule_work(&req_ctx->sec1_ahash_process_remaining);
+ }
+
+ /*
+@@ -1925,60 +1947,7 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
+ nbytes, 0, 0, 0, areq->base.flags, false);
+ }
+
+-static int ahash_init(struct ahash_request *areq)
+-{
+- struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+- struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+- struct device *dev = ctx->dev;
+- struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+- unsigned int size;
+- dma_addr_t dma;
+-
+- /* Initialize the context */
+- req_ctx->buf_idx = 0;
+- req_ctx->nbuf = 0;
+- req_ctx->first = 1; /* first indicates h/w must init its context */
+- req_ctx->swinit = 0; /* assume h/w init of context */
+- size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+- ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+- : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+- req_ctx->hw_context_size = size;
+-
+- dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+- DMA_TO_DEVICE);
+- dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
+-
+- return 0;
+-}
+-
+-/*
+- * on h/w without explicit sha224 support, we initialize h/w context
+- * manually with sha224 constants, and tell it to run sha256.
+- */
+-static int ahash_init_sha224_swinit(struct ahash_request *areq)
+-{
+- struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-
+- req_ctx->hw_context[0] = SHA224_H0;
+- req_ctx->hw_context[1] = SHA224_H1;
+- req_ctx->hw_context[2] = SHA224_H2;
+- req_ctx->hw_context[3] = SHA224_H3;
+- req_ctx->hw_context[4] = SHA224_H4;
+- req_ctx->hw_context[5] = SHA224_H5;
+- req_ctx->hw_context[6] = SHA224_H6;
+- req_ctx->hw_context[7] = SHA224_H7;
+-
+- /* init 64-bit count */
+- req_ctx->hw_context[8] = 0;
+- req_ctx->hw_context[9] = 0;
+-
+- ahash_init(areq);
+- req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
+-
+- return 0;
+-}
+-
+-static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
++static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes)
+ {
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+@@ -1997,12 +1966,12 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+
+ if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+ /* Buffer up to one whole block */
+- nents = sg_nents_for_len(areq->src, nbytes);
++ nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+ if (nents < 0) {
+ dev_err(dev, "Invalid number of src SG.\n");
+ return nents;
+ }
+- sg_copy_to_buffer(areq->src, nents,
++ sg_copy_to_buffer(req_ctx->request_sl, nents,
+ ctx_buf + req_ctx->nbuf, nbytes);
+ req_ctx->nbuf += nbytes;
+ return 0;
+@@ -2029,7 +1998,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+ sg_init_table(req_ctx->bufsl, nsg);
+ sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf);
+ if (nsg > 1)
+- sg_chain(req_ctx->bufsl, 2, areq->src);
++ sg_chain(req_ctx->bufsl, 2, req_ctx->request_sl);
+ req_ctx->psrc = req_ctx->bufsl;
+ } else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) {
+ int offset;
+@@ -2038,26 +2007,26 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+ offset = blocksize - req_ctx->nbuf;
+ else
+ offset = nbytes_to_hash - req_ctx->nbuf;
+- nents = sg_nents_for_len(areq->src, offset);
++ nents = sg_nents_for_len(req_ctx->request_sl, offset);
+ if (nents < 0) {
+ dev_err(dev, "Invalid number of src SG.\n");
+ return nents;
+ }
+- sg_copy_to_buffer(areq->src, nents,
++ sg_copy_to_buffer(req_ctx->request_sl, nents,
+ ctx_buf + req_ctx->nbuf, offset);
+ req_ctx->nbuf += offset;
+- req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, areq->src,
++ req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, req_ctx->request_sl,
+ offset);
+ } else
+- req_ctx->psrc = areq->src;
++ req_ctx->psrc = req_ctx->request_sl;
+
+ if (to_hash_later) {
+- nents = sg_nents_for_len(areq->src, nbytes);
++ nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+ if (nents < 0) {
+ dev_err(dev, "Invalid number of src SG.\n");
+ return nents;
+ }
+- sg_pcopy_to_buffer(areq->src, nents,
++ sg_pcopy_to_buffer(req_ctx->request_sl, nents,
+ req_ctx->buf[(req_ctx->buf_idx + 1) & 1],
+ to_hash_later,
+ nbytes - to_hash_later);
+@@ -2065,7 +2034,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+ req_ctx->to_hash_later = to_hash_later;
+
+ /* Allocate extended descriptor */
+- edesc = ahash_edesc_alloc(areq, nbytes_to_hash);
++ edesc = ahash_edesc_alloc(req_ctx->areq, nbytes_to_hash);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+@@ -2087,14 +2056,123 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+ if (ctx->keylen && (req_ctx->first || req_ctx->last))
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+
+- return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, ahash_done);
++ return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
+ }
+
+-static int ahash_update(struct ahash_request *areq)
++static void sec1_ahash_process_remaining(struct work_struct *work)
++{
++ struct talitos_ahash_req_ctx *req_ctx =
++ container_of(work, struct talitos_ahash_req_ctx,
++ sec1_ahash_process_remaining);
++ int err = 0;
++
++ req_ctx->request_sl = scatterwalk_ffwd(req_ctx->request_bufsl,
++ req_ctx->request_sl, TALITOS1_MAX_DATA_LEN);
++
++ if (req_ctx->remaining_ahash_request_bytes > TALITOS1_MAX_DATA_LEN)
++ req_ctx->current_ahash_request_bytes = TALITOS1_MAX_DATA_LEN;
++ else {
++ req_ctx->current_ahash_request_bytes =
++ req_ctx->remaining_ahash_request_bytes;
++
++ if (req_ctx->last_request)
++ req_ctx->last = 1;
++ }
++
++ err = ahash_process_req_one(req_ctx->areq,
++ req_ctx->current_ahash_request_bytes);
++
++ if (err != -EINPROGRESS)
++ ahash_request_complete(req_ctx->areq, err);
++}
++
++static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
++{
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
++ struct device *dev = ctx->dev;
++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++ struct talitos_private *priv = dev_get_drvdata(dev);
++ bool is_sec1 = has_ftr_sec1(priv);
++
++ req_ctx->areq = areq;
++ req_ctx->request_sl = areq->src;
++ req_ctx->remaining_ahash_request_bytes = nbytes;
++
++ if (is_sec1) {
++ if (nbytes > TALITOS1_MAX_DATA_LEN)
++ nbytes = TALITOS1_MAX_DATA_LEN;
++ else if (req_ctx->last_request)
++ req_ctx->last = 1;
++ }
++
++ req_ctx->current_ahash_request_bytes = nbytes;
++
++ return ahash_process_req_one(req_ctx->areq,
++ req_ctx->current_ahash_request_bytes);
++}
++
++static int ahash_init(struct ahash_request *areq)
+ {
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
++ struct device *dev = ctx->dev;
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++ unsigned int size;
++ dma_addr_t dma;
+
++ /* Initialize the context */
++ req_ctx->buf_idx = 0;
++ req_ctx->nbuf = 0;
++ req_ctx->first = 1; /* first indicates h/w must init its context */
++ req_ctx->swinit = 0; /* assume h/w init of context */
++ size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
++ ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
++ : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
++ req_ctx->hw_context_size = size;
++ req_ctx->last_request = 0;
+ req_ctx->last = 0;
++ INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
++
++ dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
++ DMA_TO_DEVICE);
++ dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
++
++ return 0;
++}
++
++/*
++ * on h/w without explicit sha224 support, we initialize h/w context
++ * manually with sha224 constants, and tell it to run sha256.
++ */
++static int ahash_init_sha224_swinit(struct ahash_request *areq)
++{
++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++
++ req_ctx->hw_context[0] = SHA224_H0;
++ req_ctx->hw_context[1] = SHA224_H1;
++ req_ctx->hw_context[2] = SHA224_H2;
++ req_ctx->hw_context[3] = SHA224_H3;
++ req_ctx->hw_context[4] = SHA224_H4;
++ req_ctx->hw_context[5] = SHA224_H5;
++ req_ctx->hw_context[6] = SHA224_H6;
++ req_ctx->hw_context[7] = SHA224_H7;
++
++ /* init 64-bit count */
++ req_ctx->hw_context[8] = 0;
++ req_ctx->hw_context[9] = 0;
++
++ ahash_init(areq);
++ req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
++
++ return 0;
++}
++
++static int ahash_update(struct ahash_request *areq)
++{
++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++
++ req_ctx->last_request = 0;
+
+ return ahash_process_req(areq, areq->nbytes);
+ }
+@@ -2103,7 +2181,7 @@ static int ahash_final(struct ahash_request *areq)
+ {
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+- req_ctx->last = 1;
++ req_ctx->last_request = 1;
+
+ return ahash_process_req(areq, 0);
+ }
+@@ -2112,7 +2190,7 @@ static int ahash_finup(struct ahash_request *areq)
+ {
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+- req_ctx->last = 1;
++ req_ctx->last_request = 1;
+
+ return ahash_process_req(areq, areq->nbytes);
+ }
+--
+2.53.0
+
--- /dev/null
+From 7ff3d5875ff4b2fe27b3e8dcb5b61b923684457b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:56 +0200
+Subject: crypto: talitos - rename first/last to first_desc/last_desc
+
+From: Paul Louvel <paul.louvel@bootlin.com>
+
+commit a1b80018b8cec27fc06a8b04a7f8b5f6cfe86eae upstream.
+
+Previous commit introduces a new last_request variable in the context
+structure.
+
+Renaming the first/last existing member variable in the context
+structure to improve readability.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 46 ++++++++++++++++++++--------------------
+ 1 file changed, 23 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index ea6ae72c71ad62..fb1adc2956b899 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -869,8 +869,8 @@ struct talitos_ahash_req_ctx {
+ u8 buf[2][HASH_MAX_BLOCK_SIZE];
+ int buf_idx;
+ unsigned int swinit;
+- unsigned int first;
+- unsigned int last;
++ unsigned int first_desc;
++ unsigned int last_desc;
+ unsigned int last_request;
+ unsigned int to_hash_later;
+ unsigned int nbuf;
+@@ -889,8 +889,8 @@ struct talitos_export_state {
+ u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
+ u8 buf[HASH_MAX_BLOCK_SIZE];
+ unsigned int swinit;
+- unsigned int first;
+- unsigned int last;
++ unsigned int first_desc;
++ unsigned int last_desc;
+ unsigned int to_hash_later;
+ unsigned int nbuf;
+ };
+@@ -1722,7 +1722,7 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
+ if (desc->next_desc &&
+ desc->ptr[5].ptr != desc2->ptr[5].ptr)
+ unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE);
+- if (req_ctx->last)
++ if (req_ctx->last_desc)
+ memcpy(areq->result, req_ctx->hw_context,
+ crypto_ahash_digestsize(tfm));
+
+@@ -1759,7 +1759,7 @@ static void ahash_done(struct device *dev,
+ container_of(desc, struct talitos_edesc, desc);
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+- if (!req_ctx->last && req_ctx->to_hash_later) {
++ if (!req_ctx->last_desc && req_ctx->to_hash_later) {
+ /* Position any partial block for next update/final/finup */
+ req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
+ req_ctx->nbuf = req_ctx->to_hash_later;
+@@ -1825,7 +1825,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+ /* first DWORD empty */
+
+ /* hash context in */
+- if (!req_ctx->first || req_ctx->swinit) {
++ if (!req_ctx->first_desc || req_ctx->swinit) {
+ map_single_talitos_ptr_nosync(dev, &desc->ptr[1],
+ req_ctx->hw_context_size,
+ req_ctx->hw_context,
+@@ -1833,7 +1833,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+ req_ctx->swinit = 0;
+ }
+ /* Indicate next op is not the first. */
+- req_ctx->first = 0;
++ req_ctx->first_desc = 0;
+
+ /* HMAC key */
+ if (ctx->keylen)
+@@ -1866,7 +1866,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+ /* fifth DWORD empty */
+
+ /* hash/HMAC out -or- hash context out */
+- if (req_ctx->last)
++ if (req_ctx->last_desc)
+ map_single_talitos_ptr(dev, &desc->ptr[5],
+ crypto_ahash_digestsize(tfm),
+ req_ctx->hw_context, DMA_FROM_DEVICE);
+@@ -1908,7 +1908,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+ if (sg_count > 1)
+ sync_needed = true;
+ copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
+- if (req_ctx->last)
++ if (req_ctx->last_desc)
+ map_single_talitos_ptr_nosync(dev, &desc->ptr[5],
+ req_ctx->hw_context_size,
+ req_ctx->hw_context,
+@@ -1964,7 +1964,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ bool is_sec1 = has_ftr_sec1(priv);
+ u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
+
+- if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
++ if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) {
+ /* Buffer up to one whole block */
+ nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+ if (nents < 0) {
+@@ -1981,7 +1981,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ nbytes_to_hash = nbytes + req_ctx->nbuf;
+ to_hash_later = nbytes_to_hash & (blocksize - 1);
+
+- if (req_ctx->last)
++ if (req_ctx->last_desc)
+ to_hash_later = 0;
+ else if (to_hash_later)
+ /* There is a partial block. Hash the full block(s) now */
+@@ -2041,19 +2041,19 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ edesc->desc.hdr = ctx->desc_hdr_template;
+
+ /* On last one, request SEC to pad; otherwise continue */
+- if (req_ctx->last)
++ if (req_ctx->last_desc)
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD;
+ else
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT;
+
+ /* request SEC to INIT hash. */
+- if (req_ctx->first && !req_ctx->swinit)
++ if (req_ctx->first_desc && !req_ctx->swinit)
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
+
+ /* When the tfm context has a keylen, it's an HMAC.
+ * A first or last (ie. not middle) descriptor must request HMAC.
+ */
+- if (ctx->keylen && (req_ctx->first || req_ctx->last))
++ if (ctx->keylen && (req_ctx->first_desc || req_ctx->last_desc))
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+
+ return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
+@@ -2076,7 +2076,7 @@ static void sec1_ahash_process_remaining(struct work_struct *work)
+ req_ctx->remaining_ahash_request_bytes;
+
+ if (req_ctx->last_request)
+- req_ctx->last = 1;
++ req_ctx->last_desc = 1;
+ }
+
+ err = ahash_process_req_one(req_ctx->areq,
+@@ -2103,7 +2103,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+ if (nbytes > TALITOS1_MAX_DATA_LEN)
+ nbytes = TALITOS1_MAX_DATA_LEN;
+ else if (req_ctx->last_request)
+- req_ctx->last = 1;
++ req_ctx->last_desc = 1;
+ }
+
+ req_ctx->current_ahash_request_bytes = nbytes;
+@@ -2124,14 +2124,14 @@ static int ahash_init(struct ahash_request *areq)
+ /* Initialize the context */
+ req_ctx->buf_idx = 0;
+ req_ctx->nbuf = 0;
+- req_ctx->first = 1; /* first indicates h/w must init its context */
++ req_ctx->first_desc = 1; /* first_desc indicates h/w must init its context */
+ req_ctx->swinit = 0; /* assume h/w init of context */
+ size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+ ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+ : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+ req_ctx->hw_context_size = size;
+ req_ctx->last_request = 0;
+- req_ctx->last = 0;
++ req_ctx->last_desc = 0;
+ INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
+
+ dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+@@ -2224,8 +2224,8 @@ static int ahash_export(struct ahash_request *areq, void *out)
+ req_ctx->hw_context_size);
+ memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
+ export->swinit = req_ctx->swinit;
+- export->first = req_ctx->first;
+- export->last = req_ctx->last;
++ export->first_desc = req_ctx->first_desc;
++ export->last_desc = req_ctx->last_desc;
+ export->to_hash_later = req_ctx->to_hash_later;
+ export->nbuf = req_ctx->nbuf;
+
+@@ -2250,8 +2250,8 @@ static int ahash_import(struct ahash_request *areq, const void *in)
+ memcpy(req_ctx->hw_context, export->hw_context, size);
+ memcpy(req_ctx->buf[0], export->buf, export->nbuf);
+ req_ctx->swinit = export->swinit;
+- req_ctx->first = export->first;
+- req_ctx->last = export->last;
++ req_ctx->first_desc = export->first_desc;
++ req_ctx->last_desc = export->last_desc;
+ req_ctx->to_hash_later = export->to_hash_later;
+ req_ctx->nbuf = export->nbuf;
+
+--
+2.53.0
+
--- /dev/null
+From ede435a73fd99dc97049244c271c9ea42bb1cad3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:54 +0200
+Subject: crypto: talitos - stop using crypto_ahash::init
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit 9826d1d6ed5f86cb3d61610b3b1fe31e96a40418 upstream.
+
+The function pointer crypto_ahash::init is an internal implementation
+detail of the ahash API that exists to help it support both ahash and
+shash algorithms. With an upcoming refactoring of how the ahash API
+supports shash algorithms, this field will be removed.
+
+Some drivers are invoking crypto_ahash::init to call into their own
+code, which is unnecessary and inefficient. The talitos driver is one
+of those drivers. Make it just call its own code directly.
+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index 4ca4fbd227bce1..a941ec08817eb4 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -2119,13 +2119,14 @@ static int ahash_finup(struct ahash_request *areq)
+
+ static int ahash_digest(struct ahash_request *areq)
+ {
+- struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+- struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
+-
+- ahash->init(areq);
+- req_ctx->last = 1;
++ ahash_init(areq);
++ return ahash_finup(areq);
++}
+
+- return ahash_process_req(areq, areq->nbytes);
++static int ahash_digest_sha224_swinit(struct ahash_request *areq)
++{
++ ahash_init_sha224_swinit(areq);
++ return ahash_finup(areq);
+ }
+
+ static int ahash_export(struct ahash_request *areq, void *out)
+@@ -3242,6 +3243,8 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
+ (!strcmp(alg->cra_name, "sha224") ||
+ !strcmp(alg->cra_name, "hmac(sha224)"))) {
+ t_alg->algt.alg.hash.init = ahash_init_sha224_swinit;
++ t_alg->algt.alg.hash.digest =
++ ahash_digest_sha224_swinit;
+ t_alg->algt.desc_hdr_template =
+ DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+ DESC_HDR_SEL0_MDEUA |
+--
+2.53.0
+
--- /dev/null
+From b0b66e90f910d8e1a9ace4a3c328b618d67f08ab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:36:01 +0000
+Subject: KVM: arm64: Initialize HCR_EL2.E2H early
+
+From: Mark Rutland <mark.rutland@arm.com>
+
+[ Upstream commit 7a68b55ff39b0a1638acb1694c185d49f6077a0d ]
+
+On CPUs without FEAT_E2H0, HCR_EL2.E2H is RES1, but may reset to an
+UNKNOWN value out of reset and consequently may not read as 1 unless it
+has been explicitly initialized.
+
+We handled this for the head.S boot code in commits:
+
+ 3944382fa6f22b54 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
+ b3320142f3db9b3f ("arm64: Fix early handling of FEAT_E2H0 not being implemented")
+
+Unfortunately, we forgot to apply a similar fix to the KVM PSCI entry
+points used when relaying CPU_ON, CPU_SUSPEND, and SYSTEM SUSPEND. When
+KVM is entered via these entry points, the value of HCR_EL2.E2H may be
+consumed before it has been initialized (e.g. by the 'init_el2_state'
+macro).
+
+Initialize HCR_EL2.E2H early in these paths such that it can be consumed
+reliably. The existing code in head.S is factored out into a new
+'init_el2_hcr' macro, and this is used in the __kvm_hyp_init_cpu()
+function common to all the relevant PSCI entry points.
+
+For clarity, I've tweaked the assembly used to check whether
+ID_AA64MMFR4_EL1.E2H0 is negative. The bitfield is extracted as a signed
+value, and this is checked with a signed-greater-or-equal (GE) comparison.
+
+As the hyp code will reconfigure HCR_EL2 later in ___kvm_hyp_init(), all
+bits other than E2H are initialized to zero in __kvm_hyp_init_cpu().
+
+Fixes: 3944382fa6f22b54 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
+Fixes: b3320142f3db9b3f ("arm64: Fix early handling of FEAT_E2H0 not being implemented")
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Cc: Ahmed Genidi <ahmed.genidi@arm.com>
+Cc: Ben Horgan <ben.horgan@arm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Leo Yan <leo.yan@arm.com>
+Cc: Marc Zyngier <maz@kernel.org>
+Cc: Oliver Upton <oliver.upton@linux.dev>
+Cc: Will Deacon <will@kernel.org>
+Link: https://lore.kernel.org/r/20250227180526.1204723-2-mark.rutland@arm.com
+[maz: fixed LT->GE thinko]
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+[ Backport: Resolved trivial conflict in arch/arm64/kvm/hyp/nvhe/hyp-init.S
+ caused by __kvm_init_el2_state not existing in 6.6.y (EL2 state is initialized
+ inline via init_el2_state / finalise_el2_state); placed init_el2_hcr 0
+ directly before the inline sequence. ]
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/el2_setup.h | 26 ++++++++++++++++++++++++++
+ arch/arm64/kernel/head.S | 19 +------------------
+ arch/arm64/kvm/hyp/nvhe/hyp-init.S | 2 ++
+ 3 files changed, 29 insertions(+), 18 deletions(-)
+
+diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
+index b7afaa026842b7..3498dc5d02c188 100644
+--- a/arch/arm64/include/asm/el2_setup.h
++++ b/arch/arm64/include/asm/el2_setup.h
+@@ -16,6 +16,32 @@
+ #include <asm/sysreg.h>
+ #include <linux/irqchip/arm-gic-v3.h>
+
++.macro init_el2_hcr val
++ mov_q x0, \val
++
++ /*
++ * Compliant CPUs advertise their VHE-onlyness with
++ * ID_AA64MMFR4_EL1.E2H0 < 0. On such CPUs HCR_EL2.E2H is RES1, but it
++ * can reset into an UNKNOWN state and might not read as 1 until it has
++ * been initialized explicitly.
++ *
++ * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
++ * don't advertise it (they predate this relaxation).
++ *
++ * Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H
++ * indicating whether the CPU is running in E2H mode.
++ */
++ mrs_s x1, SYS_ID_AA64MMFR4_EL1
++ sbfx x1, x1, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
++ cmp x1, #0
++ b.ge .LnVHE_\@
++
++ orr x0, x0, #HCR_E2H
++.LnVHE_\@:
++ msr hcr_el2, x0
++ isb
++.endm
++
+ .macro __init_el2_sctlr
+ mov_q x0, INIT_SCTLR_EL2_MMU_OFF
+ msr sctlr_el2, x0
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index e0e710b36da378..ff7769821166a4 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -575,25 +575,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+ msr sctlr_el2, x0
+ isb
+ 0:
+- mov_q x0, HCR_HOST_NVHE_FLAGS
+-
+- /*
+- * Compliant CPUs advertise their VHE-onlyness with
+- * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
+- * RES1 in that case. Publish the E2H bit early so that
+- * it can be picked up by the init_el2_state macro.
+- *
+- * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
+- * don't advertise it (they predate this relaxation).
+- */
+- mrs_s x1, SYS_ID_AA64MMFR4_EL1
+- tbz x1, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
+-
+- orr x0, x0, #HCR_E2H
+-1:
+- msr hcr_el2, x0
+- isb
+
++ init_el2_hcr HCR_HOST_NVHE_FLAGS
+ init_el2_state
+
+ /* Hypervisor stub */
+diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+index 1cc06e6797bda3..3efa9cfaa9d48d 100644
+--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
++++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+@@ -202,6 +202,8 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
+
+ 2: msr SPsel, #1 // We want to use SP_EL{1,2}
+
++ init_el2_hcr 0
++
+ /* Initialize EL2 CPU state to sane values. */
+ init_el2_state // Clobbers x0..x2
+ finalise_el2_state
+--
+2.53.0
+
--- /dev/null
+From 0d77a47dd1214af477961e83eb4e4671a19a3bef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:36:02 +0000
+Subject: KVM: arm64: Initialize SCTLR_EL1 in __kvm_hyp_init_cpu()
+
+From: Ahmed Genidi <ahmed.genidi@arm.com>
+
+[ Upstream commit 3855a7b91d42ebf3513b7ccffc44807274978b3d ]
+
+When KVM is in protected mode, host calls to PSCI are proxied via EL2,
+and cold entries from CPU_ON, CPU_SUSPEND, and SYSTEM_SUSPEND bounce
+through __kvm_hyp_init_cpu() at EL2 before entering the host kernel's
+entry point at EL1. While __kvm_hyp_init_cpu() initializes SPSR_EL2 for
+the exception return to EL1, it does not initialize SCTLR_EL1.
+
+Due to this, it's possible to enter EL1 with SCTLR_EL1 in an UNKNOWN
+state. In practice this has been seen to result in kernel crashes after
+CPU_ON as a result of SCTLR_EL1.M being 1 in violation of the initial
+core configuration specified by PSCI.
+
+Fix this by initializing SCTLR_EL1 for cold entry to the host kernel.
+As it's necessary to write to SCTLR_EL12 in VHE mode, this
+initialization is moved into __kvm_host_psci_cpu_entry() where we can
+use write_sysreg_el1().
+
+The remnants of the '__init_el2_nvhe_prepare_eret' macro are folded into
+its only caller, as this is clearer than having the macro.
+
+Fixes: cdf367192766ad11 ("KVM: arm64: Intercept host's CPU_ON SMCs")
+Reported-by: Leo Yan <leo.yan@arm.com>
+Signed-off-by: Ahmed Genidi <ahmed.genidi@arm.com>
+[ Mark: clarify commit message, handle E2H, move to C, remove macro ]
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Cc: Ahmed Genidi <ahmed.genidi@arm.com>
+Cc: Ben Horgan <ben.horgan@arm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Leo Yan <leo.yan@arm.com>
+Cc: Marc Zyngier <maz@kernel.org>
+Cc: Oliver Upton <oliver.upton@linux.dev>
+Cc: Will Deacon <will@kernel.org>
+Reviewed-by: Leo Yan <leo.yan@arm.com>
+Link: https://lore.kernel.org/r/20250227180526.1204723-3-mark.rutland@arm.com
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+[ Backport: Resolved context conflicts when removing the
+ __init_el2_nvhe_prepare_eret macro and invocation:
+ - arch/arm64/include/asm/el2_setup.h: conflicted because 6.6.y lacks later
+ GCS/MPAM macros (__init_el2_gcs / __init_el2_mpam) surrounding the definition.
+ - arch/arm64/kvm/hyp/nvhe/hyp-init.S: conflicted because __kvm_init_el2_state
+ does not exist in 6.6.y (EL2 state is initialized inline). ]
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/el2_setup.h | 4 ----
+ arch/arm64/kernel/head.S | 3 ++-
+ arch/arm64/kvm/hyp/nvhe/hyp-init.S | 1 -
+ arch/arm64/kvm/hyp/nvhe/psci-relay.c | 3 +++
+ 4 files changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
+index 3498dc5d02c188..76b0d50d286d59 100644
+--- a/arch/arm64/include/asm/el2_setup.h
++++ b/arch/arm64/include/asm/el2_setup.h
+@@ -229,10 +229,6 @@
+ .Lskip_fgt_\@:
+ .endm
+
+-.macro __init_el2_nvhe_prepare_eret
+- mov x0, #INIT_PSTATE_EL1
+- msr spsr_el2, x0
+-.endm
+
+ /**
+ * Initialize EL2 registers to sane values. This should be called early on all
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index ff7769821166a4..9996029853d236 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -601,7 +601,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+ msr sctlr_el1, x1
+ mov x2, xzr
+ 3:
+- __init_el2_nvhe_prepare_eret
++ mov x0, #INIT_PSTATE_EL1
++ msr spsr_el2, x0
+
+ mov w0, #BOOT_CPU_MODE_EL2
+ orr x0, x0, x2
+diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+index 3efa9cfaa9d48d..9b2ada54be5384 100644
+--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
++++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+@@ -207,7 +207,6 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
+ /* Initialize EL2 CPU state to sane values. */
+ init_el2_state // Clobbers x0..x2
+ finalise_el2_state
+- __init_el2_nvhe_prepare_eret
+
+ /* Enable MMU, set vectors and stack. */
+ mov x0, x28
+diff --git a/arch/arm64/kvm/hyp/nvhe/psci-relay.c b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
+index d57bcb6ab94d25..5688a16e2ea75d 100644
+--- a/arch/arm64/kvm/hyp/nvhe/psci-relay.c
++++ b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
+@@ -218,6 +218,9 @@ asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on)
+ if (is_cpu_on)
+ release_boot_args(boot_args);
+
++ write_sysreg_el1(INIT_SCTLR_EL1_MMU_OFF, SYS_SCTLR);
++ write_sysreg(INIT_PSTATE_EL1, SPSR_EL2);
++
+ __host_enter(host_ctxt);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From babac320fef51d3733e78497cf3a44ee5ed4b031 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 20:26:13 +0800
+Subject: LoongArch: Add PIO for early access before ACPI PCI root register
+
+From: Huacai Chen <chenhuacai@loongson.cn>
+
+commit 6061e65f95713b01f4313cda6637dfe3aa5412b4 upstream.
+
+For ACPI system we suppose the ISA/LPC PIO range is registered together
+with PCI root bridge. But the fact is there may be some early access to
+the ISA/LPC PIO range before ACPI PCI root register (most of them are
+due to abnormal BIOS). Unconditionally register the ISA/LPC PIO range
+usually causes ACPI PCI root register fail because of the address range
+confliction. So we add a pair of helpers: acpi_add_early_pio() to add
+PIO for early access, and acpi_remove_early_pio() to remove PIO before
+PCI root register. Since acpi_remove_early_pio() may be called multiple
+times, we add an acpi_pio flag to ensure PIO be removed only once.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/loongarch/include/asm/acpi.h | 2 ++
+ arch/loongarch/kernel/acpi.c | 28 ++++++++++++++++++++++++++++
+ arch/loongarch/kernel/setup.c | 2 ++
+ arch/loongarch/pci/acpi.c | 2 ++
+ 4 files changed, 34 insertions(+)
+
+diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
+index 49e29b29996f0f..4f31109714c0ab 100644
+--- a/arch/loongarch/include/asm/acpi.h
++++ b/arch/loongarch/include/asm/acpi.h
+@@ -37,6 +37,8 @@ static inline bool acpi_has_cpu_in_madt(void)
+ extern struct list_head acpi_wakeup_device_list;
+ extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC];
+
++extern void acpi_add_early_pio(void);
++extern void acpi_remove_early_pio(void);
+ extern int __init parse_acpi_topology(void);
+
+ static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
+diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
+index 1f529b13490b3b..34101b753eaac3 100644
+--- a/arch/loongarch/kernel/acpi.c
++++ b/arch/loongarch/kernel/acpi.c
+@@ -14,6 +14,7 @@
+ #include <linux/memblock.h>
+ #include <linux/of_fdt.h>
+ #include <linux/serial_core.h>
++#include <linux/vmalloc.h>
+ #include <asm/io.h>
+ #include <asm/numa.h>
+ #include <asm/loongson.h>
+@@ -57,6 +58,33 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+ return ioremap_cache(phys, size);
+ }
+
++#define PIO_BASE (unsigned long)PCI_IOBASE
++#define PIO_SIZE ALIGN(ISA_IOSIZE, PAGE_SIZE)
++
++static bool acpi_pio;
++
++/* Add PIO for early access */
++void acpi_add_early_pio(void)
++{
++ if (!acpi_disabled) {
++ acpi_pio = true;
++ ioremap_page_range(PIO_BASE, PIO_BASE + PIO_SIZE,
++ LOONGSON_LIO_BASE, pgprot_device(PAGE_KERNEL));
++ }
++}
++
++/* Remove PIO for PCI register */
++void acpi_remove_early_pio(void)
++{
++ if (!acpi_pio)
++ return;
++
++ if (!acpi_disabled) {
++ acpi_pio = false;
++ vunmap_range(PIO_BASE, PIO_BASE + PIO_SIZE);
++ }
++}
++
+ #ifdef CONFIG_SMP
+ static int set_processor_mask(u32 id, u32 flags)
+ {
+diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
+index 2e34ece474eece..729b0660b61c1a 100644
+--- a/arch/loongarch/kernel/setup.c
++++ b/arch/loongarch/kernel/setup.c
+@@ -530,6 +530,8 @@ static __init int arch_reserve_pio_range(void)
+ {
+ struct device_node *np;
+
++ acpi_add_early_pio();
++
+ for_each_node_by_name(np, "isa") {
+ struct of_range range;
+ struct of_range_parser parser;
+diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c
+index 2d584a59a2a049..b53dae9d57c899 100644
+--- a/arch/loongarch/pci/acpi.c
++++ b/arch/loongarch/pci/acpi.c
+@@ -65,6 +65,8 @@ static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
+ struct resource_entry *entry, *tmp;
+ struct acpi_device *device = ci->bridge;
+
++ acpi_remove_early_pio();
++
+ status = acpi_pci_probe_root_resources(ci);
+ if (status > 0) {
+ acpi_evaluate_integer(device->handle, "PCIH", NULL, &pci_h);
+--
+2.53.0
+
--- /dev/null
+From 4cc4b1d9c56de54140d02dd39e66e874f5580aab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 20:58:16 +0800
+Subject: net: Drop the lock in skb_may_tx_timestamp()
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+commit 983512f3a87fd8dc4c94dfa6b596b6e57df5aad7 upstream.
+
+skb_may_tx_timestamp() may acquire sock::sk_callback_lock. The lock must
+not be taken in IRQ context, only softirq is okay. A few drivers receive
+the timestamp via a dedicated interrupt and complete the TX timestamp
+from that handler. This will lead to a deadlock if the lock is already
+write-locked on the same CPU.
+
+Taking the lock can be avoided. The socket (pointed by the skb) will
+remain valid until the skb is released. The ->sk_socket and ->file
+member will be set to NULL once the user closes the socket which may
+happen before the timestamp arrives.
+If we happen to observe the pointer while the socket is closing but
+before the pointer is set to NULL then we may use it because both
+pointer (and the file's cred member) are RCU freed.
+
+Drop the lock. Use READ_ONCE() to obtain the individual pointer. Add a
+matching WRITE_ONCE() where the pointer are cleared.
+
+Link: https://lore.kernel.org/all/20260205145104.iWinkXHv@linutronix.de
+Fixes: b245be1f4db1a ("net-timestamp: no-payload only sysctl")
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260220183858.N4ERjFW6@linutronix.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ adapted sk_set_socket() in include/net/sock.h to fix the conflict from
+ not having commit 5d6b58c932ec ("net: lockless sock_i_ino()") and the
+ additional previous changes required by it.
+ It comes down to just now having the lines of
+ if (sock) {
+ WRITE_ONCE(sk->sk_uid, SOCK_INODE(sock)->i_uid);
+ WRITE_ONCE(sk->sk_ino, SOCK_INODE(sock)->i_ino);
+ }
+ below the changed line. ]
+Signed-off-by: Philo Lu <lulie@linux.alibaba.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/sock.h | 2 +-
+ net/core/skbuff.c | 23 ++++++++++++++++++-----
+ net/socket.c | 2 +-
+ 3 files changed, 20 insertions(+), 7 deletions(-)
+
+diff --git a/include/net/sock.h b/include/net/sock.h
+index a6944844553afe..c1f129a532b200 100644
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -2155,7 +2155,7 @@ static inline int sk_rx_queue_get(const struct sock *sk)
+
+ static inline void sk_set_socket(struct sock *sk, struct socket *sock)
+ {
+- sk->sk_socket = sock;
++ WRITE_ONCE(sk->sk_socket, sock);
+ }
+
+ static inline wait_queue_head_t *sk_sleep(struct sock *sk)
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index c5e2ae6d0406bd..732204d99822a2 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -5258,15 +5258,28 @@ static void __skb_complete_tx_timestamp(struct sk_buff *skb,
+
+ static bool skb_may_tx_timestamp(struct sock *sk, bool tsonly)
+ {
+- bool ret;
++ struct socket *sock;
++ struct file *file;
++ bool ret = false;
+
+ if (likely(READ_ONCE(sysctl_tstamp_allow_data) || tsonly))
+ return true;
+
+- read_lock_bh(&sk->sk_callback_lock);
+- ret = sk->sk_socket && sk->sk_socket->file &&
+- file_ns_capable(sk->sk_socket->file, &init_user_ns, CAP_NET_RAW);
+- read_unlock_bh(&sk->sk_callback_lock);
++ /* The sk pointer remains valid as long as the skb is. The sk_socket and
++ * file pointer may become NULL if the socket is closed. Both structures
++ * (including file->cred) are RCU freed which means they can be accessed
++ * within a RCU read section.
++ */
++ rcu_read_lock();
++ sock = READ_ONCE(sk->sk_socket);
++ if (!sock)
++ goto out;
++ file = READ_ONCE(sock->file);
++ if (!file)
++ goto out;
++ ret = file_ns_capable(file, &init_user_ns, CAP_NET_RAW);
++out:
++ rcu_read_unlock();
+ return ret;
+ }
+
+diff --git a/net/socket.c b/net/socket.c
+index fa242d7e51c791..ae31c54664632c 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -671,7 +671,7 @@ static void __sock_release(struct socket *sock, struct inode *inode)
+ iput(SOCK_INODE(sock));
+ return;
+ }
+- sock->file = NULL;
++ WRITE_ONCE(sock->file, NULL);
+ }
+
+ /**
+--
+2.53.0
+
--- /dev/null
+From a492ad32315e54d55173da7f252a0d86e678a0c3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 23:29:58 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 73a86db06cc9b1..d45bce2acdbc75 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4449,7 +4449,8 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
+
+ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+- struct perf_event_context *ctx);
++ struct perf_event_context *ctx,
++ unsigned long detach_flags);
+
+ /*
+ * Removes all events from the current task that have been marked
+@@ -4476,7 +4477,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
+
+ modified = true;
+
+- perf_event_exit_event(event, ctx);
++ perf_event_exit_event(event, ctx, DETACH_GROUP);
+ }
+
+ raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -13230,10 +13231,11 @@ static void sync_child_event(struct perf_event *child_event)
+ }
+
+ static void
+-perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
++perf_event_exit_event(struct perf_event *event,
++ struct perf_event_context *ctx,
++ unsigned long detach_flags)
+ {
+ struct perf_event *parent_event = event->parent;
+- unsigned long detach_flags = 0;
+
+ if (parent_event) {
+ /*
+@@ -13248,7 +13250,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
+ * Do destroy all inherited groups, we don't care about those
+ * and being thorough is better.
+ */
+- detach_flags = DETACH_GROUP | DETACH_CHILD;
++ detach_flags |= DETACH_GROUP | DETACH_CHILD;
+ mutex_lock(&parent_event->child_mutex);
+ }
+
+@@ -13328,7 +13330,7 @@ static void perf_event_exit_task_context(struct task_struct *child)
+ perf_event_task(child, child_ctx, 0);
+
+ list_for_each_entry_safe(child_event, next, &child_ctx->event_list, event_entry)
+- perf_event_exit_event(child_event, child_ctx);
++ perf_event_exit_event(child_event, child_ctx, 0);
+
+ mutex_unlock(&child_ctx->mutex);
+
+--
+2.53.0
+
--- /dev/null
+From 287c9c848fbe5458d88c57c8799996e7cad64ba9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:53 +0200
+Subject: Revert "crypto: talitos - fix SEC1 32k ahash request limitation"
+
+From: Goetz Goerisch <ggoerisch@gmail.com>
+
+This reverts commit 00463d5f864ae28b7938d5acd0ddd800d5457e8b.
+Which was backported without applying upstream
+commit 9826d1d6ed5f86cb3d61610b3b1fe31e96a40418 first.
+
+Commit a1b80018b8cec27fc06a8b04a7f8b5f6cfe86eae
+was backported to 6.6.y with a866e2b1c65edaee2e1bb1024ee2c761ced335f8
+It renames last to last_desc but misses one occurrence which leads to compile errors on mpc85xx
+
+drivers/crypto/talitos.c: In function 'ahash_digest':
+drivers/crypto/talitos.c:2204:16: error: 'struct talitos_ahash_req_ctx' has no member named 'last'
+ 2204 | req_ctx->last = 1;
+ | ^~~~
+
+Instead of renaming req_ctx->last, commit 9826d1d6ed5f8 ("crypto: talitos - stop
+using crypto_ahash::init") should be applied.
+Ideally before commit 00463d5f864a ("crypto: talitos - fix SEC1 32k ahash
+request limitation") to avoid any compilation breakage and ensure correctness of
+the code.
+
+Reverting and applying in correct order.
+
+Link: https://lore.kernel.org/all/DIOA24QU02W5.2RSVK05RE7BJK@bootlin.com/
+Signed-off-by: Goetz Goerisch <ggoerisch@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 216 +++++++++++++--------------------------
+ 1 file changed, 69 insertions(+), 147 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index f78a44f991013b..4ca4fbd227bce1 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -12,7 +12,6 @@
+ * All rights reserved.
+ */
+
+-#include <linux/workqueue.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mod_devicetable.h>
+@@ -871,18 +870,10 @@ struct talitos_ahash_req_ctx {
+ unsigned int swinit;
+ unsigned int first;
+ unsigned int last;
+- unsigned int last_request;
+ unsigned int to_hash_later;
+ unsigned int nbuf;
+ struct scatterlist bufsl[2];
+ struct scatterlist *psrc;
+-
+- struct scatterlist request_bufsl[2];
+- struct ahash_request *areq;
+- struct scatterlist *request_sl;
+- unsigned int remaining_ahash_request_bytes;
+- unsigned int current_ahash_request_bytes;
+- struct work_struct sec1_ahash_process_remaining;
+ };
+
+ struct talitos_export_state {
+@@ -1768,20 +1759,7 @@ static void ahash_done(struct device *dev,
+
+ kfree(edesc);
+
+- if (err) {
+- ahash_request_complete(areq, err);
+- return;
+- }
+-
+- req_ctx->remaining_ahash_request_bytes -=
+- req_ctx->current_ahash_request_bytes;
+-
+- if (!req_ctx->remaining_ahash_request_bytes) {
+- ahash_request_complete(areq, 0);
+- return;
+- }
+-
+- schedule_work(&req_ctx->sec1_ahash_process_remaining);
++ ahash_request_complete(areq, err);
+ }
+
+ /*
+@@ -1947,7 +1925,60 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
+ nbytes, 0, 0, 0, areq->base.flags, false);
+ }
+
+-static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes)
++static int ahash_init(struct ahash_request *areq)
++{
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
++ struct device *dev = ctx->dev;
++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++ unsigned int size;
++ dma_addr_t dma;
++
++ /* Initialize the context */
++ req_ctx->buf_idx = 0;
++ req_ctx->nbuf = 0;
++ req_ctx->first = 1; /* first indicates h/w must init its context */
++ req_ctx->swinit = 0; /* assume h/w init of context */
++ size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
++ ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
++ : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
++ req_ctx->hw_context_size = size;
++
++ dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
++ DMA_TO_DEVICE);
++ dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
++
++ return 0;
++}
++
++/*
++ * on h/w without explicit sha224 support, we initialize h/w context
++ * manually with sha224 constants, and tell it to run sha256.
++ */
++static int ahash_init_sha224_swinit(struct ahash_request *areq)
++{
++ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++
++ req_ctx->hw_context[0] = SHA224_H0;
++ req_ctx->hw_context[1] = SHA224_H1;
++ req_ctx->hw_context[2] = SHA224_H2;
++ req_ctx->hw_context[3] = SHA224_H3;
++ req_ctx->hw_context[4] = SHA224_H4;
++ req_ctx->hw_context[5] = SHA224_H5;
++ req_ctx->hw_context[6] = SHA224_H6;
++ req_ctx->hw_context[7] = SHA224_H7;
++
++ /* init 64-bit count */
++ req_ctx->hw_context[8] = 0;
++ req_ctx->hw_context[9] = 0;
++
++ ahash_init(areq);
++ req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
++
++ return 0;
++}
++
++static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+ {
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+@@ -1966,12 +1997,12 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+
+ if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+ /* Buffer up to one whole block */
+- nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
++ nents = sg_nents_for_len(areq->src, nbytes);
+ if (nents < 0) {
+ dev_err(dev, "Invalid number of src SG.\n");
+ return nents;
+ }
+- sg_copy_to_buffer(req_ctx->request_sl, nents,
++ sg_copy_to_buffer(areq->src, nents,
+ ctx_buf + req_ctx->nbuf, nbytes);
+ req_ctx->nbuf += nbytes;
+ return 0;
+@@ -1998,7 +2029,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ sg_init_table(req_ctx->bufsl, nsg);
+ sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf);
+ if (nsg > 1)
+- sg_chain(req_ctx->bufsl, 2, req_ctx->request_sl);
++ sg_chain(req_ctx->bufsl, 2, areq->src);
+ req_ctx->psrc = req_ctx->bufsl;
+ } else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) {
+ int offset;
+@@ -2007,26 +2038,26 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ offset = blocksize - req_ctx->nbuf;
+ else
+ offset = nbytes_to_hash - req_ctx->nbuf;
+- nents = sg_nents_for_len(req_ctx->request_sl, offset);
++ nents = sg_nents_for_len(areq->src, offset);
+ if (nents < 0) {
+ dev_err(dev, "Invalid number of src SG.\n");
+ return nents;
+ }
+- sg_copy_to_buffer(req_ctx->request_sl, nents,
++ sg_copy_to_buffer(areq->src, nents,
+ ctx_buf + req_ctx->nbuf, offset);
+ req_ctx->nbuf += offset;
+- req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, req_ctx->request_sl,
++ req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, areq->src,
+ offset);
+ } else
+- req_ctx->psrc = req_ctx->request_sl;
++ req_ctx->psrc = areq->src;
+
+ if (to_hash_later) {
+- nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
++ nents = sg_nents_for_len(areq->src, nbytes);
+ if (nents < 0) {
+ dev_err(dev, "Invalid number of src SG.\n");
+ return nents;
+ }
+- sg_pcopy_to_buffer(req_ctx->request_sl, nents,
++ sg_pcopy_to_buffer(areq->src, nents,
+ req_ctx->buf[(req_ctx->buf_idx + 1) & 1],
+ to_hash_later,
+ nbytes - to_hash_later);
+@@ -2034,7 +2065,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ req_ctx->to_hash_later = to_hash_later;
+
+ /* Allocate extended descriptor */
+- edesc = ahash_edesc_alloc(req_ctx->areq, nbytes_to_hash);
++ edesc = ahash_edesc_alloc(areq, nbytes_to_hash);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+@@ -2056,123 +2087,14 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ if (ctx->keylen && (req_ctx->first || req_ctx->last))
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+
+- return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
+-}
+-
+-static void sec1_ahash_process_remaining(struct work_struct *work)
+-{
+- struct talitos_ahash_req_ctx *req_ctx =
+- container_of(work, struct talitos_ahash_req_ctx,
+- sec1_ahash_process_remaining);
+- int err = 0;
+-
+- req_ctx->request_sl = scatterwalk_ffwd(req_ctx->request_bufsl,
+- req_ctx->request_sl, TALITOS1_MAX_DATA_LEN);
+-
+- if (req_ctx->remaining_ahash_request_bytes > TALITOS1_MAX_DATA_LEN)
+- req_ctx->current_ahash_request_bytes = TALITOS1_MAX_DATA_LEN;
+- else {
+- req_ctx->current_ahash_request_bytes =
+- req_ctx->remaining_ahash_request_bytes;
+-
+- if (req_ctx->last_request)
+- req_ctx->last = 1;
+- }
+-
+- err = ahash_process_req_one(req_ctx->areq,
+- req_ctx->current_ahash_request_bytes);
+-
+- if (err != -EINPROGRESS)
+- ahash_request_complete(req_ctx->areq, err);
+-}
+-
+-static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+-{
+- struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+- struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+- struct device *dev = ctx->dev;
+- struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+- struct talitos_private *priv = dev_get_drvdata(dev);
+- bool is_sec1 = has_ftr_sec1(priv);
+-
+- req_ctx->areq = areq;
+- req_ctx->request_sl = areq->src;
+- req_ctx->remaining_ahash_request_bytes = nbytes;
+-
+- if (is_sec1) {
+- if (nbytes > TALITOS1_MAX_DATA_LEN)
+- nbytes = TALITOS1_MAX_DATA_LEN;
+- else if (req_ctx->last_request)
+- req_ctx->last = 1;
+- }
+-
+- req_ctx->current_ahash_request_bytes = nbytes;
+-
+- return ahash_process_req_one(req_ctx->areq,
+- req_ctx->current_ahash_request_bytes);
+-}
+-
+-static int ahash_init(struct ahash_request *areq)
+-{
+- struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+- struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+- struct device *dev = ctx->dev;
+- struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+- unsigned int size;
+- dma_addr_t dma;
+-
+- /* Initialize the context */
+- req_ctx->buf_idx = 0;
+- req_ctx->nbuf = 0;
+- req_ctx->first = 1; /* first indicates h/w must init its context */
+- req_ctx->swinit = 0; /* assume h/w init of context */
+- size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+- ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+- : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+- req_ctx->hw_context_size = size;
+- req_ctx->last_request = 0;
+- req_ctx->last = 0;
+- INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
+-
+- dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+- DMA_TO_DEVICE);
+- dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
+-
+- return 0;
+-}
+-
+-/*
+- * on h/w without explicit sha224 support, we initialize h/w context
+- * manually with sha224 constants, and tell it to run sha256.
+- */
+-static int ahash_init_sha224_swinit(struct ahash_request *areq)
+-{
+- struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-
+- req_ctx->hw_context[0] = SHA224_H0;
+- req_ctx->hw_context[1] = SHA224_H1;
+- req_ctx->hw_context[2] = SHA224_H2;
+- req_ctx->hw_context[3] = SHA224_H3;
+- req_ctx->hw_context[4] = SHA224_H4;
+- req_ctx->hw_context[5] = SHA224_H5;
+- req_ctx->hw_context[6] = SHA224_H6;
+- req_ctx->hw_context[7] = SHA224_H7;
+-
+- /* init 64-bit count */
+- req_ctx->hw_context[8] = 0;
+- req_ctx->hw_context[9] = 0;
+-
+- ahash_init(areq);
+- req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
+-
+- return 0;
++ return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, ahash_done);
+ }
+
+ static int ahash_update(struct ahash_request *areq)
+ {
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+- req_ctx->last_request = 0;
++ req_ctx->last = 0;
+
+ return ahash_process_req(areq, areq->nbytes);
+ }
+@@ -2181,7 +2103,7 @@ static int ahash_final(struct ahash_request *areq)
+ {
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+- req_ctx->last_request = 1;
++ req_ctx->last = 1;
+
+ return ahash_process_req(areq, 0);
+ }
+@@ -2190,7 +2112,7 @@ static int ahash_finup(struct ahash_request *areq)
+ {
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+- req_ctx->last_request = 1;
++ req_ctx->last = 1;
+
+ return ahash_process_req(areq, areq->nbytes);
+ }
+--
+2.53.0
+
--- /dev/null
+From a18cb66676462286f40ddfc5b4311087e5dec840 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:52 +0200
+Subject: Revert "crypto: talitos - rename first/last to first_desc/last_desc"
+
+From: Goetz Goerisch <ggoerisch@gmail.com>
+
+This reverts commit a866e2b1c65edaee2e1bb1024ee2c761ced335f8.
+
+Which was backported without applying upstream
+commit 9826d1d6ed5f86cb3d61610b3b1fe31e96a40418 first.
+
+Commit a1b80018b8cec27fc06a8b04a7f8b5f6cfe86eae
+was backported to 6.6.y with a866e2b1c65edaee2e1bb1024ee2c761ced335f8
+It renames last to last_desc but misses one occurrence which leads to compile errors on mpc85xx
+
+drivers/crypto/talitos.c: In function 'ahash_digest':
+drivers/crypto/talitos.c:2204:16: error: 'struct talitos_ahash_req_ctx' has no member named 'last'
+ 2204 | req_ctx->last = 1;
+ | ^~~~
+
+Instead of renaming req_ctx->last, commit 9826d1d6ed5f8 ("crypto: talitos - stop
+using crypto_ahash::init") should be applied.
+Ideally before commit 00463d5f864a ("crypto: talitos - fix SEC1 32k ahash
+request limitation") to avoid any compilation breakage and ensure correctness of
+the code.
+
+Reverting and applying in correct order.
+
+Link: https://lore.kernel.org/all/DIOA24QU02W5.2RSVK05RE7BJK@bootlin.com/
+Signed-off-by: Goetz Goerisch <ggoerisch@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 46 ++++++++++++++++++++--------------------
+ 1 file changed, 23 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index 347483f6fc5dd6..f78a44f991013b 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -869,8 +869,8 @@ struct talitos_ahash_req_ctx {
+ u8 buf[2][HASH_MAX_BLOCK_SIZE];
+ int buf_idx;
+ unsigned int swinit;
+- unsigned int first_desc;
+- unsigned int last_desc;
++ unsigned int first;
++ unsigned int last;
+ unsigned int last_request;
+ unsigned int to_hash_later;
+ unsigned int nbuf;
+@@ -889,8 +889,8 @@ struct talitos_export_state {
+ u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
+ u8 buf[HASH_MAX_BLOCK_SIZE];
+ unsigned int swinit;
+- unsigned int first_desc;
+- unsigned int last_desc;
++ unsigned int first;
++ unsigned int last;
+ unsigned int to_hash_later;
+ unsigned int nbuf;
+ };
+@@ -1722,7 +1722,7 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
+ if (desc->next_desc &&
+ desc->ptr[5].ptr != desc2->ptr[5].ptr)
+ unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE);
+- if (req_ctx->last_desc)
++ if (req_ctx->last)
+ memcpy(areq->result, req_ctx->hw_context,
+ crypto_ahash_digestsize(tfm));
+
+@@ -1759,7 +1759,7 @@ static void ahash_done(struct device *dev,
+ container_of(desc, struct talitos_edesc, desc);
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+- if (!req_ctx->last_desc && req_ctx->to_hash_later) {
++ if (!req_ctx->last && req_ctx->to_hash_later) {
+ /* Position any partial block for next update/final/finup */
+ req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
+ req_ctx->nbuf = req_ctx->to_hash_later;
+@@ -1825,7 +1825,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+ /* first DWORD empty */
+
+ /* hash context in */
+- if (!req_ctx->first_desc || req_ctx->swinit) {
++ if (!req_ctx->first || req_ctx->swinit) {
+ map_single_talitos_ptr_nosync(dev, &desc->ptr[1],
+ req_ctx->hw_context_size,
+ req_ctx->hw_context,
+@@ -1833,7 +1833,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+ req_ctx->swinit = 0;
+ }
+ /* Indicate next op is not the first. */
+- req_ctx->first_desc = 0;
++ req_ctx->first = 0;
+
+ /* HMAC key */
+ if (ctx->keylen)
+@@ -1866,7 +1866,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+ /* fifth DWORD empty */
+
+ /* hash/HMAC out -or- hash context out */
+- if (req_ctx->last_desc)
++ if (req_ctx->last)
+ map_single_talitos_ptr(dev, &desc->ptr[5],
+ crypto_ahash_digestsize(tfm),
+ req_ctx->hw_context, DMA_FROM_DEVICE);
+@@ -1908,7 +1908,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+ if (sg_count > 1)
+ sync_needed = true;
+ copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
+- if (req_ctx->last_desc)
++ if (req_ctx->last)
+ map_single_talitos_ptr_nosync(dev, &desc->ptr[5],
+ req_ctx->hw_context_size,
+ req_ctx->hw_context,
+@@ -1964,7 +1964,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ bool is_sec1 = has_ftr_sec1(priv);
+ u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
+
+- if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) {
++ if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+ /* Buffer up to one whole block */
+ nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+ if (nents < 0) {
+@@ -1981,7 +1981,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ nbytes_to_hash = nbytes + req_ctx->nbuf;
+ to_hash_later = nbytes_to_hash & (blocksize - 1);
+
+- if (req_ctx->last_desc)
++ if (req_ctx->last)
+ to_hash_later = 0;
+ else if (to_hash_later)
+ /* There is a partial block. Hash the full block(s) now */
+@@ -2041,19 +2041,19 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+ edesc->desc.hdr = ctx->desc_hdr_template;
+
+ /* On last one, request SEC to pad; otherwise continue */
+- if (req_ctx->last_desc)
++ if (req_ctx->last)
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD;
+ else
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT;
+
+ /* request SEC to INIT hash. */
+- if (req_ctx->first_desc && !req_ctx->swinit)
++ if (req_ctx->first && !req_ctx->swinit)
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
+
+ /* When the tfm context has a keylen, it's an HMAC.
+ * A first or last (ie. not middle) descriptor must request HMAC.
+ */
+- if (ctx->keylen && (req_ctx->first_desc || req_ctx->last_desc))
++ if (ctx->keylen && (req_ctx->first || req_ctx->last))
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+
+ return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
+@@ -2076,7 +2076,7 @@ static void sec1_ahash_process_remaining(struct work_struct *work)
+ req_ctx->remaining_ahash_request_bytes;
+
+ if (req_ctx->last_request)
+- req_ctx->last_desc = 1;
++ req_ctx->last = 1;
+ }
+
+ err = ahash_process_req_one(req_ctx->areq,
+@@ -2103,7 +2103,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+ if (nbytes > TALITOS1_MAX_DATA_LEN)
+ nbytes = TALITOS1_MAX_DATA_LEN;
+ else if (req_ctx->last_request)
+- req_ctx->last_desc = 1;
++ req_ctx->last = 1;
+ }
+
+ req_ctx->current_ahash_request_bytes = nbytes;
+@@ -2124,14 +2124,14 @@ static int ahash_init(struct ahash_request *areq)
+ /* Initialize the context */
+ req_ctx->buf_idx = 0;
+ req_ctx->nbuf = 0;
+- req_ctx->first_desc = 1; /* first_desc indicates h/w must init its context */
++ req_ctx->first = 1; /* first indicates h/w must init its context */
+ req_ctx->swinit = 0; /* assume h/w init of context */
+ size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+ ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+ : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+ req_ctx->hw_context_size = size;
+ req_ctx->last_request = 0;
+- req_ctx->last_desc = 0;
++ req_ctx->last = 0;
+ INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
+
+ dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+@@ -2223,8 +2223,8 @@ static int ahash_export(struct ahash_request *areq, void *out)
+ req_ctx->hw_context_size);
+ memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
+ export->swinit = req_ctx->swinit;
+- export->first_desc = req_ctx->first_desc;
+- export->last_desc = req_ctx->last_desc;
++ export->first = req_ctx->first;
++ export->last = req_ctx->last;
+ export->to_hash_later = req_ctx->to_hash_later;
+ export->nbuf = req_ctx->nbuf;
+
+@@ -2249,8 +2249,8 @@ static int ahash_import(struct ahash_request *areq, const void *in)
+ memcpy(req_ctx->hw_context, export->hw_context, size);
+ memcpy(req_ctx->buf[0], export->buf, export->nbuf);
+ req_ctx->swinit = export->swinit;
+- req_ctx->first_desc = export->first_desc;
+- req_ctx->last_desc = export->last_desc;
++ req_ctx->first = export->first;
++ req_ctx->last = export->last;
+ req_ctx->to_hash_later = export->to_hash_later;
+ req_ctx->nbuf = export->nbuf;
+
+--
+2.53.0
+
--- /dev/null
+From 7ae162b72c0f0e84ec950564118408de781a7813 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 12:56:04 -0400
+Subject: Revert "LoongArch: Add PIO for early access before ACPI PCI root
+ register"
+
+This reverts commit e4c9b6d07a546969396aa7564a5c2938e4720c80.
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/loongarch/include/asm/acpi.h | 2 --
+ arch/loongarch/kernel/acpi.c | 28 ----------------------------
+ arch/loongarch/kernel/setup.c | 2 --
+ arch/loongarch/pci/acpi.c | 2 --
+ 4 files changed, 34 deletions(-)
+
+diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
+index 4f31109714c0ab..49e29b29996f0f 100644
+--- a/arch/loongarch/include/asm/acpi.h
++++ b/arch/loongarch/include/asm/acpi.h
+@@ -37,8 +37,6 @@ static inline bool acpi_has_cpu_in_madt(void)
+ extern struct list_head acpi_wakeup_device_list;
+ extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC];
+
+-extern void acpi_add_early_pio(void);
+-extern void acpi_remove_early_pio(void);
+ extern int __init parse_acpi_topology(void);
+
+ static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
+diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
+index 4f4f8a9e7e3bb7..1f529b13490b3b 100644
+--- a/arch/loongarch/kernel/acpi.c
++++ b/arch/loongarch/kernel/acpi.c
+@@ -14,7 +14,6 @@
+ #include <linux/memblock.h>
+ #include <linux/of_fdt.h>
+ #include <linux/serial_core.h>
+-#include <linux/vmalloc.h>
+ #include <asm/io.h>
+ #include <asm/numa.h>
+ #include <asm/loongson.h>
+@@ -58,33 +57,6 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+ return ioremap_cache(phys, size);
+ }
+
+-#define PIO_BASE (unsigned long)PCI_IOBASE
+-#define PIO_SIZE ALIGN(ISA_IOSIZE, PAGE_SIZE)
+-
+-static bool acpi_pio;
+-
+-/* Add PIO for early access */
+-void acpi_add_early_pio(void)
+-{
+- if (!acpi_disabled) {
+- acpi_pio = true;
+- vmap_page_range(PIO_BASE, PIO_BASE + PIO_SIZE,
+- LOONGSON_LIO_BASE, pgprot_device(PAGE_KERNEL));
+- }
+-}
+-
+-/* Remove PIO for PCI register */
+-void acpi_remove_early_pio(void)
+-{
+- if (!acpi_pio)
+- return;
+-
+- if (!acpi_disabled) {
+- acpi_pio = false;
+- vunmap_range(PIO_BASE, PIO_BASE + PIO_SIZE);
+- }
+-}
+-
+ #ifdef CONFIG_SMP
+ static int set_processor_mask(u32 id, u32 flags)
+ {
+diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
+index 729b0660b61c1a..2e34ece474eece 100644
+--- a/arch/loongarch/kernel/setup.c
++++ b/arch/loongarch/kernel/setup.c
+@@ -530,8 +530,6 @@ static __init int arch_reserve_pio_range(void)
+ {
+ struct device_node *np;
+
+- acpi_add_early_pio();
+-
+ for_each_node_by_name(np, "isa") {
+ struct of_range range;
+ struct of_range_parser parser;
+diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c
+index b53dae9d57c899..2d584a59a2a049 100644
+--- a/arch/loongarch/pci/acpi.c
++++ b/arch/loongarch/pci/acpi.c
+@@ -65,8 +65,6 @@ static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
+ struct resource_entry *entry, *tmp;
+ struct acpi_device *device = ci->bridge;
+
+- acpi_remove_early_pio();
+-
+ status = acpi_pci_probe_root_resources(ci);
+ if (status > 0) {
+ acpi_evaluate_integer(device->handle, "PCIH", NULL, &pci_h);
+--
+2.53.0
+
acpi-nfit-core-fix-possible-null-pointer-dereference.patch
loongarch-add-pio-for-early-access-before-acpi-pci-root-register.patch
rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+revert-crypto-talitos-rename-first-last-to-first_des.patch
+revert-crypto-talitos-fix-sec1-32k-ahash-request-lim.patch
+crypto-talitos-stop-using-crypto_ahash-init.patch
+crypto-talitos-fix-sec1-32k-ahash-request-limitation.patch
+crypto-talitos-rename-first-last-to-first_desc-last_.patch
+arm64-sysreg-add-layout-for-id_aa64mmfr4_el1.patch
+arm64-treat-hcr_el2.e2h-as-res1-when-id_aa64mmfr4_el.patch
+arm64-fix-early-handling-of-feat_e2h0-not-being-impl.patch
+kvm-arm64-initialize-hcr_el2.e2h-early.patch
+kvm-arm64-initialize-sctlr_el1-in-__kvm_hyp_init_cpu.patch
+arm64-revamp-hcr_el2.e2h-res1-detection.patch
+arm64-sysreg-correct-sign-definitions-for-eiesb-and-.patch
+virtio_net-support-dynamic-rss-indirection-table-siz.patch
+revert-loongarch-add-pio-for-early-access-before-acp.patch
+loongarch-add-pio-for-early-access-before-acpi-pci-r.patch
+net-drop-the-lock-in-skb_may_tx_timestamp.patch
--- /dev/null
+From 49bd6abe10fe9f28e9e19b4dd1a29e70bf1381c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 11:19:54 +0000
+Subject: virtio_net: Support dynamic rss indirection table size
+
+From: Philo Lu <lulie@linux.alibaba.com>
+
+commit 86a48a00efdf61197b6658e52c6140463eb313dc upstream.
+
+When reading/writing virtio_net_ctrl_rss, the indirection table size is
+obtained from vi->rss_indir_table_size, initialized during virtnet_probe().
+However, the indirection_table was statically sized as
+VIRTIO_NET_RSS_MAX_TABLE_LEN=128, potentially causing issues when
+vi->rss_indir_table_size exceeds this limit.
+
+This patch implements dynamic allocation for the indirection table,
+allocated alongside vi->rss after vi->rss_indir_table_size is initialized,
+and freed in virtnet_remove().
+
+In virtnet_commit_rss_command(), scatter-gather lists for RSS are
+initialized differently based on hash_report presence, so indirection_table
+is unused when !vi->has_rss. Therefore, allocation is unnecessary for
+hash_report-only scenarios.
+
+Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
+Signed-off-by: Philo Lu <lulie@linux.alibaba.com>
+Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Acked-by: Joe Damato <jdamato@fastly.com>
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ Hyokyung Kim: 6.6.y predates the refactor that moved the RSS config into
+ struct virtnet_info, so struct virtio_net_ctrl_rss is still embedded in
+ struct control_buf and reached through the heap-allocated vi->ctrl. Every
+ adaptation below follows from that single difference:
+ - the new allocation and all indirection_table accesses use vi->ctrl->rss
+ in place of upstream's vi->rss;
+ - because vi->ctrl is allocated in virtnet_alloc_queues() (via init_vqs())
+ and freed in virtnet_free_queues(), the table is allocated and freed there
+ too, not in virtnet_probe()/virtnet_remove(), so its lifetime tracks
+ vi->ctrl across the probe error-unwind and freeze/restore paths;
+ - since freeing the table now dereferences vi->ctrl, vi->ctrl is set to NULL
+ after each kfree so a re-entered virtnet_free_queues() cannot dereference
+ or free a stale pointer;
+ - the table is allocated with kcalloc() so it is zero-filled when
+ reallocated on the restore path (upstream never reallocates it). ]
+Signed-off-by: Hyokyung Kim <pulpannie@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/virtio_net.c | 43 +++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 38 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
+index 33f61922c13994..5bcd1296851c6c 100644
+--- a/drivers/net/virtio_net.c
++++ b/drivers/net/virtio_net.c
+@@ -208,15 +208,16 @@ struct receive_queue {
+ * because table sizes may be differ according to the device configuration.
+ */
+ #define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
+-#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
+ struct virtio_net_ctrl_rss {
+ u32 hash_types;
+ u16 indirection_table_mask;
+ u16 unclassified_queue;
+- u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
++ u16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */
+ u16 max_tx_vq;
+ u8 hash_key_length;
+ u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
++
++ u16 *indirection_table;
+ };
+
+ /* Control VQ buffers: protected by the rtnl lock */
+@@ -3011,6 +3012,25 @@ static int virtnet_set_ringparam(struct net_device *dev,
+ return 0;
+ }
+
++static int rss_indirection_table_alloc(struct virtio_net_ctrl_rss *rss, u16 indir_table_size)
++{
++ if (!indir_table_size) {
++ rss->indirection_table = NULL;
++ return 0;
++ }
++
++ rss->indirection_table = kcalloc(indir_table_size, sizeof(u16), GFP_KERNEL);
++ if (!rss->indirection_table)
++ return -ENOMEM;
++
++ return 0;
++}
++
++static void rss_indirection_table_free(struct virtio_net_ctrl_rss *rss)
++{
++ kfree(rss->indirection_table);
++}
++
+ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+ {
+ struct net_device *dev = vi->dev;
+@@ -3020,11 +3040,15 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+ /* prepare sgs */
+ sg_init_table(sgs, 4);
+
+- sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
++ sg_buf_size = offsetof(struct virtio_net_ctrl_rss, hash_cfg_reserved);
+ sg_set_buf(&sgs[0], &vi->ctrl->rss, sg_buf_size);
+
+- sg_buf_size = sizeof(uint16_t) * (vi->ctrl->rss.indirection_table_mask + 1);
+- sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
++ if (vi->has_rss) {
++ sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
++ sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
++ } else {
++ sg_set_buf(&sgs[1], &vi->ctrl->rss.hash_cfg_reserved, sizeof(uint16_t));
++ }
+
+ sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
+ - offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
+@@ -4080,7 +4104,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+
+ kfree(vi->rq);
+ kfree(vi->sq);
++ if (vi->ctrl)
++ rss_indirection_table_free(&vi->ctrl->rss);
+ kfree(vi->ctrl);
++ vi->ctrl = NULL;
+ }
+
+ static void _free_receive_bufs(struct virtnet_info *vi)
+@@ -4266,6 +4293,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
+ vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL);
+ if (!vi->ctrl)
+ goto err_ctrl;
++ if ((vi->has_rss || vi->has_rss_hash_report) &&
++ rss_indirection_table_alloc(&vi->ctrl->rss, vi->rss_indir_table_size))
++ goto err_sq;
+ } else {
+ vi->ctrl = NULL;
+ }
+@@ -4298,7 +4328,10 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
+ err_rq:
+ kfree(vi->sq);
+ err_sq:
++ if (vi->ctrl)
++ rss_indirection_table_free(&vi->ctrl->rss);
+ kfree(vi->ctrl);
++ vi->ctrl = NULL;
+ err_ctrl:
+ return -ENOMEM;
+ }
+--
+2.53.0
+
--- /dev/null
+From 1c034229fe9b37575bcee8d520d1adce8f108e64 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:24:47 -0700
+Subject: bpf: Prefer dirty packs for eBPF allocations
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit b72e29e0f7ee329d89f86db8700c8ea99b4a370a upstream.
+
+The pack allocator only flushes predictors when reusing a dirty pack for
+cBPF, eBPF allocations never trigger a flush. Currently, eBPF picks the
+first free pack, which could be a clean pack. As an optimization, leaving
+a clean pack for cBPF can avoid flushes.
+
+Prefer dirty packs for eBPF and keep clean packs free for cBPF. This
+mirrors the existing cBPF preference for clean packs: each program kind
+prefers the pack that avoids an extra flush, and falls back to the other
+kind only when no preferred pack has room. eBPF reuse of a dirty pack is
+harmless since eBPF being privileged does not flush.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/core.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index bba4acd61d4126..de61e1894452ef 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -988,10 +988,10 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool
+ goto found_free_area;
+ /*
+ * cBPF reuse of a dirty pack triggers a flush, so prefer a
+- * clean pack for cBPF. eBPF never flushes, so pick the first
+- * free pack, dirty or clean.
++ * clean pack for cBPF. eBPF never flushes, so steer it to a
++ * dirty pack and keep clean packs free for cBPF.
+ */
+- if (!was_classic || !pack->arch_flush_needed)
++ if (was_classic ^ pack->arch_flush_needed)
+ goto found_free_area;
+ if (!fallback_pack) {
+ fallback_pack = pack;
+--
+2.53.0
+
--- /dev/null
+From 55f010526b57111e1f86243083eb827291f72db9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:24:31 -0700
+Subject: bpf: Prefer packs that won't trigger an IBPB flush on allocation
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit a9b1f19a6a673ba06820898d0f1ad02883ea1639 upstream.
+
+Currently BPF pack allocator picks the chunks from the first available
+pack. While this is okay, it naturally leads to more frequent flushes
+when there are multiple packs in the system that weren't used since the
+last flush.
+
+As an optimization prefer allocating the new programs from packs that
+are unused since last flush. When all packs are dirty, allocation forces
+a flush and marks all packs clean.
+
+Below are some future optimizations ideas:
+
+ 1. Currently, the "dirty" tracking is only done at the pack-level.
+ Flush frequency can further be reduced with chunk-level tracking.
+ This requires a new bitmap per-pack to track the dirty state.
+ 2. IBPB flush is done on all CPUs, even if only a single CPU ran the
+ BPF program. On a system with hundreds of CPUs this could be a
+ major bottleneck forcing hundreds of IPIs to deliver the flush.
+ The solution is to track the CPUs where a BPF program ran, and
+ issue IBPB only on those CPUs.
+ 3. Avoid IBPB when flush is already done at other sources (e.g.
+ context switch).
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/core.c | 27 ++++++++++++++++++++++++---
+ 1 file changed, 24 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 1bf4b8dffe9158..bba4acd61d4126 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -948,8 +948,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
+ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic)
+ {
+ unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size);
+- struct bpf_prog_pack *pack;
+- unsigned long pos;
++ struct bpf_prog_pack *pack, *fallback_pack = NULL;
++ unsigned long pos, fallback_pos = 0;
+ void *ptr = NULL;
+
+ mutex_lock(&pack_mutex);
+@@ -981,8 +981,29 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool
+ list_for_each_entry(pack, &pack_list, list) {
+ pos = bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0,
+ nbits, 0);
+- if (pos < BPF_PROG_CHUNK_COUNT)
++ if (pos >= BPF_PROG_CHUNK_COUNT)
++ continue;
++ /* Flush not enabled, use any pack */
++ if (!static_branch_unlikely(&bpf_pred_flush_enabled))
+ goto found_free_area;
++ /*
++ * cBPF reuse of a dirty pack triggers a flush, so prefer a
++ * clean pack for cBPF. eBPF never flushes, so pick the first
++ * free pack, dirty or clean.
++ */
++ if (!was_classic || !pack->arch_flush_needed)
++ goto found_free_area;
++ if (!fallback_pack) {
++ fallback_pack = pack;
++ fallback_pos = pos;
++ }
++ }
++
++ /* No preferred pack found */
++ if (fallback_pack) {
++ pack = fallback_pack;
++ pos = fallback_pos;
++ goto found_free_area;
+ }
+
+ pack = alloc_new_pack(bpf_fill_ill_insns);
+--
+2.53.0
+
--- /dev/null
+From b05e8192788b05cd84c2a34d2f2520c301ebbed0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:23:41 -0700
+Subject: bpf: Restrict JIT predictor flush to cBPF
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit 0bb99f2cfaae6822d734d69722de30af823efdf3 upstream.
+
+Currently predictor flush on memory reuse is done for all BPF JIT
+allocations, but only cBPF programs can be loaded by an unprivileged user.
+eBPF is privileged by default, and flushing predictors for all CPUs on
+every eBPF reuse penalizes the common case for no security benefit.
+
+eBPF allocations can be frequent on busy systems, only flush predictors
+for cBPF programs. Trampoline and dispatcher allocations also skip the
+flush as they are eBPF-only.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/net/bpf_jit_comp.c | 4 ++--
+ arch/loongarch/net/bpf_jit.c | 5 +++--
+ arch/powerpc/net/bpf_jit_comp.c | 4 ++--
+ arch/riscv/net/bpf_jit_comp64.c | 2 +-
+ arch/riscv/net/bpf_jit_core.c | 3 ++-
+ arch/x86/net/bpf_jit_comp.c | 5 +++--
+ include/linux/filter.h | 5 +++--
+ kernel/bpf/core.c | 13 ++++++++-----
+ kernel/bpf/dispatcher.c | 2 +-
+ 9 files changed, 25 insertions(+), 18 deletions(-)
+
+diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
+index 0816c40fc7af95..9491c987e50c01 100644
+--- a/arch/arm64/net/bpf_jit_comp.c
++++ b/arch/arm64/net/bpf_jit_comp.c
+@@ -2094,7 +2094,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+ image_size = extable_offset + extable_size;
+ ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr,
+ sizeof(u64), &header, &image_ptr,
+- jit_fill_hole);
++ jit_fill_hole, was_classic);
+ if (!ro_header)
+ goto out_off;
+
+@@ -2782,7 +2782,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, jit_fill_hole);
++ return bpf_prog_pack_alloc(size, jit_fill_hole, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
+index 24913dc7f4e835..e14a8aa47fc8ea 100644
+--- a/arch/loongarch/net/bpf_jit.c
++++ b/arch/loongarch/net/bpf_jit.c
+@@ -1762,7 +1762,7 @@ static int invoke_bpf(struct jit_ctx *ctx, struct bpf_tramp_links *tl,
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, jit_fill_hole);
++ return bpf_prog_pack_alloc(size, jit_fill_hole, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+@@ -2228,7 +2228,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+ image_size = prog_size + extable_size;
+ /* Now we know the size of the structure to make */
+ ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, sizeof(u32),
+- &header, &image_ptr, jit_fill_hole);
++ &header, &image_ptr, jit_fill_hole,
++ bpf_prog_was_classic(prog));
+ if (!ro_header)
+ goto out_offset;
+
+diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
+index 53ab97ad607453..73ff8a64bb7fad 100644
+--- a/arch/powerpc/net/bpf_jit_comp.c
++++ b/arch/powerpc/net/bpf_jit_comp.c
+@@ -295,7 +295,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+ alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len;
+
+ fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image,
+- bpf_jit_fill_ill_insns);
++ bpf_jit_fill_ill_insns, bpf_prog_was_classic(fp));
+ if (!fhdr)
+ goto out_err;
+
+@@ -583,7 +583,7 @@ bool bpf_jit_inlines_helper_call(s32 imm)
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns);
++ return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
+index 2f1109dbf105b7..404a98a0fc90e8 100644
+--- a/arch/riscv/net/bpf_jit_comp64.c
++++ b/arch/riscv/net/bpf_jit_comp64.c
+@@ -1321,7 +1321,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, bpf_fill_ill_insns);
++ return bpf_prog_pack_alloc(size, bpf_fill_ill_insns, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
+index 4365d07aaf547c..ce3bd3762e08cc 100644
+--- a/arch/riscv/net/bpf_jit_core.c
++++ b/arch/riscv/net/bpf_jit_core.c
+@@ -109,7 +109,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+ bpf_jit_binary_pack_alloc(prog_size + extable_size,
+ &jit_data->ro_image, sizeof(u32),
+ &jit_data->header, &jit_data->image,
+- bpf_fill_ill_insns);
++ bpf_fill_ill_insns,
++ bpf_prog_was_classic(prog));
+ if (!jit_data->ro_header)
+ goto out_offset;
+
+diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
+index ea9e707e8abffb..ef8b112fd7b692 100644
+--- a/arch/x86/net/bpf_jit_comp.c
++++ b/arch/x86/net/bpf_jit_comp.c
+@@ -3520,7 +3520,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, jit_fill_hole);
++ return bpf_prog_pack_alloc(size, jit_fill_hole, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+@@ -3831,7 +3831,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+ /* allocate module memory for x86 insns and extable */
+ header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
+ &image, align, &rw_header, &rw_image,
+- jit_fill_hole);
++ jit_fill_hole,
++ bpf_prog_was_classic(prog));
+ if (!header)
+ goto out_addrs;
+ prog->aux->extable = (void *) image + roundup(proglen, align);
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index 2a7e6cbbbe1d3f..ea654453e43a34 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -1315,7 +1315,7 @@ void bpf_jit_free(struct bpf_prog *fp);
+ struct bpf_binary_header *
+ bpf_jit_binary_pack_hdr(const struct bpf_prog *fp);
+
+-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns);
++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic);
+ void bpf_prog_pack_free(void *ptr, u32 size);
+
+ static inline bool bpf_prog_kallsyms_verify_off(const struct bpf_prog *fp)
+@@ -1329,7 +1329,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **ro_image,
+ unsigned int alignment,
+ struct bpf_binary_header **rw_hdr,
+ u8 **rw_image,
+- bpf_jit_fill_hole_t bpf_fill_ill_insns);
++ bpf_jit_fill_hole_t bpf_fill_ill_insns,
++ bool was_classic);
+ int bpf_jit_binary_pack_finalize(struct bpf_binary_header *ro_header,
+ struct bpf_binary_header *rw_header);
+ void bpf_jit_binary_pack_free(struct bpf_binary_header *ro_header,
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index f49b9b23f95e60..1b7e74e63bd4bc 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -942,7 +942,7 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
+ return NULL;
+ }
+
+-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic)
+ {
+ unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size);
+ struct bpf_prog_pack *pack;
+@@ -957,7 +957,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+ * safe because cBPF programs (the unprivileged attack surface)
+ * are bounded well below a pack size.
+ */
+- if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ if (was_classic && static_branch_unlikely(&bpf_pred_flush_enabled))
+ pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n");
+ size = round_up(size, PAGE_SIZE);
+ ptr = bpf_jit_alloc_exec(size);
+@@ -989,7 +989,9 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+ pos = 0;
+
+ found_free_area:
+- static_call_cond(bpf_arch_pred_flush)();
++ /* Flush only for cBPF as it may contain a crafted gadget */
++ if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic)
++ static_call_cond(bpf_arch_pred_flush)();
+ bitmap_set(pack->bitmap, pos, nbits);
+ ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
+
+@@ -1149,7 +1151,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr,
+ unsigned int alignment,
+ struct bpf_binary_header **rw_header,
+ u8 **rw_image,
+- bpf_jit_fill_hole_t bpf_fill_ill_insns)
++ bpf_jit_fill_hole_t bpf_fill_ill_insns,
++ bool was_classic)
+ {
+ struct bpf_binary_header *ro_header;
+ u32 size, hole, start;
+@@ -1162,7 +1165,7 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr,
+
+ if (bpf_jit_charge_modmem(size))
+ return NULL;
+- ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns);
++ ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns, was_classic);
+ if (!ro_header) {
+ bpf_jit_uncharge_modmem(size);
+ return NULL;
+diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c
+index b77db7413f8c70..ea2d60dc1feeb7 100644
+--- a/kernel/bpf/dispatcher.c
++++ b/kernel/bpf/dispatcher.c
+@@ -145,7 +145,7 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,
+
+ mutex_lock(&d->mutex);
+ if (!d->image) {
+- d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero);
++ d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero, false);
+ if (!d->image)
+ goto out;
+ d->rw_image = bpf_jit_alloc_exec(PAGE_SIZE);
+--
+2.53.0
+
--- /dev/null
+From 1c643965be4743b7ff9104fb164c62b9fab89477 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:23:56 -0700
+Subject: bpf: Skip redundant IBPB in pack allocator
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit a23c1c5396a91680703360d1ee28a44657c503c4 upstream.
+
+bpf_prog_pack_alloc() issues IBPB on all CPUs on every cBPF allocation,
+even when reusing chunks from an existing pack where no new memory was
+touched since the last IBPB.
+
+Since IBPB on all CPUs is heavy, Dave Hansen suggested to track allocation
+since last IBPB, and only issue IBPB at reuse for the chunks that have not
+seen an IBPB since they were last freed.
+
+Track per-pack whether an IBPB is needed via arch_flush_needed. Set it when
+allocating a chunk, reset on IBPB flush. On reuse, conditionally issue the
+flush. Since IBPB invalidates all BTB entries, clear the flag on all packs
+after flushing.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/core.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 1b7e74e63bd4bc..1bf4b8dffe9158 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -876,6 +876,7 @@ int bpf_jit_add_poke_descriptor(struct bpf_prog *prog,
+ struct bpf_prog_pack {
+ struct list_head list;
+ void *ptr;
++ bool arch_flush_needed;
+ unsigned long bitmap[];
+ };
+
+@@ -928,6 +929,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
+ bpf_fill_ill_insns(pack->ptr, BPF_PROG_PACK_SIZE);
+ bitmap_zero(pack->bitmap, BPF_PROG_PACK_SIZE / BPF_PROG_CHUNK_SIZE);
+
++ if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ pack->arch_flush_needed = true;
+ set_vm_flush_reset_perms(pack->ptr);
+ err = set_memory_rox((unsigned long)pack->ptr,
+ BPF_PROG_PACK_SIZE / PAGE_SIZE);
+@@ -990,8 +993,15 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool
+
+ found_free_area:
+ /* Flush only for cBPF as it may contain a crafted gadget */
+- if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic)
++ if (static_branch_unlikely(&bpf_pred_flush_enabled) &&
++ pack->arch_flush_needed &&
++ was_classic) {
++ struct bpf_prog_pack *p;
++
+ static_call_cond(bpf_arch_pred_flush)();
++ list_for_each_entry(p, &pack_list, list)
++ p->arch_flush_needed = false;
++ }
+ bitmap_set(pack->bitmap, pos, nbits);
+ ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
+
+@@ -1029,6 +1039,9 @@ void bpf_prog_pack_free(void *ptr, u32 size)
+ "bpf_prog_pack bug: missing bpf_arch_text_invalidate?\n");
+
+ bitmap_clear(pack->bitmap, pos, nbits);
++
++ if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ pack->arch_flush_needed = true;
+ if (bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0,
+ BPF_PROG_CHUNK_COUNT, 0) == 0) {
+ list_del(&pack->list);
+--
+2.53.0
+
--- /dev/null
+From d520d5dd207edf3e4d35aa76882de4d9c6c2c48b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:23:10 -0700
+Subject: bpf: Support for hardening against JIT spraying
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit 96cce16e26dd02a8678f1e87f88a4b5cdb63b995 upstream.
+
+The BPF JIT allocator packs many small programs into larger executable
+allocations and reuses space within those allocations as programs are
+loaded and freed. When fresh code is written into space that a previous
+program occupied, an indirect jump into the new program can reuse a branch
+prediction left behind by the old one.
+
+Flush the indirect branch predictors before reusing JIT memory so that
+indirect jumps into a newly written program don't reuse predictions from an
+old program that occupied the same space.
+
+Introduce bpf_arch_pred_flush_enabled static key and bpf_arch_pred_flush
+static call for flushing the branch predictors on JIT memory reuse.
+Architectures that need a flush, can update it to a predictor flush
+function. By default, its a NOP and does not emit any CALL.
+
+Allocations larger than a pack are not covered by this flush. That is safe
+because cBPF programs (the unprivileged attack surface) are bounded well
+below a pack size. Issue a warning if this assumption is ever violated
+while the flush is active.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/filter.h | 10 ++++++++++
+ kernel/bpf/core.c | 19 +++++++++++++++++++
+ 2 files changed, 29 insertions(+)
+
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index 88a241aac36a27..2a7e6cbbbe1d3f 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -21,6 +21,7 @@
+ #include <linux/if_vlan.h>
+ #include <linux/vmalloc.h>
+ #include <linux/sockptr.h>
++#include <linux/static_call.h>
+ #include <linux/u64_stats_sync.h>
+
+ #include <net/sch_generic.h>
+@@ -1291,6 +1292,15 @@ extern long bpf_jit_limit_max;
+
+ typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
+
++/*
++ * Flush the indirect branch predictors before reusing JIT memory, so that
++ * indirect jumps into a newly written program don't reuse predictions left
++ * behind by an old program that occupied the same space.
++ */
++void bpf_arch_pred_flush(void);
++DECLARE_STATIC_CALL(bpf_arch_pred_flush, bpf_arch_pred_flush);
++DECLARE_STATIC_KEY_FALSE(bpf_pred_flush_enabled);
++
+ void bpf_jit_fill_hole_with_zero(void *area, unsigned int size);
+
+ struct bpf_binary_header *
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 6aa2a8b2403065..f49b9b23f95e60 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -20,6 +20,7 @@
+ #include <uapi/linux/btf.h>
+ #include <linux/filter.h>
+ #include <linux/skbuff.h>
++#include <linux/static_call.h>
+ #include <linux/vmalloc.h>
+ #include <linux/prandom.h>
+ #include <linux/bpf.h>
+@@ -883,6 +884,15 @@ void bpf_jit_fill_hole_with_zero(void *area, unsigned int size)
+ memset(area, 0, size);
+ }
+
++DEFINE_STATIC_CALL_NULL(bpf_arch_pred_flush, bpf_arch_pred_flush);
++
++/*
++ * Enabled once bpf_arch_pred_flush points at a real flush routine. Lets the
++ * pack allocator test "is a predictor flush wired up at all" with a cheap
++ * static branch instead of repeatedly querying the static call target.
++ */
++DEFINE_STATIC_KEY_FALSE(bpf_pred_flush_enabled);
++
+ #define BPF_PROG_SIZE_TO_NBITS(size) (round_up(size, BPF_PROG_CHUNK_SIZE) / BPF_PROG_CHUNK_SIZE)
+
+ static DEFINE_MUTEX(pack_mutex);
+@@ -941,6 +951,14 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+
+ mutex_lock(&pack_mutex);
+ if (size > BPF_PROG_PACK_SIZE) {
++ /*
++ * Allocations larger than a pack get their own pages, and
++ * predictors are not flushed for such allocation. This is only
++ * safe because cBPF programs (the unprivileged attack surface)
++ * are bounded well below a pack size.
++ */
++ if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n");
+ size = round_up(size, PAGE_SIZE);
+ ptr = bpf_jit_alloc_exec(size);
+ if (ptr) {
+@@ -971,6 +989,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+ pos = 0;
+
+ found_free_area:
++ static_call_cond(bpf_arch_pred_flush)();
+ bitmap_set(pack->bitmap, pos, nbits);
+ ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
+
+--
+2.53.0
+
--- /dev/null
+From 7d4ef3691eca33dabb0d53abf0f41274bff1c6b6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Jun 2026 23:22:18 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 7935d5663944ee..bab0f3bd4fa8d8 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4728,7 +4728,7 @@ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+ struct perf_event_context *ctx,
+ struct task_struct *task,
+- bool revoke);
++ unsigned long detach_flags);
+
+ /*
+ * Removes all events from the current task that have been marked
+@@ -4755,7 +4755,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
+
+ modified = true;
+
+- perf_event_exit_event(event, ctx, ctx->task, false);
++ perf_event_exit_event(event, ctx, ctx->task, DETACH_GROUP);
+ }
+
+ raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -12900,7 +12900,7 @@ static void __pmu_detach_event(struct pmu *pmu, struct perf_event *event,
+ /*
+ * De-schedule the event and mark it REVOKED.
+ */
+- perf_event_exit_event(event, ctx, ctx->task, true);
++ perf_event_exit_event(event, ctx, ctx->task, DETACH_REVOKE);
+
+ /*
+ * All _free_event() bits that rely on event->pmu:
+@@ -14488,12 +14488,13 @@ static void
+ perf_event_exit_event(struct perf_event *event,
+ struct perf_event_context *ctx,
+ struct task_struct *task,
+- bool revoke)
++ unsigned long detach_flags)
+ {
+ struct perf_event *parent_event = event->parent;
+- unsigned long detach_flags = DETACH_EXIT;
+ unsigned int attach_state;
+
++ detach_flags |= DETACH_EXIT;
++
+ if (parent_event) {
+ /*
+ * Do not destroy the 'original' grouping; because of the
+@@ -14516,8 +14517,8 @@ perf_event_exit_event(struct perf_event *event,
+ sync_child_event(event, task);
+ }
+
+- if (revoke)
+- detach_flags |= DETACH_GROUP | DETACH_REVOKE;
++ if (detach_flags & DETACH_REVOKE)
++ detach_flags |= DETACH_GROUP;
+
+ perf_remove_from_context(event, detach_flags);
+ /*
+@@ -14605,7 +14606,7 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
+ perf_event_task(task, ctx, 0);
+
+ list_for_each_entry_safe(child_event, next, &ctx->event_list, event_entry)
+- perf_event_exit_event(child_event, ctx, exit ? task : NULL, false);
++ perf_event_exit_event(child_event, ctx, exit ? task : NULL, 0);
+
+ mutex_unlock(&ctx->mutex);
+
+--
+2.53.0
+
rust-doctest-fix-incorrect-pattern-in-replacement.patch
rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
futex-requeue-revert-prevent-null-pointer-dereference-in-remove_waiter-on-self-deadlock.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+bpf-support-for-hardening-against-jit-spraying.patch
+x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch
+bpf-restrict-jit-predictor-flush-to-cbpf.patch
+bpf-skip-redundant-ibpb-in-pack-allocator.patch
+bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch
+bpf-prefer-dirty-packs-for-ebpf-allocations.patch
--- /dev/null
+From 8f1d854bb7030ea41378cc781b7222e48978708d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:23:25 -0700
+Subject: x86/bugs: Enable IBPB flush on BPF JIT allocation
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit a3af84b0fa00ead01fcd0e28b5d773ff25990a0d upstream.
+
+Enable hardening against JIT spraying when Spectre-v2 mitigations are in
+use. Specifically, issue an IBPB flush on BPF JIT memory reuse. Skip
+enabling the IBPB flush if the BPF dispatcher is already using a retpoline
+sequence.
+
+This hardening applies only when BPF-JIT is in use. Guard the enabling
+under CONFIG_BPF_JIT so that bugs.c still builds with CONFIG_BPF_JIT=n.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/nospec-branch.h | 4 +++
+ arch/x86/kernel/cpu/bugs.c | 50 +++++++++++++++++++++++++---
+ 2 files changed, 49 insertions(+), 5 deletions(-)
+
+diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
+index 4f4b5e8a157430..b68892e6d58c47 100644
+--- a/arch/x86/include/asm/nospec-branch.h
++++ b/arch/x86/include/asm/nospec-branch.h
+@@ -388,6 +388,10 @@ extern void srso_alias_return_thunk(void);
+ extern void entry_untrain_ret(void);
+ extern void write_ibpb(void);
+
++#ifdef CONFIG_BPF_JIT
++extern void bpf_arch_ibpb(void);
++#endif
++
+ #ifdef CONFIG_X86_64
+ extern void clear_bhb_loop(void);
+ #endif
+diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
+index 83f51cab0b1e39..d9af230c051259 100644
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -16,6 +16,7 @@
+ #include <linux/sched/smt.h>
+ #include <linux/pgtable.h>
+ #include <linux/bpf.h>
++#include <linux/filter.h>
+ #include <linux/kvm_types.h>
+
+ #include <asm/spec-ctrl.h>
+@@ -1651,8 +1652,21 @@ static inline const char *spectre_v2_module_string(void)
+ {
+ return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
+ }
++
++/*
++ * The "retpoline sequence" is the "call;mov;ret" sequence that
++ * replaces normal indirect branch instructions. Differentiate
++ * *the* retpoline sequence from the LFENCE-prefixed indirect
++ * branches that simply use the retpoline infrastructure.
++ */
++static inline bool retpoline_seq_enabled(void)
++{
++ return boot_cpu_has(X86_FEATURE_RETPOLINE) && !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE);
++}
++
+ #else
+ static inline const char *spectre_v2_module_string(void) { return ""; }
++static inline bool retpoline_seq_enabled(void) { return false; }
+ #endif
+
+ #define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n"
+@@ -2095,8 +2109,7 @@ static void __init bhi_apply_mitigation(void)
+ return;
+
+ /* Retpoline mitigates against BHI unless the CPU has RRSBA behavior */
+- if (boot_cpu_has(X86_FEATURE_RETPOLINE) &&
+- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) {
++ if (retpoline_seq_enabled()) {
+ spec_ctrl_disable_kernel_rrsba();
+ if (rrsba_disabled)
+ return;
+@@ -2238,6 +2251,27 @@ static void __init spectre_v2_update_mitigation(void)
+ pr_info("%s\n", spectre_v2_strings[spectre_v2_enabled]);
+ }
+
++#ifdef CONFIG_BPF_JIT
++static void __bpf_arch_ibpb(void *unused)
++{
++ write_ibpb();
++}
++
++void bpf_arch_ibpb(void)
++{
++ on_each_cpu(__bpf_arch_ibpb, NULL, 1);
++}
++
++static bool __init cpu_wants_ibpb_bpf(void)
++{
++ /* A genuine retpoline already neutralizes ring0 indirect predictions */
++ if (retpoline_seq_enabled())
++ return false;
++
++ return boot_cpu_has(X86_FEATURE_IBPB);
++}
++#endif
++
+ static void __init spectre_v2_apply_mitigation(void)
+ {
+ if (spectre_v2_enabled == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
+@@ -2314,6 +2348,14 @@ static void __init spectre_v2_apply_mitigation(void)
+ setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
+ pr_info("Enabling Restricted Speculation for firmware calls\n");
+ }
++
++#ifdef CONFIG_BPF_JIT
++ if (cpu_wants_ibpb_bpf()) {
++ static_call_update(bpf_arch_pred_flush, bpf_arch_ibpb);
++ static_branch_enable(&bpf_pred_flush_enabled);
++ pr_info("Enabling IBPB for BPF\n");
++ }
++#endif
+ }
+
+ static void update_stibp_msr(void * __unused)
+@@ -3490,9 +3532,7 @@ static const char *spectre_bhi_state(void)
+ return "; BHI: BHI_DIS_S";
+ else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP))
+ return "; BHI: SW loop, KVM: SW loop";
+- else if (boot_cpu_has(X86_FEATURE_RETPOLINE) &&
+- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) &&
+- rrsba_disabled)
++ else if (retpoline_seq_enabled() && rrsba_disabled)
+ return "; BHI: Retpoline";
+ else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_VMEXIT))
+ return "; BHI: Vulnerable, KVM: SW loop";
+--
+2.53.0
+