On 9/15/26 14:53, Breno Leitao wrote: > When the pages are being given to the allocator, check if they are > poisoned, and mark them as such. > > Similar to unaccepted memory, hook it in __free_pages_core(), and thus > the frames never enter the allocator, rather than being taken back out > of it. > > A block runs up to MAX_PAGE_ORDER and a unit is 2MB, so hold back only > the frames the table covers and free the rest one at a time. The > allocator merges them back up, so a unit costs the frames it names, not > the whole block. > > The frames that are freed go back through accept_and_free_block(), so a > clean frame in a block that is still unaccepted is accepted first. > > A frame is flagged before its memory block exists, so the per block > counter is seeded from the page flag when the block is created rather > than incremented here. > > Suggested-by: Kiryl Shutsemau <[email protected]> > Signed-off-by: Breno Leitao <[email protected]>
Acked-by: Vlastimil Babka (SUSE) <[email protected]> > --- > mm/page_alloc.c | 26 ++++++++++++++++++++++++++ > 1 file changed, 26 insertions(+) > > diff --git a/mm/page_alloc.c b/mm/page_alloc.c > index b07b5f4751cb95..cca67a2702a421 100644 > --- a/mm/page_alloc.c > +++ b/mm/page_alloc.c > @@ -1597,6 +1597,25 @@ static void __meminit accept_and_free_block(struct > page *page, > __free_pages_ok(page, order, FPI_TO_TAIL); > } > > +static void __meminit free_poisoned_block(struct page *page, unsigned int > order, > + enum meminit_context context) > +{ > + unsigned long i, nr_pages = 1UL << order; > + > + for (i = 0; i < nr_pages; i++) { > + struct page *p = page + i; > + phys_addr_t phys = page_to_phys(p); > + > + if (range_contains_poisoned_memory(phys, PAGE_SIZE)) { > + hwpoison_boot_page(p, context); > + continue; > + } > + > + /* this part of the block is not poisoned */ > + accept_and_free_block(p, 0); > + } > +} > + > void __meminit __free_pages_core(struct page *page, unsigned int order, > enum meminit_context context) > { > @@ -1631,6 +1650,13 @@ void __meminit __free_pages_core(struct page *page, > unsigned int order, > atomic_long_add(nr_pages, &page_zone(page)->managed_pages); > } > > + /* First: a block parked by __free_unaccepted() never returns here. */ > + if (range_contains_poisoned_memory(page_to_phys(page), > + PAGE_SIZE << order)) { > + free_poisoned_block(page, order, context); > + return; > + } > + > accept_and_free_block(page, order); > } > >
