From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from canpmsgout01.his.huawei.com (canpmsgout01.his.huawei.com [113.46.200.216]) (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 CA68735B136 for ; Tue, 4 Aug 2026 11:30:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.216 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785843012; cv=none; b=MAlJasSr5BiiDWBvzu7L0A/2FByZIt0bEhS8Ij+roqVLZKaGUlqR/LMZ9BkTKrzjoaz+AUnypnqLH9cCWgkTSLD9c24UAhrPsuQAMEFJNIdkE4s5BP1xCvzf5EGgffzqSabDJpgZhGl+SYPr25rCdAYz6tNgOQzkw4E8aAvDbfQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785843012; c=relaxed/simple; bh=f1V3SnlPer0B3K3Cn91XRAL+T0yqavEoJ1B80xcJ5oU=; h=Message-ID:Date:MIME-Version:Subject:To:CC:References:From: In-Reply-To:Content-Type; b=Vxvqw+N9I90eSfCK9fo5HlriWJmRK1Dhl0sP0PcTALZo/bjoG9GSOxNZ08nCnoTN/yMnpjhnpfjaaHi0hi345l8PfVx3XVY87LNfNyP2YQA45tgenPAsbHTEQlOzD9kj19Cs/+Z1PoEncxSgvFyRG3UVz7eBxdICjelNfmnl/Is= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=Hc0cKlFQ; arc=none smtp.client-ip=113.46.200.216 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="Hc0cKlFQ" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=HojYo5pnHzxEREKSgqhuuQIcjr933QfwEBwT/QVpHPQ=; b=Hc0cKlFQZWFVKbNKA+mQvVlBuGuE+gnRs8V07oanLBJzUgTA3bVyD15VtVwKt60mZC7R4jEtG eUd7+BXrTKeEswFSH6Mefj0T8t1OqFRZDXpYH/LxzL8WtqP5ktLF5/EknlITTnll6T+Fw7CBHcW c1tT/fPBq0FIrxD9A6Jrm9A= Received: from mail.maildlp.com (unknown [172.19.163.104]) by canpmsgout01.his.huawei.com (SkyGuard) with ESMTPS id 4hDrgY2phKz1T4Fq; Tue, 4 Aug 2026 19:20:25 +0800 (CST) Received: from dggpemr500006.china.huawei.com (unknown [7.185.36.185]) by mail.maildlp.com (Postfix) with ESMTPS id 8D7B04058F; Tue, 4 Aug 2026 19:30:04 +0800 (CST) Received: from [100.103.109.15] (100.103.109.15) by dggpemr500006.china.huawei.com (7.185.36.185) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.45; Tue, 4 Aug 2026 19:30:03 +0800 Message-ID: <3479780e-4c1f-40d0-bf5c-3fae0893ca20@huawei.com> Date: Tue, 4 Aug 2026 19:30:03 +0800 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH] futex: Fix missed wakeup during private hash resize To: Peter Zijlstra CC: , , , , , , References: <20260803104313.3393274-1-yaokai34@huawei.com> <20260804091605.GJ49951@noisy.programming.kicks-ass.net> Content-Language: en-US From: Yao Kai In-Reply-To: <20260804091605.GJ49951@noisy.programming.kicks-ass.net> Content-Type: text/plain; charset="UTF-8"; format=flowed Content-Transfer-Encoding: 7bit X-ClientProxiedBy: kwepems200001.china.huawei.com (7.221.188.67) To dggpemr500006.china.huawei.com (7.185.36.185) On 8/4/2026 5:16 PM, Peter Zijlstra wrote: > 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); > } > Thanks! I verified your patch with my reproducer, and it completely fixes the issue. I will send out a v2 patch adopting your approach shortly. Thanks, Yao Kai