From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (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 4863043D4F7 for ; Tue, 4 Aug 2026 09:16:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.92.199 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785834982; cv=none; b=oukIzVhBgGFmipk6SkWc6BvIE9y40BloW5inh43rqgUfNHt1Q848JA06bZgikf13m6iBI+4dPlMgYCE0H6xUUXXrSqm+aN9H3icIp8MEwV887wHiY/x8s6o/Gzidsg0SRLeXICRrd/dfFtuKXGa8Pd723Ug/NxmEnkqgYcgxZ2k= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785834982; c=relaxed/simple; bh=9bQDbGVsedlEHKLZUGDT2UdwWuQd6CrBu0BTCV/GP6Y=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=u97qJEY1WR8m8L3i+SCwaDOMwkJyv9XCHfOxfca6IRoB9YysuQSMiPvilEK31o5zeck+72f3I49duWbuLFiAzK1OvVrMiKYFrlQDpdB5Yc49LYHMErj5J68nP/c0a+JplRKa/34k0XhkjyyNg85eu+Dxr6Un1334kRhA6iJnriw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=pass smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=AEDb2+7a; arc=none smtp.client-ip=90.155.92.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="AEDb2+7a" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=In-Reply-To:Content-Type:MIME-Version: References:Message-ID:Subject:Cc:To:From:Date:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=5ZPdSDPJvMbYCBeHSwTYEZm3tiGFxL/QZOEzacMuC3M=; b=AEDb2+7aeBSaAlFUmN9y0odqoj Go+r/8iygCpkaxm2avfWDczWGlDe6arCAV3nwQ26D+Wfv6XyHdhJOXC0y6fvZW5zj+DNSzvBy2Lgj UcBRGNstILE/bitcOjJOT+YjaxaMivYh76AEjb7vcy7jrbUTzMdIkT2xKRp6nlcYEwn/WWqrOgGcB XI+zvuTeRub8CvSKyDmEAcJRKr10zPxR15ZxLiHbDNPZzEisr+HAlhxU2wLM0HpjuSBhtvjjb4W0z NI50FjDm8ME9PfGYTu3KmT4VxVjXuGRN8G0o8Ka37VfYNJ3ngn2LkCrFOBiMgHD/RyYcdVTs1+ksI /kWIGMCA==; Received: from 77-249-17-252.cable.dynamic.v4.ziggo.nl ([77.249.17.252] helo=noisy.programming.kicks-ass.net) by desiato.infradead.org with esmtpsa (Exim 4.99.2 #2 (Red Hat Linux)) id 1wrBFn-00000009jHx-3TYi; Tue, 04 Aug 2026 09:16:07 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 1000) id D28C530065D; Tue, 04 Aug 2026 11:16:05 +0200 (CEST) Date: Tue, 4 Aug 2026 11:16:05 +0200 From: Peter Zijlstra To: Yao Kai Cc: tglx@kernel.org, mingo@redhat.com, dvhart@infradead.org, dave@stgolabs.net, andrealmeid@igalia.com, linux-kernel@vger.kernel.org, liuyongqiang13@huawei.com Subject: Re: [PATCH] futex: Fix missed wakeup during private hash resize Message-ID: <20260804091605.GJ49951@noisy.programming.kicks-ass.net> References: <20260803104313.3393274-1-yaokai34@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20260803104313.3393274-1-yaokai34@huawei.com> On Mon, Aug 03, 2026 at 06:43:13PM +0800, Yao Kai wrote: > 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. 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. Since a successful pivot does not notify waiters, the task > can go to sleep after the only preceding wakeup has already been > consumed. > > Wake waiters after every successful pivot. A full memory barrier before > wake_up_var() pairs with set_current_state() in wait_var_event() and > orders the completed pivot before the lockless waitqueue_active() check > in wake_up_var(). The waiter therefore either observes hash_new == NULL > before sleeping or is made runnable. Hmm, but isn't the problem a lack of serialization on futex_mm_phash access? That is, all of this futex_mm_phash::hash_new and futex_mm_phash::hash swizzling happens while holding futex_mm_phash::lock, except for futex_pivot_pending(), that is looking at these values without holding the lock, resulting in it observing that inconsistent state per the above. Taking a mutex in a wait loop is sorta yuck, but it should work. If the mutex is contended, it sleeps and the wait-loop 'spuriously' doesn't. If the mutex is uncontended, it doesn't sleep, but the wait-loop will. Does this work for you? --- diff --git a/kernel/futex/core.c b/kernel/futex/core.c index f74ede3df161..72d4698e35fb 100644 --- a/kernel/futex/core.c +++ b/kernel/futex/core.c @@ -1778,14 +1778,15 @@ void futex_hash_free(struct mm_struct *mm) static bool futex_pivot_pending(struct mm_struct *mm) { + struct futex_mm_phash *mmph = &mm->futex.phash; struct futex_private_hash *fph; - guard(rcu)(); + guard(mutex)(&mmph->lock); - if (!mm->futex.phash.hash_new) + if (!mmph->hash_new) return true; - fph = rcu_dereference(mm->futex.phash.hash); + fph = rcu_dereference_raw(mmph->hash); return futex_ref_is_dead(fph); }