From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from canpmsgout07.his.huawei.com (canpmsgout07.his.huawei.com [113.46.200.222]) (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 AF2DC313E31 for ; Tue, 16 Jun 2026 06:54:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.222 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781592846; cv=none; b=ktjgI7uXAOjndykPdRXCGY4qhtkfdA0eMuNzDLn/CAHd3L5Tp/vwf6VdBXcVrQIIl0qaxuMLpd4d2wtrFrPAIyvxyjceyXKLZLWIs1CP9+rFGPeA+eD++TgeHIJRVL99DfAdumbaDOu81WtiXPACvMOl5gar89mnJ8lYyoO8M4E= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781592846; c=relaxed/simple; bh=iMTPwRGEzqcARf54AHCHzqwpMVo432RNin9xpMA4zhE=; h=Subject:To:CC:References:From:Message-ID:Date:MIME-Version: In-Reply-To:Content-Type; b=l6iLGL5MgGbD9fmxrO+WXi45Dnkrt967ZtzJznK7dGJ6KwzqRzNx51FjXOstrjnVg3zTZQL1zfBa6DbssKZXlbhLj5g1gN9Jw6vZ+Ef21SYWToR9rbBAnKzgd85FFllBC7qTXG0wd86428rg1kingCmseKdKBdLxBVnrwjhzzJE= 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=ljeRDcXa; arc=none smtp.client-ip=113.46.200.222 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="ljeRDcXa" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=Od+ddJM60ZxbWCIoJGH45aYhi+nlZZwU7IbCFhxRsh8=; b=ljeRDcXaai8brwvmlgDgK82u7RqJjo2I2HLfzNRBQinz7MFCMVbzvYQYSS9MOm2VA1WNmwW5e XgEkDEuguRfBeRRhtgRed4aTyZQWtCEZ1g8yGRf08y1PeBp/GZfAYLDVRvvRJXetgMDJnirUY9H BRGwzLkAL6KcRRZRobI4+UM= Received: from mail.maildlp.com (unknown [172.19.163.214]) by canpmsgout07.his.huawei.com (SkyGuard) with ESMTPS id 4gfcvL5SLBzLlTP; Tue, 16 Jun 2026 14:45:50 +0800 (CST) Received: from dggemv705-chm.china.huawei.com (unknown [10.3.19.32]) by mail.maildlp.com (Postfix) with ESMTPS id 3D06040561; Tue, 16 Jun 2026 14:53:48 +0800 (CST) Received: from kwepemq500010.china.huawei.com (7.202.194.235) by dggemv705-chm.china.huawei.com (10.3.19.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Tue, 16 Jun 2026 14:53:48 +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; Tue, 16 Jun 2026 14:53:46 +0800 Subject: Re: [PATCH v5 1/4] mm/page_alloc: only free healthy pages in high-order has_hwpoisoned folio To: Jiaqi Yan CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , Zi Yan , References: <20260531055829.3636554-1-jiaqiyan@google.com> <20260531055829.3636554-2-jiaqiyan@google.com> <84a0b176-8534-e03a-9e6e-400c74ddab0b@huawei.com> <45290F97-B8BD-4A9B-934E-0A122A5F3A80@nvidia.com> From: Miaohe Lin Message-ID: Date: Tue, 16 Jun 2026 14:53:46 +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: Content-Type: text/plain; charset="utf-8" Content-Language: en-US Content-Transfer-Encoding: 8bit X-ClientProxiedBy: kwepems100001.china.huawei.com (7.221.188.238) To kwepemq500010.china.huawei.com (7.202.194.235) On 2026/6/16 11:23, Jiaqi Yan wrote: > On Fri, Jun 12, 2026 at 11:34 AM Zi Yan wrote: >> >> On 8 Jun 2026, at 23:44, Miaohe Lin wrote: >> >>> On 2026/5/31 13:58, Jiaqi Yan wrote: >>>> At the end of dissolve_free_hugetlb_folio(), a free HugeTLB folio >>>> becomes non-HugeTLB, and it is released to buddy allocator >>>> as a high-order folio, e.g. a folio that contains 262144 pages >>>> if the folio was a 1G HugeTLB hugepage. >>>> >>>> This is problematic if the HugeTLB hugepage contained HWPoison >>>> subpages. In that case, since buddy allocator does not check >>>> HWPoison for non-zero-order folio, the raw HWPoison page can >>>> be given out with its buddy page and be re-used by either >>>> kernel or userspace. >>>> >>>> Memory failure recovery (MFR) in kernel does attempt to take >>>> raw HWPoison page off buddy allocator after >>>> dissolve_free_hugetlb_folio(). However, there is always a time >>>> window between dissolve_free_hugetlb_folio() frees a HWPoison >>>> high-order folio to buddy allocator and MFR takes HWPoison >>>> raw page off buddy allocator. >>>> >>>> Another similar situation is when a transparent huge page (THP) >>>> runs into memory failure but splitting failed. Such THP will >>>> eventually be released to buddy allocator when owning userspace >>>> processes are gone, but with certain subpages having HWPoison. >>>> >>>> One obvious way to avoid both problems is to add page sanity >>>> checks in page allocate or free path. However, it is against >>>> the past efforts to reduce sanity check overhead [1,2,3]. >>>> >>>> Introduce free_has_hwpoisoned() to only free the healthy pages >>>> and to exclude the HWPoison ones in the high-order folio. >>>> The idea is to iterate through the sub-pages of the folio to >>>> identify contiguous ranges of healthy pages. >>>> >>>> free_has_hwpoisoned() is added in free_pages_prepare() as >>>> a shortcut and is only invoked if PG_has_hwpoisoned indicates >>>> HWPoison page exists and after checks and preparations in >>>> free_pages_prepare() all succeeded. free_has_hwpoisoned() then >>>> can re-use free_prepared_contig_range() [4] to decompose healthy >>>> ranges into the largest possible chunks of different orders. >>>> Every chunk meets the requirements to be freed via free_one_page(). >>>> >>>> free_has_hwpoisoned() has linear time complexity wrt the number >>>> of pages in the folio. While the power-of-two decomposition >>>> ensures that the number of calls to the buddy allocator is >>>> logarithmic for each contiguous healthy range, the mandatory >>>> linear scan of pages to identify PageHWPoison() defines the >>>> overall time complexity. For a 1G hugepage having 8 HWPoison >>>> pages, free_has_hwpoisoned() takes around 1ms on average on >>>> a system having 56 Intel Skylake physical cores. This is >>>> 15x to the case of freeing no HWPoison page. The cost is far >>>> from triggering soft lockup, and fair for handling exceptional >>>> hardware memory errors. >>>> >>>> [1] https://lore.kernel.org/linux-mm/1460711275-1130-15-git-send-email-mgorman@techsingularity.net >>>> [2] https://lore.kernel.org/linux-mm/1460711275-1130-16-git-send-email-mgorman@techsingularity.net >>>> [3] https://lore.kernel.org/all/20230216095131.17336-1-vbabka@suse.cz >>>> [4] https://lore.kernel.org/all/20260401101634.2868165-2-usama.anjum@arm.com >>>> >>>> Signed-off-by: Jiaqi Yan >>> >>> Thanks for your update. This patch looks good to me while some comments below. >>> >>>> --- >>>> mm/page_alloc.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ >>>> 1 file changed, 85 insertions(+) >>>> >>>> diff --git a/mm/page_alloc.c b/mm/page_alloc.c >>>> index e47679e7a9db..03df929abca6 100644 >>>> --- a/mm/page_alloc.c >>>> +++ b/mm/page_alloc.c >>>> @@ -208,6 +208,7 @@ gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; >>>> unsigned int pageblock_order __read_mostly; >>>> #endif >>>> >>>> +static void free_has_hwpoisoned(struct page *page, unsigned int order); >>>> static void __free_pages_ok(struct page *page, unsigned int order, >>>> fpi_t fpi_flags); >>>> static void reserve_highatomic_pageblock(struct page *page, int order, >>>> @@ -1309,6 +1310,14 @@ static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) >>>> >>>> #endif /* CONFIG_MEM_ALLOC_PROFILING */ >>>> >>>> +/* >>>> + * Returns >>>> + * - true: checks and preparations all good, caller can proceed freeing. >>>> + * - false: do not proceed freeing for one of the following reasons: >>>> + * 1. Some check failed so it is not safe to proceed freeing. >>>> + * 2. A compound page has some HWPoison pages. The healthy pages >>>> + * are already safely freed, and the HWPoison ones isolated. >>>> + */ >>>> static __always_inline bool __free_pages_prepare(struct page *page, >>>> unsigned int order, fpi_t fpi_flags) >>>> { >>>> @@ -1317,6 +1326,15 @@ static __always_inline bool __free_pages_prepare(struct page *page, >>>> bool init = want_init_on_free(); >>>> bool compound = PageCompound(page); >>>> struct folio *folio = page_folio(page); >>>> + /* >>>> + * When dealing with compound page, PG_has_hwpoisoned is cleared >>>> + * with PAGE_FLAGS_SECOND. So the check must be done first. >>>> + * >>>> + * Note we can't exclude PG_has_hwpoisoned from PAGE_FLAGS_SECOND. >>>> + * Because PG_has_hwpoisoned == PG_active, free_page_is_bad() will >>>> + * confuse and complaint that the first tail page is still active. >>>> + */ >>>> + bool should_fhh = compound && folio_test_has_hwpoisoned(folio); >>>> >>>> if (fpi_flags & FPI_PREPARED) >>>> return true; >>>> @@ -1443,6 +1461,16 @@ static __always_inline bool __free_pages_prepare(struct page *page, >>>> >>>> debug_pagealloc_unmap_pages(page, 1 << order); >>>> >>>> + /* >>>> + * After breaking down compound page and dealing with page metadata >>>> + * (e.g. page owner and page alloc tags), take a shortcut if this >>>> + * was a compound page containing certain HWPoison subpages. >>>> + */ >>>> + if (should_fhh) { >>>> + free_has_hwpoisoned(page, order); >>>> + return false; >>>> + } >>> >>> When the code reaches here, the hwpoisoned pages have passed through kernel_poison_pages, >>> kasan_poison_pages, kernel_init_pages, arch_free_page... These functions might write to >>> the hwpoisoned pages. Is it safe to do so? >> >> At least, kernel_poison_pages() writes to the page. It probably should be >> moved up, somewhere like above kernel_poison_pages(). > > Writing to HWPoison pages (location having memory error) is usually > safe, as in it doesn't cause a machine check exception. Memory In x86, set_mce_nospec is called for hwpoisoned pages. So writing to HWPoison pages would cause unexpected page fault in kernel? Thanks. .