From nobody Mon Jun 8 08:54:10 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63BA9481665; Wed, 3 Jun 2026 14:24:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780496699; cv=none; b=aG1CWid4K9IhHizjCj5N3LVxow0IEaFPmo603s7U6K+jl/V1afLkXO0vHOiUqJCdGMOeoeMf/HMGMlTp0ve6VuI4A6/hgFE2lQNSgLIMN1kMNgtEZ5esg1ocAwm1i2quj2bB7y2US/fzGa1wDKoj2qHe3BhQDpSPbzivwtxsV4U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780496699; c=relaxed/simple; bh=dv7BlGud5wG1C18NbSB2a8r2DUlyW2eWOhq/hBEyQUo=; h=Date:From:To:Subject:Cc:In-Reply-To:References:MIME-Version: Message-ID:Content-Type; b=it38OlrzlAfMxyDGcEJW1/zgdS4NZy6zFkFyYdJOUxutxHq4cWGWnVDnk1NoU4tli/jiqKXg5iGjaFRyyFNXB8Ml2ZxVP9U+m0L2XBBSlZkTuSJ6mSyYK/rGlDW776OwiWD9Chtwt/DHqEulqg4aRVfIad9ND992iSZ1O8CBwv0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=vJewECDt; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=z4iqSJ4g; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="vJewECDt"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="z4iqSJ4g" Date: Wed, 03 Jun 2026 14:24:54 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1780496696; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kXlLBdRbFGq59XHWMqAG9xvB4EVt1u6azwvYGl6bv5g=; b=vJewECDtgdKcuV0QFrBK/0dTt1hh0CRpk21yiO+EFej3WGx+3hTezr9R6png+4DjqmO7d6 TDHkRhw4aVpwr2KNQ0ZEs7PAErAc3HTjhoNPsbVNbvqyL0tgoTxFbs75DbKb2dsPYyJSVu 7twoHHMK9c+McKugVLMqWoHN6kw0k2i8vJs3ALs5sV/blpG3SNAunrTJiQvD32iwaUpeDx XCiqmpzox9MuT2N4EhqA/rhYC/xtCzJgBoWRM86yiDjjSzNVi3tnoI6Wu88hd8xwR0wD4E mA7rc+0SeTB2SPAeoOzf8/lnJr93JjKa/1zka6bXGeu78K6iL+rRVQEBOB0gfw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1780496696; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kXlLBdRbFGq59XHWMqAG9xvB4EVt1u6azwvYGl6bv5g=; b=z4iqSJ4gdy4SwyqvoZOv9TGJX52gbmnIQqYIyALWu/YIe4fVFoVbG0fblHU55cgKKJVRdz SBkfUdkH0WcHIQDQ== From: "tip-bot2 for Thomas Gleixner" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: locking/core] futex: Add robust futex unlock IP range Cc: Thomas Gleixner , "Peter Zijlstra (Intel)" , andrealmeid@igalia.com, x86@kernel.org, linux-kernel@vger.kernel.org In-Reply-To: <20260602090535.718926819@kernel.org> References: <20260602090535.718926819@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <178049669466.710.16541586267709807109.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Precedence: bulk Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The following commit has been merged into the locking/core branch of tip: Commit-ID: 042df0c1d48609a85580dcbaff498c95ced20a5f Gitweb: https://git.kernel.org/tip/042df0c1d48609a85580dcbaff498c95c= ed20a5f Author: Thomas Gleixner AuthorDate: Tue, 02 Jun 2026 11:09:59 +02:00 Committer: Peter Zijlstra CommitterDate: Wed, 03 Jun 2026 11:38:51 +02:00 futex: Add robust futex unlock IP range 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 Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Andr=C3=A9 Almeida Link: https://patch.msgid.link/20260602090535.718926819@kernel.org --- include/linux/futex.h | 21 +++++++++++++--- include/linux/futex_types.h | 28 ++++++++++++++++++++++- init/Kconfig | 6 +++++- kernel/futex/core.c | 46 ++++++++++++++++++++++++++++-------- 4 files changed, 89 insertions(+), 12 deletions(-) diff --git a/include/linux/futex.h b/include/linux/futex.h index 9e6218c..cb2a182 100644 --- a/include/linux/futex.h +++ b/include/linux/futex.h @@ -81,11 +81,9 @@ int futex_hash_prctl(unsigned long arg2, unsigned long a= rg3, unsigned long arg4) #ifdef CONFIG_FUTEX_PRIVATE_HASH int futex_hash_allocate_default(void); void futex_hash_free(struct mm_struct *mm); -void futex_mm_init(struct mm_struct *mm); #else /* CONFIG_FUTEX_PRIVATE_HASH */ static inline int futex_hash_allocate_default(void) { return 0; } static inline int futex_hash_free(struct mm_struct *mm) { return 0; } -static inline void futex_mm_init(struct mm_struct *mm) { } #endif /* !CONFIG_FUTEX_PRIVATE_HASH */ =20 #else /* CONFIG_FUTEX */ @@ -104,7 +102,24 @@ static inline int futex_hash_prctl(unsigned long arg2,= unsigned long arg3, unsig } static inline int futex_hash_allocate_default(void) { return 0; } static inline int futex_hash_free(struct mm_struct *mm) { return 0; } -static inline void futex_mm_init(struct mm_struct *mm) { } #endif /* !CONFIG_FUTEX */ =20 +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK +void futex_reset_cs_ranges(struct futex_mm_data *fd); + +static inline void futex_set_vdso_cs_range(struct futex_mm_data *fd, unsig= ned int idx, + unsigned long start, unsigned long end, bool sz32) +{ + fd->unlock.cs_ranges[idx].start_ip =3D start; + fd->unlock.cs_ranges[idx].len =3D end - start; + fd->unlock.cs_ranges[idx].pop_size32 =3D sz32; +} +#endif /* CONFIG_FUTEX_ROBUST_UNLOCK */ + +#if defined(CONFIG_FUTEX_PRIVATE_HASH) || defined(CONFIG_FUTEX_ROBUST_UNLO= CK) +void futex_mm_init(struct mm_struct *mm); +#else +static inline void futex_mm_init(struct mm_struct *mm) { } +#endif + #endif /* _LINUX_FUTEX_H */ diff --git a/include/linux/futex_types.h b/include/linux/futex_types.h index d41557d..d320c05 100644 --- a/include/linux/futex_types.h +++ b/include/linux/futex_types.h @@ -55,12 +55,40 @@ struct futex_mm_phash { struct futex_mm_phash { }; #endif /* !CONFIG_FUTEX_ROBUST_UNLOCK */ =20 +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK +/** + * struct futex_unlock_cs_range - Range for the VDSO unlock critical secti= on + * @start_ip: The start IP of the robust futex unlock critical section (in= clusive) + * @len: The length of the robust futex unlock critical section + * @pop_size32: Pending OP pointer size indicator. 0 =3D=3D 64-bit, 1 =3D= =3D 32-bit + */ +struct futex_unlock_cs_range { + unsigned long start_ip; + unsigned int len; + unsigned int pop_size32; +}; + +#define FUTEX_ROBUST_MAX_CS_RANGES (1 + IS_ENABLED(CONFIG_COMPAT)) + +/** + * struct futex_unlock_cs_ranges - Futex unlock VSDO critical sections + * @cs_ranges: Array of critical section ranges + */ +struct futex_unlock_cs_ranges { + struct futex_unlock_cs_range cs_ranges[FUTEX_ROBUST_MAX_CS_RANGES]; +}; +#else /* CONFIG_FUTEX_ROBUST_UNLOCK */ +struct futex_unlock_cs_ranges { }; +#endif /* !CONFIG_FUTEX_ROBUST_UNLOCK */ + /** * struct futex_mm_data - Futex related per MM data * @phash: Futex private hash related data + * @unlock: Futex unlock VDSO critical sections */ struct futex_mm_data { struct futex_mm_phash phash; + struct futex_unlock_cs_ranges unlock; }; #else /* CONFIG_FUTEX */ struct futex_sched_data { }; diff --git a/init/Kconfig b/init/Kconfig index 2937c4d..165b08e 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1842,6 +1842,12 @@ config FUTEX_MPOL depends on FUTEX && NUMA default y =20 +config HAVE_FUTEX_ROBUST_UNLOCK + bool + +config FUTEX_ROBUST_UNLOCK + def_bool FUTEX && HAVE_GENERIC_VDSO && GENERIC_IRQ_ENTRY && RSEQ && HAVE_= FUTEX_ROBUST_UNLOCK + config EPOLL bool "Enable eventpoll support" if EXPERT default y diff --git a/kernel/futex/core.c b/kernel/futex/core.c index 77ccb77..aad6e50 100644 --- a/kernel/futex/core.c +++ b/kernel/futex/core.c @@ -1761,11 +1761,11 @@ static bool futex_ref_is_dead(struct futex_private_= hash *fph) return atomic_long_read(&mm->futex.phash.atomic) =3D=3D 0; } =20 -void futex_mm_init(struct mm_struct *mm) +static void futex_hash_init_mm(struct futex_mm_data *fd) { - memset(&mm->futex, 0, sizeof(mm->futex)); - mutex_init(&mm->futex.phash.lock); - mm->futex.phash.batches =3D get_state_synchronize_rcu(); + memset(&fd->phash, 0, sizeof(fd->phash)); + mutex_init(&fd->phash.lock); + fd->phash.batches =3D get_state_synchronize_rcu(); } =20 void futex_hash_free(struct mm_struct *mm) @@ -1969,19 +1969,47 @@ static int futex_hash_get_slots(void) return fph->hash_mask + 1; return 0; } +#else /* CONFIG_FUTEX_PRIVATE_HASH */ +static inline int futex_hash_allocate(unsigned int hslots, unsigned int fl= ags) { return -EINVAL; } +static inline int futex_hash_get_slots(void) { return 0; } +static inline void futex_hash_init_mm(struct futex_mm_data *fd) { } +#endif /* !CONFIG_FUTEX_PRIVATE_HASH */ =20 -#else +#ifdef CONFIG_FUTEX_ROBUST_UNLOCK +static void futex_invalidate_cs_ranges(struct futex_mm_data *fd) +{ + /* + * Invalidate start_ip so that the quick check fails for ip >=3D start_ip + * if VDSO is not mapped or the second slot is not available for compat + * tasks as they use VDSO32 which does not provide the 64-bit pointer + * variant. + */ + for (int i =3D 0; i < FUTEX_ROBUST_MAX_CS_RANGES; i++) + fd->unlock.cs_ranges[i].start_ip =3D ~0UL; +} =20 -static int futex_hash_allocate(unsigned int hash_slots, unsigned int flags) +void futex_reset_cs_ranges(struct futex_mm_data *fd) { - return -EINVAL; + memset(fd->unlock.cs_ranges, 0, sizeof(fd->unlock.cs_ranges)); + futex_invalidate_cs_ranges(fd); } =20 -static int futex_hash_get_slots(void) +static void futex_robust_unlock_init_mm(struct futex_mm_data *fd) { - return 0; + /* mm_dup() preserves the range, mm_alloc() clears it */ + if (!fd->unlock.cs_ranges[0].start_ip) + futex_invalidate_cs_ranges(fd); } +#else /* CONFIG_FUTEX_ROBUST_UNLOCK */ +static inline void futex_robust_unlock_init_mm(struct futex_mm_data *fd) {= } +#endif /* !CONFIG_FUTEX_ROBUST_UNLOCK */ =20 +#if defined(CONFIG_FUTEX_PRIVATE_HASH) || defined(CONFIG_FUTEX_ROBUST_UNLO= CK) +void futex_mm_init(struct mm_struct *mm) +{ + futex_hash_init_mm(&mm->futex); + futex_robust_unlock_init_mm(&mm->futex); +} #endif =20 int futex_hash_prctl(unsigned long arg2, unsigned long arg3, unsigned long= arg4)