From: Mike Rapoport <rppt@kernel.org>
To: Breno Leitao <leitao@debian.org>
Cc: Andrew Morton <akpm@linux-foundation.org>,
David Hildenbrand <david@kernel.org>,
Lorenzo Stoakes <ljs@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
Vlastimil Babka <vbabka@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>, Baoquan He <baoquan.he@linux.dev>,
Pasha Tatashin <pasha.tatashin@soleen.com>,
Pratyush Yadav <pratyush@kernel.org>,
Miaohe Lin <linmiaohe@huawei.com>,
Naoya Horiguchi <nao.horiguchi@gmail.com>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
kexec@lists.infradead.org, rmikey@meta.com, riel@surriel.com,
kernel-team@meta.com, Kiryl Shutsemau <kas@kernel.org>
Subject: Re: [PATCH v5] kexec: keep the next kernel off hardware-poisoned pages
Date: Mon, 10 Aug 2026 19:32:41 +0300 [thread overview]
Message-ID: <ann9Kcesyb4T9Z8b@kernel.org> (raw)
In-Reply-To: <20260810-kexec_posioned-v5-1-95e1b5e2e656@debian.org>
Hi Breno,
On Mon, Aug 10, 2026 at 06:32:04AM -0700, Breno Leitao wrote:
> Memory failures (such as unrecoverable ECCs errors) are getting more and
> more common. The kernel knows how to handle it while running, marking it
> as poisoned (and SIGBUS user tasks).
>
> Poisoned memory is removed from the buddy allocator, but, not from
> other places. A current problem is that kexec will load new kernel
> on top of a bad/poisoned memory, which is undesirable.
>
> If the next kernel's image, initrd or purgatory lands on poisoned frame,
> the relocation copy writes to the bad memory and the machine checks
What does the machine check here? ;-)
> during the kexec.
>
> Skip hardware-poisoned frames when placing segments: check them in the
> kexec_file hole finder so it lays the next kernel down on good memory,
> and reject a poisoned destination in sanity_check_segment_list() for
> the kexec_load path, which cannot relocate.
>
> The two hole finders walk in opposite directions, so each asks for the
> end of the poison it has to clear: the top-down walk for the first
> poisoned page in the window, the bottom-up walk for the last. A poisoned
> hugetlb folio counts in full, as hugetlb keeps the flag on the folio and
> the poisoned subpages on its raw hwpoison list.
I had hard time parsing these two paragraphs. Can you please add more human
touch to them?
> Suggested-by: Kiryl Shutsemau <kas@kernel.org>
> Signed-off-by: Breno Leitao <leitao@debian.org>
>
> diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
> index dc770b9a6d053..7ee8c9f078f6b 100644
> --- a/kernel/kexec_core.c
> +++ b/kernel/kexec_core.c
> @@ -212,6 +212,16 @@ int sanity_check_segment_list(struct kimage *image)
> }
> #endif
>
> + /*
> + * Reject destinations that land on hardware-poisoned memory: the
> + * relocation copy would machine-check on the bad frame.
Would cause machine-check exception?
> + */
> + for (i = 0; i < nr_segments; i++) {
> + if (range_first_hwpoison(image->segment[i].mem,
> + image->segment[i].memsz) != PHYS_ADDR_MAX)
> + return -EHWPOISON;
> + }
> +
> /*
> * The destination addresses are searched from system RAM rather than
> * being allocated from the buddy allocator, so they are not guaranteed
> diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
> index 59fb9d71e9d86..9ba6cc01af929 100644
> --- a/kernel/kexec_file.c
> +++ b/kernel/kexec_file.c
> @@ -475,6 +475,7 @@ static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
> {
> struct kimage *image = kbuf->image;
> unsigned long temp_start, temp_end;
> + phys_addr_t poison;
>
> temp_end = min(end, kbuf->buf_max);
> temp_start = temp_end - kbuf->memsz + 1;
> @@ -504,6 +505,15 @@ static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
> continue;
> }
>
> + poison = range_first_hwpoison(temp_start, kbuf->memsz);
> + if (poison != PHYS_ADDR_MAX) {
> + /* we hit a poisoned page */
> + if (poison < kbuf->memsz)
> + return 0;
Won't we break out on the next iteration boundaries check? I.e.
if (temp_start < start || temp_start < kbuf->buf_min)
return 0;
> + temp_start = poison - kbuf->memsz;
> + continue;
> + }
> +
> /* We found a suitable memory range */
> break;
> } while (1);
> @@ -520,6 +530,7 @@ static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,
> {
> struct kimage *image = kbuf->image;
> unsigned long temp_start, temp_end;
> + phys_addr_t poison;
>
> temp_start = max(start, kbuf->buf_min);
>
> @@ -546,6 +557,13 @@ static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,
> continue;
> }
>
> + poison = range_last_hwpoison(temp_start, kbuf->memsz);
> + if (poison != PHYS_ADDR_MAX) {
> + /* we hit a poisoned page */
> + temp_start = poison + PAGE_SIZE;
> + continue;
> + }
> +
> /* We found a suitable memory range */
> break;
> } while (1);
> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> index a8b03e2920ba8..f3875680e7955 100644
> --- a/mm/memory-failure.c
> +++ b/mm/memory-failure.c
> @@ -96,6 +96,47 @@ void num_poisoned_pages_sub(unsigned long pfn, long i)
> memblk_nr_poison_sub(pfn, i);
> }
>
> +/*
> + * Return the first or the last hardware-poisoned online page in [start,
> + * start + size), or PHYS_ADDR_MAX if the range is clean.
> + */
> +static phys_addr_t range_hwpoison(phys_addr_t start, unsigned long size,
> + bool first)
> +{
> + phys_addr_t poison = PHYS_ADDR_MAX;
> + unsigned long pfn, end_pfn;
> +
> + if (!size || !atomic_long_read(&num_poisoned_pages))
> + return poison;
> +
> + end_pfn = PHYS_PFN(start + size - 1);
> + for (pfn = PHYS_PFN(start); pfn <= end_pfn; pfn++) {
> + struct page *page = pfn_to_online_page(pfn);
> +
> + cond_resched();
cond_resched() for every pfn is too much, isn't it?
> +
> + if (!page || !is_page_hwpoison(page))
> + continue;
> +
> + if (first)
> + return PFN_PHYS(pfn);
> +
> + poison = PFN_PHYS(pfn);
> + }
> +
> + return poison;
> +}
> +
> +phys_addr_t range_first_hwpoison(phys_addr_t start, unsigned long size)
> +{
> + return range_hwpoison(start, size, true);
> +}
> +
> +phys_addr_t range_last_hwpoison(phys_addr_t start, unsigned long size)
> +{
> + return range_hwpoison(start, size, false);
> +}
> +
> /**
> * MF_ATTR_RO - Create sysfs entry for each memory failure statistics.
> * @_name: name of the file in the per NUMA sysfs directory.
>
> ---
> base-commit: c5e32e86ca02b003f86e095d379b38148999293d
> change-id: 20260727-kexec_posioned-72bb0a4143a0
>
> Best regards,
> --
> Breno Leitao <leitao@debian.org>
>
--
Sincerely yours,
Mike.
prev parent reply other threads:[~2026-08-10 16:32 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-10 13:32 [PATCH v5] kexec: keep the next kernel off hardware-poisoned pages Breno Leitao
2026-08-10 14:01 ` Pratyush Yadav
2026-08-10 14:42 ` Bradley Morgan
2026-08-10 14:59 ` Kiryl Shutsemau
2026-08-10 16:32 ` Mike Rapoport [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ann9Kcesyb4T9Z8b@kernel.org \
--to=rppt@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=baoquan.he@linux.dev \
--cc=david@kernel.org \
--cc=kas@kernel.org \
--cc=kernel-team@meta.com \
--cc=kexec@lists.infradead.org \
--cc=leitao@debian.org \
--cc=liam@infradead.org \
--cc=linmiaohe@huawei.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=mhocko@suse.com \
--cc=nao.horiguchi@gmail.com \
--cc=pasha.tatashin@soleen.com \
--cc=pratyush@kernel.org \
--cc=riel@surriel.com \
--cc=rmikey@meta.com \
--cc=surenb@google.com \
--cc=vbabka@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.