summaryrefslogtreecommitdiff
path: root/kernel/futex/core.c
AgeCommit message (Collapse)AuthorFilesLines
11 daystreewide: refresh kmalloc_obj() conversionsKees Cook1-3/+3
This is another run of the Coccinelle script for converting kmalloc() family of allocations to kmalloc_obj() via the existing rules in scripts/coccinelle/api/kmalloc_objs.cocci This catches both the set of kmalloc() uses added since the first kmalloc_obj() conversions in v7.0 and adds a large group missed in the first pass due to Coccinelle not interacting well with the cleanup.h scoped_...() family of macros[1]. I worked around this with spatch's "--macro-file" argument to a file with all the scoped_...() macros mapped to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control flow indicator I could find. Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc, riscv, and s390 with no new warnings. Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1] Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2] Signed-off-by: Kees Cook <kees+treewide@kernel.org>
2026-08-22Merge tag 'locking-urgent-2026-08-22' of ↵Linus Torvalds1-30/+74
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull futex fixes from Ingo Molnar: - Enforce that the private futex owner shares the mm when attaching (Kyle Zeng, Thomas Gleixner) - Fix race on the initial mm->futex.phash.ref allocation (Hyunwoo Kim) - Fix might_sleep() warning in futex_pivot_pending() (Peter Zijlstra) * tag 'locking-urgent-2026-08-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: futex: Fix might_sleep() warning in futex_pivot_pending() futex: Fix race on the initial mm->futex.phash.ref allocation futex: Clean up the redundant exit/exec functions futex/pi: Plug private futex exec() race futex: Sanitize and document task_struct::futex::state transitions futex/pi: Reject cross-mm private futex owners
2026-08-20futex: Fix might_sleep() warning in futex_pivot_pending()Peter Zijlstra1-1/+26
A younger me put a WARN in might_sleep() to warn about nested sleep loops. This younger me also build a wait-loop variant that can deal with it. This wait-loop variant doesn't have all the fancy wrappers, since it isn't used much. It also lacks wait-bit support. Add the wait-bit support and use it to fix the nested wait issue. Fixes: 8e7ff730dd96 ("futex: Fix race in futex_pivot_pending() during private hash resize") Reported-by: syzbot+350a93852ac854927f45@syzkaller.appspotmail.com Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Link: https://patch.msgid.link/20260820074927.GH1246887@noisy.programming.kicks-ass.net Closes: https://syzkaller.appspot.com/bug?extid=350a93852ac854927f45
2026-08-18Merge tag 'locking-futex-2026-08-17' of ↵Linus Torvalds1-2/+1
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull futex updates from Thomas Gleixner: - Improvements to various futex self tests: - Conversion to the selftest harness - Provide and use thread creation and synchronization helpers to reduce the dependency on delays, which tend to fail on loaded test systems - New tests for validating owner exit scenarios for robust and PI futexes - Runtime detect supported features and skip the tests if the kernel has no support - A few minor fixes * tag 'locking-futex-2026-08-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: selftests/futex: Give circular-list nodes static storage selftests/futex: Use thread synchronization helpers instead of usleep() selftests/futex: Provide thread creation and synchronization helpers selftests/futex: Dynamically skip unsupported tests selftests/futex: Add FUTEX_LOCK_PI owner-exiting coverage selftests/futex: Migrate robust_list to harness selftests/futex: Migrate futex_priv_hash to harness selftests/futex: Migrate futex_numa_mpol to harness selftests/futex: Migrate futex_requeue_pi_signal_restart to harness selftests/futex: Migrate futex_requeue_pi_mismatched_ops to harness selftests/futex: Migrate futex_requeue_pi to harness selftests/futex: Migrate futex_requeue to harness selftests/futex: Migrate futex_wait_uninitialized_heap to harness selftests/futex: Migrate futex_wait_private_mapped_file to harness selftests/futex: Migrate futex_wait to harness selftests/futex: Correct validation logic in waitv selftests/futex: Migrate functional tests to harness selftests/futex: Remove static keyword from 'head' futex: Remove unnecessary NULL check before kvfree() selftests/rseq: Replace glibc-specific __GNUC_PREREQ with portable check
2026-08-18Merge tag 'locking-core-2026-08-17' of ↵Linus Torvalds1-22/+36
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull locking updates from Ingo Molnar: "Futexes: - Use runtime constants for futex_hash computation (K Prateek Nayak, Peter Zijlstra) - Optimise the size check get_futex_key() (Sebastian Andrzej Siewior) - Avoid private hash use-after-free on final put (Felix Hoffmann) - Tell kmemleak we're not leaking __futex_queues (Peter Zijlstra) Rust integration updates: - Implement refcounted interrupt disable and SpinLockIrq for Rust (Boqun Feng, Heiko Carstens, Joel Fernandes, Lyude Paul) - Rust sync: add helpers for mb, dma_mb and friends; add generic memory barriers and use LKMM atomics instead of Rust atomics in the revocable code (Gary Guo) - Add abstraction and integrate synchronize_rcu() (Philipp Stanner) Lock debugging: - Add qspinlock contended_release tracepoint (Dmitry Ilvokhin, Peter Zijlstra) - Enable the printing of held locks of remote running tasks and print task CPU (Ingo Molnar) - percpu-rwsem: Annotate intentional data race in readers_active_check() (Sun Shaojie) Misc fixes and updates by Boqun Feng, Peter Zijlstra, Fangrui Song, Naveen Kumar Chaudhary and Thomas Huth" * tag 'locking-core-2026-08-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (44 commits) rust: sync: Introduce SpinLockIrq::lock_with() and friends rust: sync: Add SpinLockIrq rust: sync: Use super::* in spinlock.rs rust: helper: Add spin_{un,}lock_irq_{enable,disable}() helpers rust: Introduce interrupt module s390/preempt: Enable HAS_SEPARATE_PREEMPT_RESCHED_BITS arm64: sched/preempt: Enable HAS_SEPARATE_PREEMPT_RESCHED_BITS preempt: Introduce HAS_SEPARATE_PREEMPT_RESCHED_BITS sched: Avoid signed comparison of preempt_count() in __cant_migrate() sched: Remove the unused preempt_offset parameter of __cant_sleep() locking: Switch to _irq_{disable,enable}() variants in cleanup guards irq: Add KUnit test for refcounted interrupt enable/disable irq,spin_lock: Add counted interrupt disabling/enabling openrisc: Include <linux/cpumask.h> in smp.h preempt: Introduce __preempt_count_{sub,add}_return() preempt: Introduce HARDIRQ_DISABLE_BITS preempt: Track NMI nesting to separate per-CPU counter futex: Tell kmemleak we're not leaking __futex_queues x86/paravirt: Trace contended_release on unlock tracing/lock: Use TRACE_EVENT_FN() for contended_release ...
2026-08-16futex: Fix race on the initial mm->futex.phash.ref allocationHyunwoo Kim1-6/+10
futex_hash_allocate() allocates mm->futex.phash.ref without any locking. Commit d9b05321e21e ("futex: Move futex_hash_free() back to __mmput()") moved the allocation here and assumed that the process has just a single thread at this point. Commit ee9dce44362b ("futex: Drop CLONE_THREAD requirement for private default hash alloc") widened need_futex_hash_allocate_default() to cover any CLONE_VM clone, but left out vfork because the parent is suspended and cannot race. That no longer holds once vfork is nested. If a vfork child calls vfork again and is then killed with SIGKILL, the parent is released from its vfork wait and runs concurrently with the grandchild in the same mm. Neither of them went through futex_hash_allocate_default(). When both call prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_SET_SLOTS) at the same time, each one sees mm->futex.phash.ref as NULL and stores its own percpu counter. Only the last store survives. The counter stored first is no longer reachable from the mm, so the references on it are not seen by __futex_ref_atomic_end(). A private hash that still has references is then considered dead and freed, and a task that still holds one of its buckets writes into freed memory in futex_q_lock(). Store the counter once with cmpxchg() and let the loser free_percpu() its own. The initial reference has to be taken before the store, otherwise another task can install a private hash while the counter is still 0. Fixes: d9b05321e21e ("futex: Move futex_hash_free() back to __mmput()") Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/ansrpP4ImE1MaBY9@v4bel
2026-08-16futex: Clean up the redundant exit/exec functionsThomas Gleixner1-20/+17
futex_exit_release() and futex_exec_release() are identical now. That means also exit_mm_release() and exec_mm_release() are identical. Consolidate the whole lot and remove the redundant copies. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Reviewed-by: Kyle Zeng <kylebot@openai.com> Acked-by: Peter Zijlstra <peterz@infradead.org>
2026-08-16futex/pi: Plug private futex exec() raceThomas Gleixner1-17/+37
The check for private futexes whether the waiter's mm, which is stored in the futex_key and copied into the pi_state, is the same as the owner's mm is not sufficient for exec(). exec() has a gap where the mm check fails to give the correct answer: exec() ... exec_release_mm() futex_exec_release() tsk::futex::exit_state = EXITING; cleanup_robust_list(); 1) tsk::futex::exit_state = OK; ... old_mm = tsk::mm; 2) tsk::mm = ->mm; Between #1 and #2 the check for the mm is wrong as that mm is about to be swapped out and eventually freed. Plug this gap by: 1) Setting tsk::futex::exit_state to FUTEX_STATE_DEAD in futex_exec_release() 2) Setting tsk::futex::exit_state to FUTEX_STATE_OK after the mm has been switched. From a futex point of view the task is dead after it finished the robust list cleanup up to the point where it sets the state to OK again. Fixes: 80367ad01d93 ("futex: Add basic infrastructure for local task local hash") Signed-off-by: Thomas Gleixner <tglx@kernel.org> Reviewed-by: Kyle Zeng <kylebot@openai.com> Acked-by: Peter Zijlstra <peterz@infradead.org> Cc: stable@vger.kernel.org
2026-08-10futex: Sanitize and document task_struct::futex::state transitionsThomas Gleixner1-5/+3
The futex state is used to prevent a waiter from attaching to the lock owner while the owner runs the futex cleanup in exit() or exec(). Only the state transition from FUTEX_STATE_OK to FUTEX_STATE_EXITING must be done with the task's pi_lock held, the transition away from FUTEX_STATE_EXITING has no serialization requirements on the writer side, but it's completely non obvious why. It's magically protected by exit_pi_state(), which operates under tsk::pi_lock, as that's the state which has to be correct when the waiter observes the new state. OTOH, taking the pi_lock in futex_cleanup_end() is not a performance issue because at that point the lock should be uncontended in the vast majority of cases. Aside of that the handling of FUTEX_STATE_EXITING in attach_to_pi_owner() and handle_exit_race() is confusing at best. Protect the store in futex_cleanup_end() with tsk::pi_lock, handle FUTEX_STATE_EXITING in attach_to_pi_owner() explicitly and document how this is supposed to work. Reported-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Reviewed-by: Kyle Zeng <kylebot@openai.com> Acked-by: Peter Zijlstra <peterz@infradead.org> Cc: stable@vger.kernel.org
2026-08-08futex: Tell kmemleak we're not leaking __futex_queuesPeter Zijlstra1-0/+2
Kmemleak doesn't know about runtime_const stuff and figures we're leaking __futex_queues. So add this little annotation to tell it all is well. Fixes: b78b0b658252 ("futex: Use runtime constants for __futex_hash() hot path") Reported-by: kernel test robot <oliver.sang@intel.com> Closes: https://lore.kernel.org/oe-lkp/202608071053.6db6276e-lkp@intel.com Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260807152353.GP687043@noisy.programming.kicks-ass.net
2026-08-07futex: Fix race in futex_pivot_pending() during private hash resizeYao Kai1-3/+4
A task performing a custom private hash resize can remain blocked in uninterruptible sleep indefinitely. The hung-task detector reports: INFO: task futex-resizer:314 blocked for more than 10 seconds. task:futex-resizer state:D stack:14824 pid:314 tgid:312 ppid:311 Call Trace: __schedule+0x521/0xf30 schedule+0x22/0xa0 futex_hash_allocate+0x3db/0x490 __do_sys_prctl+0x6f5/0xbd0 do_syscall_64+0xf9/0x530 entry_SYSCALL_64_after_hwframe+0x77/0x7f Kernel panic - not syncing: hung_task: blocked tasks futex_pivot_pending() allows the resize request to continue when either no replacement hash is pending (hash_new == NULL) or the current hash reference count has reached zero. After the final-reference wake, another futex task can complete the pivot between the two observations: T1 T2 futex_hash_allocate() wait_var_event(mm, ...) futex_pivot_pending(mm) hash_new != NULL futex_hash() futex_ref_get(old) -> false futex_pivot_hash(mm) hash_new = NULL __futex_pivot_hash(mm, new) rcu_assign_pointer(hash, new) fph = rcu_dereference(hash) /* new */ futex_ref_is_dead(fph) -> false schedule() The pivot changes the state from hash_new != NULL with a dead current hash to hash_new == NULL with a live current hash. Because futex_pivot_pending() reads hash_new and hash without serialization, the resize task can observe hash_new in the pre-pivot state and hash in the post-pivot state, causing futex_pivot_pending() to return false even though the pivot has completed. The task then goes to sleep after the wakeup has already been consumed. Serialize state reads in futex_pivot_pending() using futex_mm_phash::lock. This guarantees that futex_pivot_pending() observes hash_new and hash atomically, eliminating the race condition. Fixes: bd54df5ea7ca ("futex: Allow to resize the private local hash") Suggested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Yao Kai <yaokai34@huawei.com> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260804125530.3933754-1-yaokai34@huawei.com
2026-08-04futex: Avoid private hash use-after-free on final putFelix Hoffmann1-2/+8
futex_private_hash_put() drops the reference to fph before evaluating fph->mm for wake_up_var(). futex_ref_put() enables preemption again before returning. If that put drops the final reference and the task is preempted, another task can pivot to the replacement hash and free the old hash after an RCU grace period. The first task then reads fph->mm from the freed allocation when it resumes. KASAN reports a slab-use-after-free in futex_private_hash_put(), with the read at offset 24 in a freed kmalloc-512 allocation. The allocation and free stacks point to futex_hash_allocate() and the RCU free path, respectively. Load the mm pointer while the fph reference is still held and pass the saved value to wake_up_var(). wake_up_var() uses the pointer as a waitqueue key and does not dereference the mm through it. Fixes: bd54df5ea7ca ("futex: Allow to resize the private local hash") Signed-off-by: Felix Hoffmann <f3lix.dev@gmx.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260731155024.1150011-1-f3lix.dev@gmx.de
2026-08-02futex: Prevent robust futex exit race some moreKeno Fischer1-27/+58
A robust futex unlock stores 0 over the whole futex value - wiping FUTEX_WAITERS - and wakes a single waiter. That wakeup is a one-shot notification: the protocol relies on its recipient to either acquire the futex (and eventually unlock while aware of the remaining contention) or re-arm FUTEX_WAITERS before sleeping again. If the woken waiter is killed before it can do either, the kernel must jump in and wake the next task down the line. This is a known complication of the futex protocol with a previous partial fix in commit ca16d5bee598 ("futex: Prevent robust futex exit race"). Unfortunately, that fix is insufficient. If a third task re-acquired the futex through the uncontended fast path in the meantime, the notification is lost: robust exit processing sees that it is owned by another task and does nothing, while the new owner sees no FUTEX_WAITERS when it unlocks and wakes nobody. The remaining waiters sleep forever behind a free futex: A owns the futex, B and C sleep in FUTEX_WAIT uval == A | FUTEX_WAITERS A robust unlock: store 0, FUTEX_WAKE(1) wakes B uval == 0 D fast path acquire: cmpxchg(0 -> D) uval == D, no FUTEX_WAITERS B killed before acting on the wakeup B exit walk, pending op: owner D != B -> no action D unlock: no FUTEX_WAITERS -> no wake C sleeps forever This is clearly a shortcoming in the implementation, which fails to keep the FUTEX_WAITERS bit consistent. Work around this by augmenting the robust list exit processing to also perform the extra wakeup if the futex word is owned by another thread but FUTEX_WAITERS is not set. This does not fix the problem of a non-contended take over/release and free sequence, which has been discussed for years and has been addressed by commit 3ca9595d9fb6 ("futex: Add support for unlocking robust futexes") and subsequent changes, but failed to take the problem described above into account. A more complete solution which is based on the in kernel unlock of contended robust futexes has been discussed in the context of this change and should show up in mainline sooner than later. [ tglx: Amend change log slightly and fixup coding style ] Fixes: ca16d5bee598 ("futex: Prevent robust futex exit race") Signed-off-by: Keno Fischer <keno@juliahub.com> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Assisted-by: ClaudeCode:claude-fable-5 tla+ Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260730194705.38981-1-keno@juliacomputing.com
2026-07-29futex: Optimise the size check get_futex_key()Sebastian Andrzej Siewior1-1/+1
The futex address must be naturally aligned and this is checked via "address % size" where `address' is the supplied address and `size' is the expected size of futex. It is guaranteed that `size' is power of two but the compiler does not see it and creates here a `div' operation (x86, arm, gcc-15). We can take advantage of the pow2 property and rewrite it as "address & (size-1)". As per testing, the command |perf bench futex hash -f 1 -b 16384 -t 1 -r 30 improved from | [thread 0] futex: 0x5619f931f740 [ 7001583 ops/sec ] to | [thread 0] futex: 0x55da173e5740 [ 7376137 ops/sec ] or by 5.3% Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260701161736.xYYizA0e@linutronix.de
2026-07-29futex: Use runtime constants for __futex_hash() hot pathPeter Zijlstra1-19/+25
Runtime constify the read-only after init data __futex_shift(shift_32), __futex_mask(mask_32), and __futex_queues(ptr) used in __futex_hash() hot path to avoid referencing global variable. This also allows __futex_queues to be allocated dynamically to "nr_node_ids" slots instead of reserving config dependent MAX_NUMNODES (1 << CONFIG_NODES_SHIFT) worth of slots upfront. Runtime constants are initialized before their first access and runtime_const_init() provides necessary barrier to ensure subsequent accesses are not reordered against their initialization. No functional changes intended. perf bench futex on a 3rd Gen EPYC (2 x 64C/128T): +----------------+-----------+-----------+-----------+--------------+ | Benchmark | Kernel 1 | Kernel 2 | Unit | % Improvement| | | (avg/5) | (avg/5) | | (K2 vs K1) | +----------------+-----------+-----------+-----------+--------------+ | Wake-parallel | 0.01614 | 0.00456 | ms | +71.75% | | Requeue | 0.26394 | 0.24644 | ms | +6.63% | | Lock-pi | 34.0 | 57.2 | ops/sec | +68.24% | +----------------+-----------+-----------+-----------+--------------+ Performance testing on a 144-thread Intel(R) Xeon(R) CPU E7-8890 v3 (4 NUMA nodes): +-------------------------------------------------------------+ | perf bench futex hash -b 0 | +----------------------+------------+------------+------------+ | Configuration | As-is | Patched | Delta | +----------------------+------------+------------+------------+ | 1 thread, 1 futex | 6,449,632 | 6,532,004 | +1.28% | | 144 threads, 1024 fx | 2,111,486 | 2,139,685 | +1.34% | +----------------------+------------+------------+------------+i [ prateek: Dynamically allocate __futex_queues, mark the global data __ro_after_init since they are constified after futex_init(). ] Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> # MAX_NUMNODES bloat Signed-off-by: K Prateek Nayak <kprateek.nayak@amd.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com> Tested-by: Charlie Jenkins <thecharlesjenkins@gmail.com> Link: https://patch.msgid.link/20260227161841.GH606826@noisy.programming.kicks-ass.net Link: https://patch.msgid.link/20260728052540.4728-9-kprateek.nayak@amd.com
2026-07-05futex: Remove unnecessary NULL check before kvfree()Vasileios Almpanis1-2/+1
The NULL check before kvfree() is unnecessary and triggers a Coccinelle warning, since kvfree() handles NULL arguments internally. Reported by ifnullfree.cocci Coccinelle semantic patch script. Signed-off-by: Vasileios Almpanis <vasilisalmpanis@gmail.com> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Reviewed-by: André Almeida <andrealmeid@igalia.com> Link: https://patch.msgid.link/20260630133530.2577832-1-vasilisalmpanis@gmail.com
2026-06-11futex: Optimize futex hash bucket access patternsPeter Zijlstra1-79/+32
Breno reported significant c2c HITM in a futex hash heavy workload. It turns out that the hash bucket to private hash table reverse pointer (futex_hash_bucket::priv) was to blame. Notably when the hash buckets are heavily contended, the: 'fph = bh->priv;' load in futex_hash() will typically miss and consequently become quite expensive. Since this load in particular is quite superfluous, removing it is fairly straight forward. However, removing it does not in fact achieve anything much. The pain moves to the next user, notably: futex_hash_put(). Therefore rework the whole private hash refcounting to avoid needing this back pointer (and removing it). Instead of passing around 'struct futex_hash_bucket *hb', pass around a new structure that contains it and the related 'struct futex_private_hash *fph' pointer in tandem. Funnily this turns out to remove more code than it adds and significantly improves futex hash performance (as measured by 'perf bench futex hash'): SKL dual socket 112 threads: Baseline Patched shared (16k) 1571857 1641435 + 4.4% autosize (512) 646390 903371 +39.7% -b 256 464395 587014 +26.4% -b 512 715687 995943 +39.2% -b 1024 995085 1396328 +40.3% -b 2048 1293114 1668395 +29.0% -b 4096 2124438 2240228 + 5.5% Zen3 dual socket 256 threads: Baseline Patched shared (16k) 1275840 1381279 + 8.2% autosize (512) 1252745 1482179 +18.3% -b 256 856274 955455 +11.5% -b 512 1267490 1544010 +21.8% -b 1024 1424013 1625424 +14.1% -b 2048 1505181 1669342 +10.9% -b 4096 1465993 1688932 +15.2% AMD EPYC 9D64 (Zen4, single socket) 176 threads: Baseline Patched Delta shared (16k) 1,230,599 1,368,655 +11.2% autosize (1024) 1,285,440 1,556,946 +21.1% -b 256 1,341,471 1,520,303 +13.3% -b 512 1,438,330 1,599,319 +11.2% -b 1024 1,443,772 1,622,493 +12.4% -b 2048 1,472,108 1,643,975 +11.7% -b 4096 1,333,098 1,570,897 +17.8% Reported-by: Breno Leitao <leitao@debian.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Tested-by: Breno Leitao <leitao@debian.org> Tested-by: Thomas Gleixner <tglx@kernel.org> Link: https://patch.msgid.link/20260610135510.GB1430057@noisy.programming.kicks-ass.net
2026-06-03futex: Provide infrastructure to plug the non contended robust futex unlock raceThomas Gleixner1-0/+18
When the FUTEX_ROBUST_UNLOCK mechanism is used for unlocking (PI-)futexes, then the unlock sequence in user space looks like this: 1) robust_list_set_op_pending(mutex); 2) robust_list_remove(mutex); lval = gettid(); 3) if (atomic_try_cmpxchg(&mutex->lock, lval, 0)) 4) robust_list_clear_op_pending(); else 5) sys_futex(OP | FUTEX_ROBUST_UNLOCK, ....); That still leaves a minimal race window between #3 and #4 where the mutex could be acquired by some other task, which observes that it is the last user and: 1) unmaps the mutex memory 2) maps a different file, which ends up covering the same address When then the original task exits before reaching #5 then the kernel robust list handling observes the pending op entry and tries to fix up user space. In case that the newly mapped data contains the TID of the exiting thread at the address of the mutex/futex the kernel will set the owner died bit in that memory and therefore corrupt unrelated data. On X86 this boils down to this simplified assembly sequence: mov %esi,%eax // Load TID into EAX xor %ecx,%ecx // Set ECX to 0 #3 lock cmpxchg %ecx,(%rdi) // Try the TID -> 0 transition .Lstart: jnz .Lend #4 movq %rcx,(%rdx) // Clear list_op_pending .Lend: If the cmpxchg() succeeds and the task is interrupted before it can clear list_op_pending in the robust list head (#4) and the task crashes in a signal handler or gets killed then it ends up in do_exit() and subsequently in the robust list handling, which then might run into the unmap/map issue described above. This is only relevant when user space was interrupted and a signal is pending. The fix-up has to be done before signal delivery is attempted because: 1) The signal might be fatal so get_signal() ends up in do_exit() 2) The signal handler might crash or the task is killed before returning from the handler. At that point the instruction pointer in pt_regs is not longer the instruction pointer of the initially interrupted unlock sequence. The right place to handle this is in __exit_to_user_mode_loop() before invoking arch_do_signal_or_restart() as this covers obviously both scenarios. As this is only relevant when the task was interrupted in user space, this is tied to RSEQ and the generic entry code as RSEQ keeps track of user space interrupts unconditionally even if the task does not have a RSEQ region installed. That makes the decision very lightweight: if (current->rseq.user_irq && within(regs, csr->unlock_ip_range)) futex_fixup_robust_unlock(regs, csr); futex_fixup_robust_unlock() then invokes a architecture specific function to return the pending op pointer or NULL. The function evaluates the register content to decide whether the pending ops pointer in the robust list head needs to be cleared. Assuming the above unlock sequence, then on x86 this decision is the trivial evaluation of the zero flag: return regs->eflags & X86_EFLAGS_ZF ? regs->dx : NULL; Other architectures might need to do more complex evaluations due to LLSC, but the approach is valid in general. The size of the pointer is determined from the matching range struct, which covers both 32-bit and 64-bit builds including COMPAT. The unlock sequence is going to be placed in the VDSO so that the kernel can keep everything synchronized, especially the register usage. The resulting code sequence for user space is: if (__vdso_futex_robust_list$SZ_try_unlock(lock, tid, &pending_op) != tid) err = sys_futex($OP | FUTEX_ROBUST_UNLOCK,....); Both the VDSO unlock and the kernel side unlock ensure that the pending_op pointer is always cleared when the lock becomes unlocked. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: André Almeida <andrealmeid@igalia.com> Link: https://patch.msgid.link/20260602090535.773669210@kernel.org
2026-06-03futex: Add robust futex unlock IP rangeThomas Gleixner1-9/+37
There will be a VDSO function to unlock robust futexes in user space. The unlock sequence is racy vs. clearing the list_pending_op pointer in the tasks robust list head. To plug this race the kernel needs to know the instruction window. As the VDSO is per MM the addresses are stored in mm_struct::futex. Architectures which implement support for this have to update these addresses when the VDSO is (re)mapped and indicate the pending op pointer size which is matching the IP. Arguably this could be resolved by chasing mm->context->vdso->image, but that's architecture specific and requires to touch quite some cache lines. Having it in mm::futex reduces the cache line impact and avoids having yet another set of architecture specific functionality. To support multi size robust list applications (gaming) this provides two ranges when COMPAT is enabled. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: André Almeida <andrealmeid@igalia.com> Link: https://patch.msgid.link/20260602090535.718926819@kernel.org
2026-06-03futex: Add support for unlocking robust futexesThomas Gleixner1-2/+51
Unlocking robust non-PI futexes happens in user space with the following sequence: 1) robust_list_set_op_pending(mutex); 2) robust_list_remove(mutex); lval = 0; 3) lval = atomic_xchg(lock, lval); 4) if (lval & WAITERS) 5) sys_futex(WAKE,....); 6) robust_list_clear_op_pending(); That opens a window between #3 and #6 where the mutex could be acquired by some other task which observes that it is the last user and: A) unmaps the mutex memory B) maps a different file, which ends up covering the same address When the original task exits before reaching #6 then the kernel robust list handling observes the pending op entry and tries to fix up user space. In case that the newly mapped data contains the TID of the exiting thread at the address of the mutex/futex the kernel will set the owner died bit in that memory and therefore corrupting unrelated data. PI futexes have a similar problem both for the non-contented user space unlock and the in kernel unlock: 1) robust_list_set_op_pending(mutex); 2) robust_list_remove(mutex); lval = gettid(); 3) if (!atomic_try_cmpxchg(lock, lval, 0)) 4) sys_futex(UNLOCK_PI,....); 5) robust_list_clear_op_pending(); Address the first part of the problem where the futexes have waiters and need to enter the kernel anyway. Add a new FUTEX_ROBUST_UNLOCK flag, which is valid for the sys_futex() FUTEX_UNLOCK_PI, FUTEX_WAKE, FUTEX_WAKE_BITSET operations. This deliberately omits FUTEX_WAKE_OP from this treatment as it's unclear whether this is needed and there is no usage of it in glibc either to investigate. For the futex2 syscall family this needs to be implemented with a new syscall. The sys_futex() case [ab]uses the @uaddr2 argument to hand the pointer to robust_list_head::list_pending_op into the kernel. This argument is only evaluated when the FUTEX_ROBUST_UNLOCK bit is set and is therefore backward compatible. This is an explicit argument to avoid the lookup of the robust list pointer and retrieving the pending op pointer from there. User space has the pointer already available so it can just put it into the @uaddr2 argument. Aside of that this allows the usage of multiple robust lists in the future without any changes to the internal functions as they just operate on the provided pointer. This requires a second flag FUTEX_ROBUST_LIST32 which indicates that the robust list pointer points to an u32 and not to an u64. This is required for two reasons: 1) sys_futex() has no compat variant 2) The gaming emulators use both both 64-bit and compat 32-bit robust lists in the same 64-bit application As a consequence 32-bit applications have to set this flag unconditionally so they can run on a 64-bit kernel in compat mode unmodified. 32-bit kernels return an error code when the flag is not set. 64-bit kernels will happily clear the full 64 bits if user space fails to set it. In case of FUTEX_UNLOCK_PI this clears the robust list pending op when the unlock succeeded. In case of errors, the user space value is still locked by the caller and therefore the above cannot happen. In case of FUTEX_WAKE* this does the unlock of the futex in the kernel and clears the robust list pending op when the unlock was successful. If not, the user space value is still locked and user space has to deal with the returned error. That means that the unlocking of non-PI robust futexes has to use the same try_cmpxchg() unlock scheme as PI futexes. If the clearing of the pending list op fails (fault) then the kernel clears the registered robust list pointer if it matches to prevent that exit() will try to handle invalid data. That's a valid paranoid decision because the robust list head sits usually in the TLS and if the TLS is not longer accessible then the chance for fixing up the resulting mess is very close to zero. The problem of non-contended unlocks still exists and will be addressed separately. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: André Almeida <andrealmeid@igalia.com> Link: https://patch.msgid.link/20260602090535.670514505@kernel.org
2026-06-03futex: Provide UABI defines for robust list entry modifiersThomas Gleixner1-28/+25
The marker for PI futexes in the robust list is a hardcoded 0x1 which lacks any sensible form of documentation. Provide proper defines for the bit and the mask and fix up the usage sites. Thereby convert the boolean pi argument into a modifier argument, which allows new modifier bits to be trivially added and conveyed. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Reviewed-by: André Almeida <andrealmeid@igalia.com> Link: https://patch.msgid.link/20260602090535.458758556@kernel.org
2026-06-03futex: Move futex related mm_struct data into a structThomas Gleixner1-72/+61
Having all these members in mm_struct along with the required #ifdeffery is annoying, does not allow efficient initializing of the data with memset() and makes extending it tedious. Move it into a data structure and fix up all usage sites. The extra struct for the private hash is intentional to make integration of other conditional mechanisms easier in terms of initialization and separation. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260602090535.407756793@kernel.org
2026-06-03futex: Make futex_mm_init() voidThomas Gleixner1-2/+1
Nothing fails there. Mop up the leftovers of the early version of this, which did an allocation. While at it clean up the stubs and the #ifdef comments to make the header file readable. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260602090535.356789395@kernel.org
2026-06-03futex: Move futex task related data into a structThomas Gleixner1-29/+30
Having all these members in task_struct along with the required #ifdeffery is annoying, does not allow efficient initializing of the data with memset() and makes extending it tedious. Move it into a data structure and fix up all usage sites. Signed-off-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Reviewed-by: André Almeida <andrealmeid@igalia.com> Link: https://patch.msgid.link/20260602090535.308220888@kernel.org
2026-04-14Merge tag 'locking-core-2026-04-13' of ↵Linus Torvalds1-3/+6
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull locking updates from Ingo Molnar: "Mutexes: - Add killable flavor to guard definitions (Davidlohr Bueso) - Remove the list_head from struct mutex (Matthew Wilcox) - Rename mutex_init_lockep() (Davidlohr Bueso) rwsems: - Remove the list_head from struct rw_semaphore and replace it with a single pointer (Matthew Wilcox) - Fix logic error in rwsem_del_waiter() (Andrei Vagin) Semaphores: - Remove the list_head from struct semaphore (Matthew Wilcox) Jump labels: - Use ATOMIC_INIT() for initialization of .enabled (Thomas Weißschuh) - Remove workaround for old compilers in initializations (Thomas Weißschuh) Lock context analysis changes and improvements: - Add context analysis for rwsems (Peter Zijlstra) - Fix rwlock and spinlock lock context annotations (Bart Van Assche) - Fix rwlock support in <linux/spinlock_up.h> (Bart Van Assche) - Add lock context annotations in the spinlock implementation (Bart Van Assche) - signal: Fix the lock_task_sighand() annotation (Bart Van Assche) - ww-mutex: Fix the ww_acquire_ctx function annotations (Bart Van Assche) - Add lock context support in do_raw_{read,write}_trylock() (Bart Van Assche) - arm64, compiler-context-analysis: Permit alias analysis through __READ_ONCE() with CONFIG_LTO=y (Marco Elver) - Add __cond_releases() (Peter Zijlstra) - Add context analysis for mutexes (Peter Zijlstra) - Add context analysis for rtmutexes (Peter Zijlstra) - Convert futexes to compiler context analysis (Peter Zijlstra) Rust integration updates: - Add atomic fetch_sub() implementation (Andreas Hindborg) - Refactor various rust_helper_ methods for expansion (Boqun Feng) - Add Atomic<*{mut,const} T> support (Boqun Feng) - Add atomic operation helpers over raw pointers (Boqun Feng) - Add performance-optimal Flag type for atomic booleans, to avoid slow byte-sized RMWs on architectures that don't support them. (FUJITA Tomonori) - Misc cleanups and fixes (Andreas Hindborg, Boqun Feng, FUJITA Tomonori) LTO support updates: - arm64: Optimize __READ_ONCE() with CONFIG_LTO=y (Marco Elver) - compiler: Simplify generic RELOC_HIDE() (Marco Elver) Miscellaneous fixes and cleanups by Peter Zijlstra, Randy Dunlap, Thomas Weißschuh, Davidlohr Bueso and Mikhail Gavrilov" * tag 'locking-core-2026-04-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (39 commits) compiler: Simplify generic RELOC_HIDE() locking: Add lock context annotations in the spinlock implementation locking: Add lock context support in do_raw_{read,write}_trylock() locking: Fix rwlock support in <linux/spinlock_up.h> lockdep: Raise default stack trace limits when KASAN is enabled cleanup: Optimize guards jump_label: remove workaround for old compilers in initializations jump_label: use ATOMIC_INIT() for initialization of .enabled futex: Convert to compiler context analysis locking/rwsem: Fix logic error in rwsem_del_waiter() locking/rwsem: Add context analysis locking/rtmutex: Add context analysis locking/mutex: Add context analysis compiler-context-analysys: Add __cond_releases() locking/mutex: Remove the list_head from struct mutex locking/semaphore: Remove the list_head from struct semaphore locking/rwsem: Remove the list_head from struct rw_semaphore rust: atomic: Update a safety comment in impl of `fetch_add()` rust: sync: atomic: Update documentation for `fetch_add()` rust: sync: atomic: Add fetch_sub() ...
2026-03-26futex: Fix UaF between futex_key_to_node_opt() and vma_replace_policy()Hao-Yu Yang1-1/+1
During futex_key_to_node_opt() execution, vma->vm_policy is read under speculative mmap lock and RCU. Concurrently, mbind() may call vma_replace_policy() which frees the old mempolicy immediately via kmem_cache_free(). This creates a race where __futex_key_to_node() dereferences a freed mempolicy pointer, causing a use-after-free read of mpol->mode. [ 151.412631] BUG: KASAN: slab-use-after-free in __futex_key_to_node (kernel/futex/core.c:349) [ 151.414046] Read of size 2 at addr ffff888001c49634 by task e/87 [ 151.415969] Call Trace: [ 151.416732] __asan_load2 (mm/kasan/generic.c:271) [ 151.416777] __futex_key_to_node (kernel/futex/core.c:349) [ 151.416822] get_futex_key (kernel/futex/core.c:374 kernel/futex/core.c:386 kernel/futex/core.c:593) Fix by adding rcu to __mpol_put(). Fixes: c042c505210d ("futex: Implement FUTEX2_MPOL") Reported-by: Hao-Yu Yang <naup96721@gmail.com> Suggested-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Hao-Yu Yang <naup96721@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Eric Dumazet <edumazet@google.com> Acked-by: David Hildenbrand (Arm) <david@kernel.org> Link: https://patch.msgid.link/20260324174418.GB1850007@noisy.programming.kicks-ass.net
2026-03-16futex: Convert to compiler context analysisPeter Zijlstra1-3/+6
Convert the sparse annotations over to the new compiler context analysis stuff. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260121111213.950376128@infradead.org
2025-12-02Merge tag 'core-uaccess-2025-11-30' of ↵Linus Torvalds1-2/+2
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull scoped user access updates from Thomas Gleixner: "Scoped user mode access and related changes: - Implement the missing u64 user access function on ARM when CONFIG_CPU_SPECTRE=n. This makes it possible to access a 64bit value in generic code with [unsafe_]get_user(). All other architectures and ARM variants provide the relevant accessors already. - Ensure that ASM GOTO jump label usage in the user mode access helpers always goes through a local C scope label indirection inside the helpers. This is required because compilers are not supporting that a ASM GOTO target leaves a auto cleanup scope. GCC silently fails to emit the cleanup invocation and CLANG fails the build. [ Editor's note: gcc-16 will have fixed the code generation issue in commit f68fe3ddda4 ("eh: Invoke cleanups/destructors in asm goto jumps [PR122835]"). But we obviously have to deal with clang and older versions of gcc, so.. - Linus ] This provides generic wrapper macros and the conversion of affected architecture code to use them. - Scoped user mode access with auto cleanup Access to user mode memory can be required in hot code paths, but if it has to be done with user controlled pointers, the access is shielded with a speculation barrier, so that the CPU cannot speculate around the address range check. Those speculation barriers impact performance quite significantly. This cost can be avoided by "masking" the provided pointer so it is guaranteed to be in the valid user memory access range and otherwise to point to a guaranteed unpopulated address space. This has to be done without branches so it creates an address dependency for the access, which the CPU cannot speculate ahead. This results in repeating and error prone programming patterns: if (can_do_masked_user_access()) from = masked_user_read_access_begin((from)); else if (!user_read_access_begin(from, sizeof(*from))) return -EFAULT; unsafe_get_user(val, from, Efault); user_read_access_end(); return 0; Efault: user_read_access_end(); return -EFAULT; which can be replaced with scopes and automatic cleanup: scoped_user_read_access(from, Efault) unsafe_get_user(val, from, Efault); return 0; Efault: return -EFAULT; - Convert code which implements the above pattern over to scope_user.*.access(). This also corrects a couple of imbalanced masked_*_begin() instances which are harmless on most architectures, but prevent PowerPC from implementing the masking optimization. - Add a missing speculation barrier in copy_from_user_iter()" * tag 'core-uaccess-2025-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: lib/strn*,uaccess: Use masked_user_{read/write}_access_begin when required scm: Convert put_cmsg() to scoped user access iov_iter: Add missing speculation barrier to copy_from_user_iter() iov_iter: Convert copy_from_user_iter() to masked user access select: Convert to scoped user access x86/futex: Convert to scoped user access futex: Convert to get/put_user_inline() uaccess: Provide put/get_user_inline() uaccess: Provide scoped user access regions arm64: uaccess: Use unsafe wrappers for ASM GOTO s390/uaccess: Use unsafe wrappers for ASM GOTO riscv/uaccess: Use unsafe wrappers for ASM GOTO powerpc/uaccess: Use unsafe wrappers for ASM GOTO x86/uaccess: Use unsafe wrappers for ASM GOTO uaccess: Provide ASM GOTO safe wrappers for unsafe_*_user() ARM: uaccess: Implement missing __get_user_asm_dword()
2025-11-06futex: Optimize per-cpu reference countingPeter Zijlstra1-6/+6
Shrikanth noted that the per-cpu reference counter was still some 10% slower than the old immutable option (which removes the reference counting entirely). Further optimize the per-cpu reference counter by: - switching from RCU to preempt; - using __this_cpu_*() since we now have preempt disabled; - switching from smp_load_acquire() to READ_ONCE(). This is all safe because disabling preemption inhibits the RCU grace period exactly like rcu_read_lock(). Having preemption disabled allows using __this_cpu_*() provided the only access to the variable is in task context -- which is the case here. Furthermore, since we know changing fph->state to FR_ATOMIC demands a full RCU grace period we can rely on the implied smp_mb() from that to replace the acquire barrier(). This is very similar to the percpu_down_read_internal() fast-path. The reason this is significant for PowerPC is that it uses the generic this_cpu_*() implementation which relies on local_irq_disable() (the x86 implementation relies on it being a single memop instruction to be IRQ-safe). Switching to preempt_disable() and __this_cpu*() avoids this IRQ state swizzling. Also, PowerPC needs LWSYNC for the ACQUIRE barrier, not having to use explicit barriers safes a bunch. Combined this reduces the performance gap by half, down to some 5%. Fixes: 760e6f7befba ("futex: Remove support for IMMUTABLE") Reported-by: Shrikanth Hegde <sshegde@linux.ibm.com> Tested-by: Shrikanth Hegde <sshegde@linux.ibm.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Link: https://patch.msgid.link/20251106092929.GR4067720@noisy.programming.kicks-ass.net
2025-11-04futex: Convert to get/put_user_inline()Thomas Gleixner1-2/+2
Replace the open coded implementation with the new get/put_user_inline() helpers. This might be replaced by a regular get/put_user(), but that needs a proper performance evaluation. No functional change intended. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Link: https://patch.msgid.link/20251027083745.736737934@linutronix.de
2025-08-31futex: Move futex_hash_free() back to __mmput()Sebastian Andrzej Siewior1-4/+12
To avoid a memory leak via mm_alloc() + mmdrop() the futex cleanup code has been moved to __mmdrop(). This resulted in a warnings if the futex hash table has been allocated via vmalloc() the mmdrop() was invoked from atomic context. The free path must stay in __mmput() to ensure it is invoked from preemptible context. In order to avoid the memory leak, delay the allocation of mm_struct::mm->futex_ref to futex_hash_allocate(). This works because neither the per-CPU counter nor the private hash has been allocated and therefore - futex_private_hash() callers (such as exit_pi_state_list()) don't acquire reference if there is no private hash yet. There is also no reference put. - Regular callers (futex_hash()) fallback to global hash. No reference counting here. The futex_ref member can be allocated in futex_hash_allocate() before the private hash itself is allocated. This happens either while the first thread is created or on request. In both cases the process has just a single thread so there can be either futex operation in progress or the request to create a private hash. Move futex_hash_free() back to __mmput(); Move the allocation of mm_struct::futex_ref to futex_hash_allocate(). [ bp: Fold a follow-up fix to prevent a use-after-free: https://lore.kernel.org/r/20250830213806.sEKuuGSm@linutronix.de ] Fixes: e703b7e247503 ("futex: Move futex cleanup to __mmdrop()") Closes: https://lore.kernel.org/all/20250821102721.6deae493@kernel.org/ Reported-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lkml.kernel.org/r/20250822141238.PfnkTjFb@linutronix.de
2025-07-11futex: Remove support for IMMUTABLESebastian Andrzej Siewior1-33/+3
The FH_FLAG_IMMUTABLE flag was meant to avoid the reference counting on the private hash and so to avoid the performance regression on big machines. With the switch to per-CPU counter this is no longer needed. That flag was never useable on any released kernel. Remove any support for IMMUTABLE while preserve the flags argument and enforce it to be zero. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250710110011.384614-5-bigeasy@linutronix.de
2025-07-11futex: Make futex_private_hash_get() staticSebastian Andrzej Siewior1-1/+1
futex_private_hash_get() is not used outside if its compilation unit. Make it static. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250710110011.384614-4-bigeasy@linutronix.de
2025-07-11futex: Use RCU-based per-CPU reference counting instead of rcuref_tPeter Zijlstra1-17/+226
The use of rcuref_t for reference counting introduces a performance bottleneck when accessed concurrently by multiple threads during futex operations. Replace rcuref_t with special crafted per-CPU reference counters. The lifetime logic remains the same. The newly allocate private hash starts in FR_PERCPU state. In this state, each futex operation that requires the private hash uses a per-CPU counter (an unsigned int) for incrementing or decrementing the reference count. When the private hash is about to be replaced, the per-CPU counters are migrated to a atomic_t counter mm_struct::futex_atomic. The migration process: - Waiting for one RCU grace period to ensure all users observe the current private hash. This can be skipped if a grace period elapsed since the private hash was assigned. - futex_private_hash::state is set to FR_ATOMIC, forcing all users to use mm_struct::futex_atomic for reference counting. - After a RCU grace period, all users are guaranteed to be using the atomic counter. The per-CPU counters can now be summed up and added to the atomic_t counter. If the resulting count is zero, the hash can be safely replaced. Otherwise, active users still hold a valid reference. - Once the atomic reference count drops to zero, the next futex operation will switch to the new private hash. call_rcu_hurry() is used to speed up transition which otherwise might be delay with RCU_LAZY. There is nothing wrong with using call_rcu(). The side effects would be that on auto scaling the new hash is used later and the SET_SLOTS prctl() will block longer. [bigeasy: commit description + mm get/ put_async] Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250710110011.384614-3-bigeasy@linutronix.de
2025-06-11futex: Verify under the lock if hash can be replacedSebastian Andrzej Siewior1-0/+10
Once the global hash is requested there is no way back to switch back to the per-task private hash. This is checked at the begin of the function. It is possible that two threads simultaneously request the global hash and both pass the initial check and block later on the mm::futex_hash_lock. In this case the first thread performs the switch to the global hash. The second thread will also attempt to switch to the global hash and while doing so, accessing the nonexisting slot 1 of the struct futex_private_hash. The same applies if the hash is made immutable: There is no reference counting and the hash must not be replaced. Verify under mm_struct::futex_phash that neither the global hash nor an immutable hash in use. Tested-by: "Lai, Yi" <yi1.lai@linux.intel.com> Reported-by: "Lai, Yi" <yi1.lai@linux.intel.com> Closes: https://lore.kernel.org/all/aDwDw9Aygqo6oAx+@ly-workstation/ Fixes: bd54df5ea7cad ("futex: Allow to resize the private local hash") Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/all/20250610104400.1077266-5-bigeasy@linutronix.de/
2025-06-05futex: Handle invalid node numbers supplied by userPeter Zijlstra1-2/+2
syzbot used a negative node number which was not rejected early and led to invalid memory access in node_possible(). Reject negative node numbers except for FUTEX_NO_NODE. [bigeasy: Keep the FUTEX_NO_NODE check] Closes: https://lore.kernel.org/all/6835bfe3.a70a0220.253bc2.00b5.GAE@google.com/ Fixes: cec199c5e39bd ("futex: Implement FUTEX2_NUMA") Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reported-by: syzbot+9afaf6749e3a7aa1bdf3@syzkaller.appspotmail.com Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/20250528085521.1938355-4-bigeasy@linutronix.de
2025-06-02Merge tag 'mm-stable-2025-06-01-14-06' of ↵Linus Torvalds1-1/+1
git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Pull more MM updates from Andrew Morton: - "zram: support algorithm-specific parameters" from Sergey Senozhatsky adds infrastructure for passing algorithm-specific parameters into zram. A single parameter `winbits' is implemented at this time. - "memcg: nmi-safe kmem charging" from Shakeel Butt makes memcg charging nmi-safe, which is required by BFP, which can operate in NMI context. - "Some random fixes and cleanup to shmem" from Kemeng Shi implements small fixes and cleanups in the shmem code. - "Skip mm selftests instead when kernel features are not present" from Zi Yan fixes some issues in the MM selftest code. - "mm/damon: build-enable essential DAMON components by default" from SeongJae Park reworks DAMON Kconfig to make it easier to enable CONFIG_DAMON. - "sched/numa: add statistics of numa balance task migration" from Libo Chen adds more info into sysfs and procfs files to improve visibility into the NUMA balancer's task migration activity. - "selftests/mm: cow and gup_longterm cleanups" from Mark Brown provides various updates to some of the MM selftests to make them play better with the overall containing framework. * tag 'mm-stable-2025-06-01-14-06' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (43 commits) mm/khugepaged: clean up refcount check using folio_expected_ref_count() selftests/mm: fix test result reporting in gup_longterm selftests/mm: report unique test names for each cow test selftests/mm: add helper for logging test start and results selftests/mm: use standard ksft_finished() in cow and gup_longterm selftests/damon/_damon_sysfs: skip testcases if CONFIG_DAMON_SYSFS is disabled sched/numa: add statistics of numa balance task sched/numa: fix task swap by skipping kernel threads tools/testing: check correct variable in open_procmap() tools/testing/vma: add missing function stub mm/gup: update comment explaining why gup_fast() disables IRQs selftests/mm: two fixes for the pfnmap test mm/khugepaged: fix race with folio split/free using temporary reference mm: add CONFIG_PAGE_BLOCK_ORDER to select page block order mmu_notifiers: remove leftover stub macros selftests/mm: deduplicate test names in madv_populate kcov: rust: add flags for KCOV with Rust mm: rust: make CONFIG_MMU ifdefs more narrow mmu_gather: move tlb flush for VM_PFNMAP/VM_MIXEDMAP vmas into free_pgtables() mm/damon/Kconfig: enable CONFIG_DAMON by default ...
2025-05-31mm: rename page->index to page->__folio_indexMatthew Wilcox (Oracle)1-1/+1
All users of page->index have been converted to not refer to it any more. Update a few pieces of documentation that were missed and prevent new users from appearing (or at least make them easy to grep for). Link: https://lkml.kernel.org/r/20250514181508.3019795-1-willy@infradead.org Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Acked-by: David Hildenbrand <david@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-05-03futex: Implement FUTEX2_MPOLPeter Zijlstra1-16/+100
Extend the futex2 interface to be aware of mempolicy. When FUTEX2_MPOL is specified and there is a MPOL_PREFERRED or home_node specified covering the futex address, use that hash-map. Notably, in this case the futex will go to the global node hashtable, even if it is a PRIVATE futex. When FUTEX2_NUMA|FUTEX2_MPOL is specified and the user specified node value is FUTEX_NO_NODE, the MPOL lookup (as described above) will be tried first before reverting to setting node to the local node. [bigeasy: add CONFIG_FUTEX_MPOL, add MPOL to FUTEX2_VALID_MASK, write the node only to user if FUTEX_NO_NODE was supplied] Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-18-bigeasy@linutronix.de
2025-05-03futex: Implement FUTEX2_NUMAPeter Zijlstra1-17/+83
Extend the futex2 interface to be numa aware. When FUTEX2_NUMA is specified for a futex, the user value is extended to two words (of the same size). The first is the user value we all know, the second one will be the node to place this futex on. struct futex_numa_32 { u32 val; u32 node; }; When node is set to ~0, WAIT will set it to the current node_id such that WAKE knows where to find it. If userspace corrupts the node value between WAIT and WAKE, the futex will not be found and no wakeup will happen. When FUTEX2_NUMA is not set, the node is simply an extension of the hash, such that traditional futexes are still interleaved over the nodes. This is done to avoid having to have a separate !numa hash-table. [bigeasy: ensure to have at least hashsize of 4 in futex_init(), add pr_info() for size and allocation information. Cast the naddr math to void*] Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-17-bigeasy@linutronix.de
2025-05-03futex: Allow to make the private hash immutableSebastian Andrzej Siewior1-6/+43
My initial testing showed that: perf bench futex hash reported less operations/sec with private hash. After using the same amount of buckets in the private hash as used by the global hash then the operations/sec were about the same. This changed once the private hash became resizable. This feature added an RCU section and reference counting via atomic inc+dec operation into the hot path. The reference counting can be avoided if the private hash is made immutable. Extend PR_FUTEX_HASH_SET_SLOTS by a fourth argument which denotes if the private should be made immutable. Once set (to true) the a further resize is not allowed (same if set to global hash). Add PR_FUTEX_HASH_GET_IMMUTABLE which returns true if the hash can not be changed. Update "perf bench" suite. For comparison, results of "perf bench futex hash -s": - Xeon CPU E5-2650, 2 NUMA nodes, total 32 CPUs: - Before the introducing task local hash shared Averaged 1.487.148 operations/sec (+- 0,53%), total secs = 10 private Averaged 2.192.405 operations/sec (+- 0,07%), total secs = 10 - With the series shared Averaged 1.326.342 operations/sec (+- 0,41%), total secs = 10 -b128 Averaged 141.394 operations/sec (+- 1,15%), total secs = 10 -Ib128 Averaged 851.490 operations/sec (+- 0,67%), total secs = 10 -b8192 Averaged 131.321 operations/sec (+- 2,13%), total secs = 10 -Ib8192 Averaged 1.923.077 operations/sec (+- 0,61%), total secs = 10 128 is the default allocation of hash buckets. 8192 was the previous amount of allocated hash buckets. - Xeon(R) CPU E7-8890 v3, 4 NUMA nodes, total 144 CPUs: - Before the introducing task local hash shared Averaged 1.810.936 operations/sec (+- 0,26%), total secs = 20 private Averaged 2.505.801 operations/sec (+- 0,05%), total secs = 20 - With the series shared Averaged 1.589.002 operations/sec (+- 0,25%), total secs = 20 -b1024 Averaged 42.410 operations/sec (+- 0,20%), total secs = 20 -Ib1024 Averaged 740.638 operations/sec (+- 1,51%), total secs = 20 -b65536 Averaged 48.811 operations/sec (+- 1,35%), total secs = 20 -Ib65536 Averaged 1.963.165 operations/sec (+- 0,18%), total secs = 20 1024 is the default allocation of hash buckets. 65536 was the previous amount of allocated hash buckets. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Shrikanth Hegde <sshegde@linux.ibm.com> Link: https://lore.kernel.org/r/20250416162921.513656-16-bigeasy@linutronix.de
2025-05-03futex: Allow to resize the private local hashSebastian Andrzej Siewior1-19/+271
The mm_struct::futex_hash_lock guards the futex_hash_bucket assignment/ replacement. The futex_hash_allocate()/ PR_FUTEX_HASH_SET_SLOTS operation can now be invoked at runtime and resize an already existing internal private futex_hash_bucket to another size. The reallocation is based on an idea by Thomas Gleixner: The initial allocation of struct futex_private_hash sets the reference count to one. Every user acquires a reference on the local hash before using it and drops it after it enqueued itself on the hash bucket. There is no reference held while the task is scheduled out while waiting for the wake up. The resize process allocates a new struct futex_private_hash and drops the initial reference. Synchronized with mm_struct::futex_hash_lock it is checked if the reference counter for the currently used mm_struct::futex_phash is marked as DEAD. If so, then all users enqueued on the current private hash are requeued on the new private hash and the new private hash is set to mm_struct::futex_phash. Otherwise the newly allocated private hash is saved as mm_struct::futex_phash_new and the rehashing and reassigning is delayed to the futex_hash() caller once the reference counter is marked DEAD. The replacement is not performed at rcuref_put() time because certain callers, such as futex_wait_queue(), drop their reference after changing the task state. This change will be destroyed once the futex_hash_lock is acquired. The user can change the number slots with PR_FUTEX_HASH_SET_SLOTS multiple times. An increase and decrease is allowed and request blocks until the assignment is done. The private hash allocated at thread creation is changed from 16 to 16 <= 4 * number_of_threads <= global_hash_size where number_of_threads can not exceed the number of online CPUs. Should the user PR_FUTEX_HASH_SET_SLOTS then the auto scaling is disabled. [peterz: reorganize the code to avoid state tracking and simplify new object handling, block the user until changes are in effect, allow increase and decrease of the hash]. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-15-bigeasy@linutronix.de
2025-05-03futex: Allow automatic allocation of process wide futex hashSebastian Andrzej Siewior1-0/+11
Allocate a private futex hash with 16 slots if a task forks its first thread. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-14-bigeasy@linutronix.de
2025-05-03futex: Add basic infrastructure for local task local hashSebastian Andrzej Siewior1-18/+190
The futex hash is system wide and shared by all tasks. Each slot is hashed based on futex address and the VMA of the thread. Due to randomized VMAs (and memory allocations) the same logical lock (pointer) can end up in a different hash bucket on each invocation of the application. This in turn means that different applications may share a hash bucket on the first invocation but not on the second and it is not always clear which applications will be involved. This can result in high latency's to acquire the futex_hash_bucket::lock especially if the lock owner is limited to a CPU and can not be effectively PI boosted. Introduce basic infrastructure for process local hash which is shared by all threads of process. This hash will only be used for a PROCESS_PRIVATE FUTEX operation. The hashmap can be allocated via: prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_SET_SLOTS, num); A `num' of 0 means that the global hash is used instead of a private hash. Other values for `num' specify the number of slots for the hash and the number must be power of two, starting with two. The prctl() returns zero on success. This function can only be used before a thread is created. The current status for the private hash can be queried via: num = prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_GET_SLOTS); which return the current number of slots. The value 0 means that the global hash is used. Values greater than 0 indicate the number of slots that are used. A negative number indicates an error. For optimisation, for the private hash jhash2() uses only two arguments the address and the offset. This omits the VMA which is always the same. [peterz: Use 0 for global hash. A bit shuffling and renaming. ] Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-13-bigeasy@linutronix.de
2025-05-03futex: Create helper function to initialize a hash slotSebastian Andrzej Siewior1-5/+9
Factor out the futex_hash_bucket initialisation into a helpr function. The helper function will be used in a follow up patch implementing process private hash buckets. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-12-bigeasy@linutronix.de
2025-05-03futex: Introduce futex_q_lockptr_lock()Sebastian Andrzej Siewior1-0/+25
futex_lock_pi() and __fixup_pi_state_owner() acquire the futex_q::lock_ptr without holding a reference assuming the previously obtained hash bucket and the assigned lock_ptr are still valid. This isn't the case once the private hash can be resized and becomes invalid after the reference drop. Introduce futex_q_lockptr_lock() to lock the hash bucket recorded in futex_q::lock_ptr. The lock pointer is read in a RCU section to ensure that it does not go away if the hash bucket has been replaced and the old pointer has been observed. After locking the pointer needs to be compared to check if it changed. If so then the hash bucket has been replaced and the user has been moved to the new one and lock_ptr has been updated. The lock operation needs to be redone in this case. The locked hash bucket is not returned. A special case is an early return in futex_lock_pi() (due to signal or timeout) and a successful futex_wait_requeue_pi(). In both cases a valid futex_q::lock_ptr is expected (and its matching hash bucket) but since the waiter has been removed from the hash this can no longer be guaranteed. Therefore before the waiter is removed and a reference is acquired which is later dropped by the waiter to avoid a resize. Add futex_q_lockptr_lock() and use it. Acquire an additional reference in requeue_pi_wake_futex() and futex_unlock_pi() while the futex_q is removed, denote this extra reference in futex_q::drop_hb_ref and let the waiter drop the reference in this case. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-11-bigeasy@linutronix.de
2025-05-03futex: Decrease the waiter count before the unlock operationSebastian Andrzej Siewior1-1/+1
To support runtime resizing of the process private hash, it's required to not use the obtained hash bucket once the reference count has been dropped. The reference will be dropped after the unlock of the hash bucket. The amount of waiters is decremented after the unlock operation. There is no requirement that this needs to happen after the unlock. The increment happens before acquiring the lock to signal early that there will be a waiter. The waiter can avoid blocking on the lock if it is known that there will be no waiter. There is no difference in terms of ordering if the decrement happens before or after the unlock. Decrease the waiter count before the unlock operation. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-10-bigeasy@linutronix.de
2025-05-03futex: Create private_hash() get/put classPeter Zijlstra1-0/+12
This gets us: fph = futex_private_hash(key) /* gets fph and inc users */ futex_private_hash_get(fph) /* inc users */ futex_private_hash_put(fph) /* dec users */ Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-8-bigeasy@linutronix.de
2025-05-03futex: Create futex_hash() get/put classPeter Zijlstra1-3/+3
This gets us: hb = futex_hash(key) /* gets hb and inc users */ futex_hash_get(hb) /* inc users */ futex_hash_put(hb) /* dec users */ Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-7-bigeasy@linutronix.de
2025-05-03futex: Create hb scopesPeter Zijlstra1-39/+42
Create explicit scopes for hb variables; almost pure re-indent. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250416162921.513656-6-bigeasy@linutronix.de