[PATCH v4 4/5] mm/memory-failure: efi: answer whether a range is poisoned
Breno Leitao
leitao at debian.org
Wed Sep 9 06:05:23 PDT 2026
The bitmap an earlier kernel filled in gets in this one through EFI,
but nothing reads it back yet.
Introduce range_contains_poisoned_memory(), which the page allocator
will use to ask about a block before handing it out.
Signed-off-by: Breno Leitao <leitao at debian.org>
---
drivers/firmware/efi/poison.c | 26 ++++++++++++++++++++++++++
include/linux/mm.h | 14 ++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/drivers/firmware/efi/poison.c b/drivers/firmware/efi/poison.c
index c18edf111c710..e16d43f4438ee 100644
--- a/drivers/firmware/efi/poison.c
+++ b/drivers/firmware/efi/poison.c
@@ -96,6 +96,32 @@ static struct linux_efi_poisoned_memory *efi_poisoned_memory(void)
return phys_to_virt(efi.poisoned_memory);
}
+/* Does the range cover a unit an earlier kernel recorded as bad? */
+bool range_contains_poisoned_memory(phys_addr_t start, unsigned long size)
+{
+ struct linux_efi_poisoned_memory *pm = efi_poisoned_memory();
+ u64 first, last, nbits;
+
+ if (!pm)
+ return false;
+
+ nbits = pm->size * BITS_PER_BYTE;
+
+ if (start + size <= pm->phys_base)
+ return false;
+ if (start < pm->phys_base)
+ start = pm->phys_base;
+
+ first = (start - pm->phys_base) / pm->unit_size;
+ if (first >= nbits)
+ return false;
+
+ last = (start + size - 1 - pm->phys_base) / pm->unit_size;
+ last = min(last, nbits - 1);
+
+ return find_next_bit(pm->bitmap, last + 1, first) <= last;
+}
+
/*
* A bit is never cleared: it stands for a whole EFI_POISON_UNIT_SIZE, so an
* unpoison cannot tell whether the unit as a whole is good again.
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 274fa880077c5..b68824fcfbef1 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -5387,6 +5387,20 @@ static inline bool pfn_is_unaccepted_memory(unsigned long pfn)
return range_contains_unaccepted_memory(pfn << PAGE_SHIFT, PAGE_SIZE);
}
+#ifdef CONFIG_EFI_POISONED_MEMORY
+
+bool range_contains_poisoned_memory(phys_addr_t start, unsigned long size);
+
+#else
+
+static inline bool range_contains_poisoned_memory(phys_addr_t start,
+ unsigned long size)
+{
+ return false;
+}
+
+#endif
+
void vma_pgtable_walk_begin(struct vm_area_struct *vma);
void vma_pgtable_walk_end(struct vm_area_struct *vma);
--
2.53.0-Meta
More information about the kexec
mailing list