mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-21 23:57:36 -04:00
mm/huge_memory: set PG_has_hwpoisoned only after new folio head is established
__split_folio_to_order() copies the hwpoison state onto each new sub-folio while splitting a folio to a non-zero order. It does so via if (handle_hwpoison && page_range_has_hwpoisoned(new_head, new_nr_pages)) folio_set_has_hwpoisoned(new_folio); *before* clear_compound_head(new_head)/prep_compound_page(new_head, ...) turns @new_head from a tail page into a proper folio head. PG_has_hwpoisoned is a FOLIO_SECOND_PAGE flag, so folio_set_has_hwpoisoned() resolves to folio_flags(folio, 1). With the new compound_info-based page-flags layout, folio_flags() asserts the page is not a tail: VM_BUG_ON_PGFLAGS(page->compound_info & 1, page); VM_BUG_ON_PGFLAGS(n > 0 && !test_bit(PG_head, &page->flags.f), page); At the current call site @new_head still has the tail marker (compound_info bit 0 set, PG_head clear), so on CONFIG_DEBUG_VM kernels this hits: kernel BUG at include/linux/page-flags.h:354 folio_flags+0x82 folio_set_has_hwpoisoned __split_folio_to_order __split_unmapped_folio __folio_split truncate_inode_partial_folio (shmem hole-punch / MADV_REMOVE) Reproduced by syzkaller: hwpoison-inject a few subpages of a large shmem folio, then MADV_REMOVE (fallocate punch hole) on the same range, which splits the partial folio to a non-zero order. memory_failure() tries to split the poisoned folio to order 0 first, but that split is best-effort; when it fails the folio is left large with PG_has_hwpoisoned set, the casefa5a061700added this hwpoison copying for. Move the folio_set_has_hwpoisoned() call to after clear_compound_head()/prep_compound_page(), where @new_folio is a real order-new_order head folio (handle_hwpoison implies new_order != 0, so a second page always exists). The flag still lands on the same struct page (page[1] of the new folio); only the ordering relative to compound-head setup changes, satisfying the FOLIO_SECOND_PAGE precondition. Link: https://lore.kernel.org/20260701174235.3173401-1-riel@surriel.com Fixes:fa5a061700("mm/huge_memory: preserve PG_has_hwpoisoned if a folio is split to >0 order") Signed-off-by: Rik van Riel <riel@surriel.com> Assisted-by: Claude:claude-opus-4-8 Reviewed-by: Zi Yan <ziy@nvidia.com> Acked-by: David Hildenbrand (Arm) <david@kernel.org> Tested-by: Lance Yang <lance.yang@linux.dev> Reviewed-by: Lorenzo Stoakes <ljs@kernel.org> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com> Cc: Barry Song <baohua@kernel.org> Cc: Dev Jain <dev.jain@arm.com> Cc: Lance Yang <lance.yang@linux.dev> Cc: Liam R. Howlett <liam@infradead.org> Cc: Nico Pache <npache@redhat.com> Cc: Ryan Roberts <ryan.roberts@arm.com> Cc: Yang Shi <yang@os.amperecomputing.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
committed by
Andrew Morton
parent
f84ca9b188
commit
e1cd30eceb
@@ -3587,10 +3587,6 @@ static void __split_folio_to_order(struct folio *folio, int old_order,
|
||||
(1L << PG_dropbehind) |
|
||||
LRU_GEN_MASK | LRU_REFS_MASK));
|
||||
|
||||
if (handle_hwpoison &&
|
||||
page_range_has_hwpoisoned(new_head, new_nr_pages))
|
||||
folio_set_has_hwpoisoned(new_folio);
|
||||
|
||||
new_folio->mapping = folio->mapping;
|
||||
new_folio->index = folio->index + i;
|
||||
|
||||
@@ -3612,6 +3608,14 @@ static void __split_folio_to_order(struct folio *folio, int old_order,
|
||||
folio_set_large_rmappable(new_folio);
|
||||
}
|
||||
|
||||
/*
|
||||
* PG_has_hwpoisoned is on the 2nd page, so set it after
|
||||
* the compound head is prepped.
|
||||
*/
|
||||
if (handle_hwpoison &&
|
||||
page_range_has_hwpoisoned(new_head, new_nr_pages))
|
||||
folio_set_has_hwpoisoned(new_folio);
|
||||
|
||||
if (folio_test_young(folio))
|
||||
folio_set_young(new_folio);
|
||||
if (folio_test_idle(folio))
|
||||
|
||||
Reference in New Issue
Block a user