From nobody Sun May 24 19:34:48 2026 Received: from canpmsgout03.his.huawei.com (canpmsgout03.his.huawei.com [113.46.200.218]) (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 371DE21A457 for ; Fri, 22 May 2026 01:24:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.218 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779413089; cv=none; b=Xx8SG6GFzDEdNy/Jp8SIvsH/VVuV9R8IEDx41zriWufGf25mxi5Z7gUEQLB+DOlry13iza2xwxQWLKjtWwovmIQo4WrHjcDhAD90iioBNhqAR6CxuxEAgemHPhIUkmuaYmvSsEpPokjJUbE1BYcMqxLeFUXqET76Qt1l9Ye1tMo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779413089; c=relaxed/simple; bh=sSHqxx2promkjoMg1uSyOs2DRiltsHKpT0pQb3jk6Ok=; h=From:To:CC:Subject:Date:Message-ID:MIME-Version:Content-Type; b=QIpbpmv9Y1chCQfCvrSe5kh+0ojDWP3WkkoSBTfZborsTJLHWB9FF93mQnUfRuJdG+4hZZnjKmJ9Md61qe3rrnzxnYhKSdKv2if/VsfreF6IyH5qzosaM4FnCLAZG2PNUcZX1MzQoMs8V1hF/u5wrBXB/T3cWmCCXeEtZnZAKY8= 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=dLCuvDnQ; arc=none smtp.client-ip=113.46.200.218 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="dLCuvDnQ" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=cBJvlhdX2BSZuFuaHgzoJ8EYhaT7BipLqr07dC7wr80=; b=dLCuvDnQglDQSdOrCdk4gDNwpU4VnCtB0l+7+ui+QEU6WFA1xz0p5Fkr8SyMG/ygfHATVreRg XqH1Y95g+pWq8+mxPv0DdojQ9pL8JAoQmvYIL6SIYMFee6w9e29Z3bF9IjJvXuNheJRw15/Hy2B 7QKvm5nBNmAoHUVFgzIt8ko= Received: from mail.maildlp.com (unknown [172.19.162.140]) by canpmsgout03.his.huawei.com (SkyGuard) with ESMTPS id 4gM6nr4TX9zpTLk; Fri, 22 May 2026 09:17:20 +0800 (CST) Received: from kwepemj100016.china.huawei.com (unknown [7.202.194.10]) by mail.maildlp.com (Postfix) with ESMTPS id 58DD9203AC; Fri, 22 May 2026 09:24:37 +0800 (CST) Received: from huawei.com (10.50.85.135) by kwepemj100016.china.huawei.com (7.202.194.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Fri, 22 May 2026 09:24:36 +0800 From: Wupeng Ma To: , , , , , , , , , , , CC: , , Subject: [PATCH resend] mm/memory-failure: fix hugetlb_lock AA deadlock in get_huge_page_for_hwpoison Date: Fri, 22 May 2026 09:03:05 +0800 Message-ID: <20260522010305.4099834-1-mawupeng1@huawei.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: kwepems500001.china.huawei.com (7.221.188.70) To kwepemj100016.china.huawei.com (7.202.194.10) Content-Type: text/plain; charset="utf-8" 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 a= nd memory_failure_hugetlb()") Signed-off-by: Wupeng Ma Acked-by: Miaohe Lin Acked-by: Muchun Song Acked-by: Oscar Salvador (SUSE) Reviewed-by: Kefeng Wang --- Changelog since v3[1]: - update commit message to fit current issue =20 [1]: https://lore.kernel.org/linux-mm/20260520020128.3506168-1-mawupeng1@hu= awei.com/=20 --- 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 un= poison); -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 fo= lio *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 f= lags); */ 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 lon= g pfn, int flags) { } -static inline int __get_huge_page_for_hwpoison(unsigned long pfn, int flag= s, - 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 =3D __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 *foli= o) 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 =3D pfn_to_page(pfn); @@ -1977,6 +1974,7 @@ int __get_huge_page_for_hwpoison(unsigned long pfn, i= nt flags, bool count_increased =3D false; int ret, rc; + spin_lock_irq(&hugetlb_lock); if (!folio_test_hugetlb(folio)) { ret =3D MF_HUGETLB_NON_HUGEPAGE; goto out; @@ -2013,8 +2011,10 @@ int __get_huge_page_for_hwpoison(unsigned long pfn, = int flags, *migratable_cleared =3D true; } + spin_unlock_irq(&hugetlb_lock); return ret; out: + spin_unlock_irq(&hugetlb_lock); if (count_increased) folio_put(folio); return ret; -- 2.43.0