From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from canpmsgout08.his.huawei.com (canpmsgout08.his.huawei.com [113.46.200.223]) (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 EC3B4346E7D for ; Fri, 22 May 2026 09:22:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.223 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779441723; cv=none; b=oxTdKBB5N7DuMkq0Ltikv62rzzM8olfSl2/X7gVy2fP+jHUlaPF2Wxc/w5dDiTZm8CUtaRYGX1YUxTCsBlv4cuEjrMyhSnFmtvr17l+jP99GaNoXKDNmrehbW76TIYASRI54LbL6ZZehHZW3G5v0SvsPHavGYCEi0CbqnOcPG38= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779441723; c=relaxed/simple; bh=Axsh1svJtOoPD8tE08u4i4m5r1u+gtp4rtaQxi0DdhM=; h=Subject:To:CC:References:From:Message-ID:Date:MIME-Version: In-Reply-To:Content-Type; b=V2zoGUpjOSEkadqpklpdt6vuX0ZwlSD0/TRQDBwX329G+kbaS0tQLG7JTX7EHeq5yQFPKR7YJMoobrCJDhdTWyGF2jfJS5+cv9nGeMDyKCpda1RacYlRop3nt5VntI111OidgibetUA4DBDpehCroxq5i+x2QjWc+co4ZzqtqKU= 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=TxJNTDkd; arc=none smtp.client-ip=113.46.200.223 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="TxJNTDkd" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=K7xGK62mRDtxiOSxUrHZC18KBCBUyKRrfRPKIIO/WHk=; b=TxJNTDkdY8hFEDKVpQYBuvrlxmE5XCXPZ7K3wxWRAJUlswsJZTspV3lVVJjvJHxa9ZM/WbgB4 Lc8kvXPdciuUFpnXb3pQYvGxTGy3EtZ9MasLt0hlvmzfgWgtovqYFgIBTuwnogks14xtMUwOpY4 a5AQkmjiHFKt8Uru+co1sck= Received: from mail.maildlp.com (unknown [172.19.162.92]) by canpmsgout08.his.huawei.com (SkyGuard) with ESMTPS id 4gMKN06dWCzmVXb; Fri, 22 May 2026 17:14:08 +0800 (CST) Received: from dggemv706-chm.china.huawei.com (unknown [10.3.19.33]) by mail.maildlp.com (Postfix) with ESMTPS id BBBF140565; Fri, 22 May 2026 17:21:52 +0800 (CST) Received: from kwepemq500010.china.huawei.com (7.202.194.235) by dggemv706-chm.china.huawei.com (10.3.19.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 22 May 2026 17:21:52 +0800 Received: from [10.173.124.160] (10.173.124.160) by kwepemq500010.china.huawei.com (7.202.194.235) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 22 May 2026 17:21:51 +0800 Subject: Re: [PATCH resend] mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison To: Wupeng Ma CC: , , , , , , , , , , , , References: <20260522010305.4099834-1-mawupeng1@huawei.com> From: Miaohe Lin Message-ID: Date: Fri, 22 May 2026 17:21:51 +0800 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.6.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 In-Reply-To: <20260522010305.4099834-1-mawupeng1@huawei.com> Content-Type: text/plain; charset="utf-8" Content-Language: en-US Content-Transfer-Encoding: 7bit X-ClientProxiedBy: kwepems500001.china.huawei.com (7.221.188.70) To kwepemq500010.china.huawei.com (7.202.194.235) On 2026/5/22 9:03, Wupeng Ma wrote: > Two concurrent madvise(MADV_HWPOISON) calls on the same hugetlb page > can trigger a recursive spinlock self-deadlock (AA deadlock) on > hugetlb_lock when racing with a concurrent unmap: > > thread#0 thread#1 > -------- -------- > madvise(folio, MADV_HWPOISON) > -> poisons the folio successfully > madvise(folio, MADV_HWPOISON) unmap(folio) > try_memory_failure_hugetlb > get_huge_page_for_hwpoison > spin_lock_irq(&hugetlb_lock) <- held > __get_huge_page_for_hwpoison > hugetlb_update_hwpoison() > -> MF_HUGETLB_FOLIO_PRE_POISONED > goto out: > folio_put() > refcount: 1 -> 0 > free_huge_folio() > spin_lock_irqsave(&hugetlb_lock) > -> AA DEADLOCK! > > The out: path in __get_huge_page_for_hwpoison() calls folio_put() to > drop the GUP reference while the hugetlb_lock is still held by the > hugetlb.c wrapper get_huge_page_for_hwpoison(). If concurrent unmap > has released the page table mapping reference, folio_put() drops the > folio refcount to zero, triggering free_huge_folio() which attempts > to re-acquire the non-recursive hugetlb_lock. > > Fix this by moving hugetlb_lock acquisition from the hugetlb.c wrapper > into get_huge_page_for_hwpoison(). Place spin_unlock_irq() before the > folio_put() at the out: label so the folio is always released outside > the lock. > > Fixes: 405ce051236c ("mm/hwpoison: fix race between hugetlb free/demotion and memory_failure_hugetlb()") > Signed-off-by: Wupeng Ma Thanks for your patch. > --- > Changelog since v3[1]: > - update commit message to fit current issue > > [1]: https://lore.kernel.org/linux-mm/20260520020128.3506168-1-mawupeng1@huawei.com/ > --- > include/linux/hugetlb.h | 8 -------- > include/linux/mm.h | 8 -------- > mm/hugetlb.c | 11 ----------- > mm/memory-failure.c | 8 ++++---- > 4 files changed, 4 insertions(+), 31 deletions(-) > > diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h > index 93418625d3c5..059749ed519f 100644 > --- a/include/linux/hugetlb.h > +++ b/include/linux/hugetlb.h > @@ -153,8 +153,6 @@ long hugetlb_unreserve_pages(struct inode *inode, long start, long end, > long freed); > bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list); > int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, bool unpoison); > -int get_huge_page_for_hwpoison(unsigned long pfn, int flags, > - bool *migratable_cleared); > void folio_putback_hugetlb(struct folio *folio); > void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int reason); > void hugetlb_fix_reserve_counts(struct inode *inode); > @@ -422,12 +420,6 @@ static inline int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, > return 0; > } > > -static inline int get_huge_page_for_hwpoison(unsigned long pfn, int flags, > - bool *migratable_cleared) > -{ > - return 0; > -} > - > static inline void folio_putback_hugetlb(struct folio *folio) > { > } > diff --git a/include/linux/mm.h b/include/linux/mm.h > index 0b776907152e..4c4d1a61a6a7 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -4975,8 +4975,6 @@ extern int soft_offline_page(unsigned long pfn, int flags); > */ > extern const struct attribute_group memory_failure_attr_group; > extern void memory_failure_queue(unsigned long pfn, int flags); > -extern int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, > - bool *migratable_cleared); > void num_poisoned_pages_inc(unsigned long pfn); > void num_poisoned_pages_sub(unsigned long pfn, long i); > #else > @@ -4984,12 +4982,6 @@ static inline void memory_failure_queue(unsigned long pfn, int flags) > { > } > > -static inline int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, > - bool *migratable_cleared) > -{ > - return 0; > -} > - > static inline void num_poisoned_pages_inc(unsigned long pfn) > { > } > diff --git a/mm/hugetlb.c b/mm/hugetlb.c > index f24bf49be047..67243923fa24 100644 > --- a/mm/hugetlb.c > +++ b/mm/hugetlb.c > @@ -7154,17 +7154,6 @@ int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, bool unpoison > return ret; > } > > -int get_huge_page_for_hwpoison(unsigned long pfn, int flags, > - bool *migratable_cleared) > -{ > - int ret; > - > - spin_lock_irq(&hugetlb_lock); > - ret = __get_huge_page_for_hwpoison(pfn, flags, migratable_cleared); > - spin_unlock_irq(&hugetlb_lock); > - return ret; > -} > - > /** > * folio_putback_hugetlb - unisolate a hugetlb folio > * @folio: the isolated hugetlb folio > diff --git a/mm/memory-failure.c b/mm/memory-failure.c > index ee42d4361309..28522180cf7f 100644 > --- a/mm/memory-failure.c > +++ b/mm/memory-failure.c > @@ -1966,10 +1966,7 @@ void folio_clear_hugetlb_hwpoison(struct folio *folio) > folio_free_raw_hwp(folio, true); > } > > -/* > - * Called from hugetlb code with hugetlb_lock held. > - */ > -int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, > +static int get_huge_page_for_hwpoison(unsigned long pfn, int flags, > bool *migratable_cleared) > { > struct page *page = pfn_to_page(pfn); > @@ -1977,6 +1974,7 @@ int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, > bool count_increased = false; > int ret, rc; > > + spin_lock_irq(&hugetlb_lock); > if (!folio_test_hugetlb(folio)) { > ret = MF_HUGETLB_NON_HUGEPAGE; > goto out; > @@ -2013,8 +2011,10 @@ int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, > *migratable_cleared = true; > } > > + spin_unlock_irq(&hugetlb_lock); > return ret; > out: It might be better to rename out: as out_unlock. But that's trivial. Acked-by: Miaohe Lin Thanks. .